capture Ansible WARNING messages to a variable - search

I have the below playbook:
- name: Play 1.5 - Check Python on each target
hosts: "{{ location }}"
user: "{{ USER }}"
ignore_unreachable: yes
ignore_errors: yes
gather_facts: false
tasks:
- setup:
gather_subset:
- network
register: setupdata
- debug:
msg: "SETUP: {{ setupdata }}"
For a few inventory hosts I get the below WARNING message when i print setupdata variable as below:
Output:
ok: [10.9.10.16] => {
"msg": "SETUP: {'warnings': [u\"No python interpreters found for host 10.9.10.16 (tried ['/usr/bin/python', 'python3.7', 'python3.6', 'python3.5', 'python2.7', 'python2.6', '/usr/libexec/platform-python', '/usr/bin/python3', 'python'])\"], 'module_stderr': u'This system is for the use of authorized users only. Individuals using this computer system without authority, or in excess of their authority, are subject to having all of their activities on this system monitored and recorded by system personnel. In the course of monitoring individuals improperly using this system, or in the course of system maintenance, the activities of authorized users may also be monitored. Anyone using this system expressly consents to such monitoring and is advised that if such such monitoring reveals possible evidence of criminal activity, system personnel may provide the evidence of such monitoring to the law enforcement officials\\n/bin/sh: /usr/bin/python: not found\\n', 'changed': False, 'module_stdout': u'', 'failed': True, 'rc': 127, 'msg': u'MODULE FAILURE\\nSee stdout/stderr for the exact error', 'ansible_facts': {u'discovered_interpreter_python': u'/usr/bin/python'}}"
}
Is it possible to search for a string No python interpreters found for host in the output above ?
I tried the below but it fails to search:
- debug:
msg: "No Python Found on {{ inventory_hostname }}"
when: setupdata | join('') | regex_search('No python interpreters found for host')
Can you please suggest how can I capture the WARNING message and search for a string in the WARNING?

Be aware that setupdata has a key in it named warnings that is list[str] and is a much better candidate for the actual when. You can test members of that list by changing the when: to use the search test, which pedantically speaking should be applied using the contains test, but just feeding the list into search seems to do what I expected and is easier to read
- debug:
msg: "No Python Found on {{ inventory_hostname }}"
when: setupdata.warnings is search('No python interpreters')

Related

Ansible gcp_compute_instance_template: argument network is of type <class 'str'> found in 'properties -> network_interfaces'

I'm currently adding GCP to our ansible system as up until now we've done the lengthy process of creating images, instance templates, groups and deploying them all manually with the CLI suite.
I'm getting stuck on an error with network interfaces trying to create a simple Instance Template using the same parameters we used to do manually.
Error:
"msg": "argument network is of type <class 'str'> found in 'properties -> network_interfaces'. and we were unable to convert to dict: dictionary requested, could not parse JSON or key=value"
We don't have a default network for our GCP instances as we have a very specific setup so omitting the network parameter isn't viable either. When I do I get the error The resource 'projects/<PROJECT_NAME>/global/networks/default' was not found\",. As a test when I put the default network as my parameter I again get the <class 'str'> error.
I'm feel like I'm losing my mind. Here is my playbook (with parts changed for company anonymity):
- hosts: localhost
vars_files:
- ../vault/vault.yml
vars:
current_date: "{{ ansible_date_time.year }}{{ ansible_date_time.month }}{{ ansible_date_time.day }}"
site_code: [ eur ]
nat_zone: [ a ]
project_name: "PROJECT_NAME"
network_name: "STG-NET"
image: "haproxy-master-20210219-01"
- name: Create instance template in staging
google.cloud.gcp_compute_instance_template:
name: "ew2-{{ item[1] }}-ig-stg-{{ item[0] }}-haproxy-tpl-{{ current_date }}-test"
properties:
disks:
- auto_delete: true
boot: true
initialize_params:
source_image: "projects/{{ project_name }}/global/images/{{ image }}"
machine_type: n1-standard-1
network_interfaces:
- network: 'projects/{{ project }}/global/networks/{{ network }}'
access_configs:
- name: access_config
type: ONE_TO_ONE_NAT
project: "{{ project_name }}"
auth_kind: "{{ gcp_auth_kind }}"
service_account_file: "{{ gcp_eur_service_account_file }}"
scopes:
- https://www.googleapis.com/auth/compute
state: present
with_nested:
- "{{ site_code }}"
- "{{ nat_zone }}"
I've also tried the network param without using variables. I've tried without quotation marks. I've tried without the hyphen which is syntax incorrect and subtly changes the error to complain about a list not being a dict instead.
Any guidance as to what I'm getting wrong here would be greatly appreciated!
Environment details:
ansible-playbook --version
ansible-playbook 2.10.5
config file = /home/USER/ansible_aws/ansible.cfg
configured module search path = ['/home/USER/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python3.6/site-packages/ansible
executable location = /usr/local/bin/ansible-playbook
python version = 3.6.8 (default, Nov 16 2020, 16:55:22) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
Disclaimer: I have no experience with GCP and nothing to correctly test this against. Meanwhile I have some experience in reading ansible documentation and testing module usage for correct parameters (at least at pure ansible level...)
As I first did, you probably flew over the documentation and its examples a little to fast ;). Meanwhile the specific parameter description is very clear:
network - dictionary
Hence a str is definitely not what is expected, as explicitely reported by your error message. We get more information in the comment:
[...] This field represents a link to a Network resource in GCP. It can be specified in two ways. First, you can place a dictionary with key selfLink and value of your resource's selfLink Alternatively, you can add register: name-of-resource to a gcp_compute_network task and then set this network field to {{ name-of-resource }}
If you look correctly at the examples, you'll see that they demonstrate the second scenario above (creating/registering a network to use the registered var directly in that parameter).
Taking for granted your own example in your question is using a ressource selfLink (have no clue if your current value looks correct or not...), I guess you should modify your definition as follows (abridged to network interfaces only):
network_interfaces:
- network:
selfLink: 'projects/{{ project }}/global/networks/{{ network }}'
access_configs:
- name: access_config
type: ONE_TO_ONE_NAT

I wanted to deploy multiple VMs from ansible, from values given by the enduser

I wanted to deploy multiple VMS from my ansible-playbook, so I used split function and I am getting the error of dict does not have user_inout error. Please have a look at my code.
Code:
- name: os system
pause:
prompt: |
Which os do you want to use?
1- Windows Server
2- CentOS_7
3- CentOs_8
4- Ubuntu
5- Others
register: os_system
- set_fact:
o_name: "{{ os_system.user_input.split(',') }}"
- name: Domain Decision
pause:
prompt: Do you want your PC in Domain
register: decision
when: 'item|string == "1"'
with_items:
- "{{ o_name }}"
- set_fact:
dec: "{{ decision.user_input.split(',') }}"
Now my real issue, if the user chooses option 1,2 then it will be split by set_fact for os_system and according to that input it will decide for the domain decision my main issue is that while the task is at set_fact for the decision, it will give me the error like this:
Error:
fatal: [x.x.x.x]: FAILED! => {
"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'user_input'\n\nThe error appears to be in '/home/x.x.x.x/sites/playbook.yml': line 82, column 6, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - set_fact:\n ^ here\n"
}
IF I remove the loop from task domain decision, then set_fact works very perfectly.
When you want to collect user input, it can be in two ways:
Interactive (prompted), using vars_prompt.
Through variables (non-prompted). For example, you could have users create a file with variables and load with vars_file.
I would prefer the second approach if possible.
However, to get user input interactively through prompts:
- hosts: my_hosts
vars_prompt:
- name: os_system
prompt: |
Which os do you want to use?
1- Windows Server
2- CentOS_7
3- CentOs_8
4- Ubuntu
5- Others
private: no
tasks:
- set_fact:
o_name: "{{ os_system.split(',') }}"
You should note that by splitting the input of 1,2 - you will not get OS name. You will again have to set a fact based on the number (1 = Windows Server). IMHO this is unnecessary complication.
A much better option would be to have users create a variables file like below:
my_vars.yml:
os_choices:
- { name: Windows Server, domain: yes }
- { name: CentOS_7, domain: no }
And load it in play using:
- hosts: my_hosts
vars_file:
- my_vars.yml

With ansible, how do I read a file and use the IP address contained as an argument to update an Azure MySQL firewall?

My current project is to create a DigitalOcean Droplet and add the IP address to the Azure MySQL server firewall. In my script to spin up the Droplet I save the IP address as a .txt with only the IPv4 address. The ansible playbook I have now uses the following to read from the file and store the IP address as a variable.
vars:
droplet_ip: "{{ lookup('file', '/tmp/created-droplet-ip.txt') }}"
I print this out in my playbook for debugging and it's the correct IP in the correct format (x.x.x.x).
I'm using azure_rm_mysqlfirewallrule to create the rule for this new address. I can login to Azure, find the resource group and server name but I get an error when using my droplet_ip variable, which is:
File \"/home/me/.local/lib/python3.8/site-packages/msrest/serialization.py\", line 674, in validate\n raise ValidationError(key, name, value)\nmsrest.exceptions.ValidationError: Parameter 'FirewallRule.start_ip_address' must conform to the following pattern: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'.\n"
When I type the IP address out as the parameter it works fine so I'm 99% certain it's either how I'm reading the file or using the variable name. For this to be automated that isn't a possibility for me so if anyone can help I would be extremely grateful.
Below is my playbook:
---
- hosts: local
vars:
droplet_ip: "{{ lookup('file', '/tmp/created-droplet-ip.txt') }}"
tasks:
- name: Print droplet_ip
debug:
msg: "{{ droplet_ip }}"
- name: Azure login
shell: az login
- name: Update firewall
azure_rm_mysqlfirewallrule:
ad_user: x#y.com
resource_group: example_group
server_name: example-dbs
name: new_machine
password: ******
start_ip_address: droplet_ip
end_ip_address: droplet_ip
subscription_id: xxxxxx-xxxxxxxx-xxxxxxxx
tenant: yyyyyyyy-yyyyyyyy-yyyyyyyyyyyyy
If you want to include the value of the droplet_ip variable in your task, you need to write:
start_ip_address: "{{ droplet_ip }}"
The way it's written write now, you're trying to set start_ip_address (et al) to the literal string "droplet_ip".

How to execute ansible-playbook with Azure Dynamic Inventories along with keyed groups conditional

I am trying to use azure_rm plugin in ansible to generate dynamic hosts on Azure platform. With keyed group conditional, I am able to successfully make it work with an ansible ad-hoc command. However, it does not work when I try to pass the same with "ansible-playbook". Can anyone please help how could I run an ansible-playbook the same way ?
Below is my dynamic inventory generation file:
---
plugin: azure_rm
auth_source: msi
keyed_groups:
- prefix: tag
key: tags
When I use the file to ping the target VM, below is a success response.
Command used:
ansible -m ping tag_my_devops_ansible_slave -i dynamic_inventory_azure_rm.yml
Response:
devops-eastus2-dev-ansibleslave-vm_2f44 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
However, when I use the same with ansible-playbook, I get the below error.
Command used:
ansible-playbook tag_cdo_devops_ansible_slave -i dynamic_inventory_azure_rm.yml test-playbook.yml
Error:
ansible-playbook: error: unrecognized arguments: test-playbook.yml
Can anyone please help on how to execute an ansible-playbook for the above use case ?
The ansible-playbook command does not accept a list of targets on the command line, rather the playbook file has hosts: as a top-level key indicating the hosts to which the playbook will apply.
So, if the playbook is always going to be used with that tag, you can just indicate that in the playbook:
- hosts: tag_cdo_devops_ansible_slave
tasks:
- debug: var=ansible_host
It also appears that hosts: does honor jinja2 templating, so you can achieve what you're trying to do via:
- hosts: '{{ azure_playbook_hosts }}'
tasks:
- debug: var=ansible_host
and then ansible-playbook -e azure_playbook_hosts=tag_cdo_devops_ansible_slave -i dynamic_inventory_azure_rm.yml test-playbook.yml
Or you can create a dedicated inventory file that only returns hosts matching your desired tag, and then use -i for that inventory along with hosts: all in the playbook file.

Error occuer when creating a VM in azure using ansible

i am using azure=0.11.1 and also tried in 1.0.1 version and execute it but i getting same error which mention below, playbook is mention below:
azurevm_yml
---
- local_action:
module: "azure"
name: 'vm_ubuntu1'
role_size: Small
image: '5112500ae3b842c8b9c604889f8753c3__OpenLogic-CentOS-67-20150815'
password: "admin12345#"
location: 'East US 2'
user: admin
wait: yes
subscription_id: 'xxxxxxxxxxxxxx'
management_cert_path: '/ansible-pbook/xxxx.pem'
storage_account: 'storageacc01'
endpoints: '22,8080,80'
register: azure_vm
Error:
root#xxxxx:/ansible-pbook# ansible-playbook azure_vm.yml
ERROR: password is not a legal parameter of an Ansible Play
Please suggest me...
The correct format for a task is something like this:
- local_action: azure
name='vm_ubuntu1'
role_size=Small
image='5112500ae3b842c8b9c604889f8753c3__OpenLogic-CentOS-67-20150815'
password="admin12345#"
location='East US 2'
user=admin
wait=yes
subscription_id='xxxxxxxxxxxxxx'
management_cert_path='/ansible-pbook/xxxx.pem'
storage_account='storageacc01'
endpoints='22,8080,80'
register: azure_vm
All the parameters passed to the module should be in the format of key=value, while attributes to the task/action itself (like register, tags, ignore_errors, etc.) are in the format of attribute: value

Resources