error while setting a fact or debug a webpage after registering this webpage in the get_uri module in Ansible - automation

I have a problem every time while setting a fact for a registered webpage the error is :
u'redirected': False}]}: template error while templating string: unexpected char u'&' at 1238
The Playbook like:
- name: check webpage
uri:
url: http://{{ item.host }}.x.x.x
validate_certs: False
return_content: yes
status_code: 200
register: webpage3
with_items: "{{ servers }}"
when:
- lb is defined
- lb == "true"
- name: debug webpage
set_fact:
fact: "{{ webpage3 }}"
when:
- lb is defined
ignore_errors: yes
and my ansible version is ansible 2.2.1.0
So, do I have a problem with my webpage itself and is there's a solution to skip this error?
and after troubleshooting, I figured out that it fails because of a line starts with
<!-->
so how to skip this line with this character?

Thanks all, I have solved it by providing the dest in the uri module to a file then using sed to remove the unwanted characters and then registering the output to a new value to set_fact from and finally greping the needed value using a grep command. as it was hard to skip those chars in output

Related

Ansible: How to use examples from the documentation?

I'm starting to learn Ansible and for this I copy and paste examples from the documentation. For example this one
- name: Check that a page returns a status 200 and fail if the word AWESOME is not in the page contents
ansible.builtin.uri:
url: http://www.example.com
return_content: yes
register: this
failed_when: "'AWESOME' not in this.content"
which I've found in uri module documentation.
Every single time I do this, whatever the module I get:
ERROR! 'ansible.builtin.uri' is not a valid attribute for a Play
The error appears to have been in '/home/alfrerra/test2.yml': line 1, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- name: Check that a page returns a status 200 and fail if the word AWESOME is not in the page contents
^ here
I have only 2 playbooks that only ping successfully:
-
name: ping localhost
hosts: localhost
tasks:
- name: ping test
ping
and
---
- name: ping localhost
hosts: localhost
tasks:
- name: ping test
ping
So I adapted the example to match these 2 examples, but to no avail so far.
I'm sure it's nothing much but it's driving me crazy.
As already mentioned within the comments, the documentation are to show how to use certain parameter of certain modules within a single task. They are not mentioned to work in a copy and paste manner by itself or only.
You may have a look into the following minimal example playbook
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Check that a page returns a status 200 and fail if the word 'iana.org' is not in the page contents
uri:
url: http://www.example.com
return_content: yes
environment:
http_proxy: "localhost:3128"
https_proxy: "localhost:3128"
register: this
failed_when: "'iana.org' not in this.content"
- name: Show content
debug:
msg: "{{ this.content }}"
resulting into the output of the page content.
Please take note that the web page of the example domain is connected and delivers a valid result, but it does not contain the word AWESOME. To address this the string to lookup was changed to the page owner iana.org and to not let the task fail. Furthermore and since working behind a proxy it was necessary to address the proxy configuration and which you probably need to remove again.
Your first example is a single task and failing therefore with ERROR! ... not a valid attribute for a Play. Your second and
third examples are playbooks with a single task and therefore executing.
Documentation
Module format and documentation - EXAMPLES block
... show users how your module works with real-world examples in multi-line plain-text YAML format. The best examples are ready for the user to copy and paste into a playbook.
Ansible playbooks
failed_when must be a comparison or a boolean.
example :
- name: Check that a page returns AWESOME is not in the page contents
ansible.builtin.uri:
url: http://www.example.com
return_content: yes
register: this
failed_when: this.rc == 0;
It will execute the task only if the return value is equal to 0

How to dynamically set the hosts field in Ansible playbooks with a variable generated during execution?

I am trying to test something at home with the variables mechanism Ansible offers, which I am about to implement in one of my projects at work. So, been searching for a while now, but seems I can't get it working that easily, even with others` solutions here and there.
I will represent my project logic at work now, by demonstrating with my test directory & files structure at home. Here's the case, I have the following playbooks:
main.yaml
pl1.yaml
pl2.yaml
Contents of ./main.yaml:
- import_playbook: /home/martin/ansible/pl1.yaml
- import_playbook: /home/martin/ansible/pl2.yaml
Contents of ./pl1.yaml:
- name: Test playbook 1
hosts: localhost
tasks:
- name: Discovering the secret host
shell: cat /home/martin/secret
register: whichHostAd
- debug:
msg: "{{ whichHostAd.stdout }}"
- name: Discovering my hostname
shell: hostname
register: myHostnameAd
- set_fact:
whichHost: "{{ whichHostAd.stdout }}"
myHostname: "{{ myHostnameAd.stdout }}"
cacheable: yes
- name: Test playbook 1 part 2
hosts: "{{ hostvars['localhost']['ansible_facts']['whichHost'] }}"
tasks:
- name: Structuring info
shell: hostname
register: secretHostname
- name: Showing the secret hostname
debug:
msg: "{{ secretHostname.stdout }}"
Contents of ./pl2.yaml:
- name: Test Playbook 2
hosts: "{{ whichHost }}"
tasks:
- name: Finishing up
shell: echo "And here am i again.." && hostname
- name: Showing var myHostname
debug:
msg: "{{ myHostname.stdout }}"
The whole idea is to have a working variable on the go at the hosts field between the plays. How do we do that?
The playbook does not run at all if I won't define the whichHost variable as an extra arg, and that's ok, I can do it each time, but during the execution I would like to have that variable manageable and changeable. In the test case above, I want whichHost to be used everywhere across the plays/playbooks included in main.yaml, specifically to reflect the output of the first task in pl1.yaml (or the output of the whichHostAd.stdout variable), so I can determine the host I am about to target in pl2.yaml.
According to docs, I should be able to at least access it with hostvars (as in my playbook), but this is the output I get when I try the above example:
ERROR! The field 'hosts' has an invalid value, which includes an undefined variable. The error was: 'dict object' has no attribute 'whichHost'
The error appears to have been in '/home/martin/ansible/pl1.yaml': line 22, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- name: Test playbook 1 part 2
^ here
set_fact also does not seem to be very helpful. Any help will be appreciated!
Ok, I've actually figured it out pretty fast.
So, we definitely need to have a fact task, holding the actual data/output:
- hosts: localhost
tasks:
- name: Saving variable
set_fact:
whichHost: "{{ whichHostAd.stdout }}"
After that, when you want to invoke the var in other hosts and plays, we have to provide the host and the fact:
"{{ hostvars['localhost']['whichHost'] }}"
Like in my test above, but without ['ansible_facts']

ansible-vault error - "Vault format unhexlify error: Odd-length string"

I am using ansible-napalm and trying to write a simple playbook to pull facts from network devices.
I want to encrypt the passwords with ansible-vault, however regardless of what I try I keep getting the error:
Vault format unhexlify error: Odd-length string
I initially was trying this in bash under the Windows subsystem for Linux and I thought this may be the issue so I recreated everything on a centos VM and still run into the same issue.
I have tried using encrypt-string to embed the encrypted pw directly into the playbook.
I have also tried encrypting the file and calling the variable. Both methods give the same error.
I found this issue: Ansible-vault errors with "Odd-length string"
And I thought the issue was to do with CRLF line terminators so I sorted that and made sure all files were ASCII text but this still gives the same errors.
My code is below, any help would be majorly appreciated because I am pulling my hair out!
---
- name: napalm_facts
hosts: all
connection: local
gather_facts: no
tasks:
- name: get facts from device
napalm_get_facts:
hostname: "{{ ansible_host }}"
username: 'admin'
password: "{{ napalm_password }}"
dev_os: 'ios'
register: result
- name: print results
debug: msg="{{ result }}"
I've tried the below methods, for reference.
ansible-vault encrypt vars/vaultpw.yml
ansible-vault encrypt_string password123 --ask-vault-pass
I managed to get this sorted by taking suggestions from this thread: Inline encrypted variable not JSON serializable
Thanks for the reply at first, it put me on the right path with getting this sorted.

Using variable from set_fact in roles within same playbook

I'm stuck with using variable from tasks within roles in Ansible playbook. My playbook is following:
- hosts: server.com
gather_facts: yes
tasks:
- set_fact:
private_ip: "{{ item }}"
with_items: "{{ ansible_all_ipv4_addresses }}"
when: "item.startswith('10.')"
- debug: var=private_ip
roles:
- role: check-server
server_ip: 10.10.0.1
client_ip: "{{ private_ip }}
When pleybook is ran -debug shows correct IP inside the variable private_ip, but I can't make client_ip (from roles block) to get private_ip content. client_ip remains always undefined.
What sorcery can I apply here to have client_ip=$private_ip?
tasks are executed after roles are applied.
Change tasks to pre_tasks.
Besides, using set_fact in a loop is not the best practice. If you get the value you want, that's ok, I believe you verified it. But you should rather use (ansible_all_ipv4_addresses | select("match", "10\..*") | list)[0].

Ansible gets variable only from second execution

I've got a strange behavior of Ansible "copy" module when it is working with variables.
So, I have:
1. Config.yml:
- hosts: temp
vars_prompt:
- name: server_name
prompt: "Enter server number: 1, 2, 3..."
private: no
default: 5
- name: server_role
prompt: "Enter server role: app, admin"
private: no
default: admin
- name: server_type
prompt: "Enter server type: stage, prod"
private: no
default: stage
pre_tasks:
- name: Types and roles
set_fact:
servername: "{{ server_name }}"
serverrole: "{{ server_role }}"
servertype: "{{ server_type }}"
vars_files:
- "vars/variables"
roles:
- configs
"Configs" role with main.yml:
---
- set_fact: folder=server
when: serverrole == "app"
- set_fact: folder=admin-server
when: serverrole == "admin"
- set_fact: stageorprod=stage01
when: servertype == "stage"
- set_fact: stageorprod=prod
when: servertype == "prod"
- set_fact: fast={{ stageorprod }}/{{ folder }}/{{ servername }}
- name: Base copying admin-server
copy: src=admin-server/config dest=/home/tomcat/config/{{ fast }}/
when: serverrole == "admin"
Config files in ansible/roles/configs/files/admin-server/config.
When I run playbook with default values of variables (5, admin, stage), I've got:
TASK: [configs | set_fact fast={{stageorprod}}/{{folder}}/{{servername}}] *****
ok: [testcen04] => {"ansible_facts": {"fast": "stage01/admin-server/5"}, "item": ""}
TASK: [configs | Base copying admin-server] ***********************************
failed: [testcen04] => {"failed": true, "item": "", "md5sum": "cb2547d6235c078cfda365a5fb3c27c3",
"path": "/home/tomcat/config/stage01/admin-server/config", "state": "absent"}
msg: path /home/tomcat/config/stage01/admin-server/config does not exist
When I run this task one more time with same values, everything goes ok. But if I change some variable, it appears again.
I have noticed, that other modules, like "Template", works fine in same playbook with this variables. Maybe something wrong with "copy"?
As you can see, variable "fast" gets right values, but somehow, value of "servername" disappeared.
Your question is quite ambiguous to how you are executing your playbook and what you are trying to accomplish with the prompted variables. If you are trying to spin up servers, it's likely better to declare them in the inventory without prompting. If you are trying to access specific ones, you should likely be using groups to limit their range.
If you are using ansible to generate a set of hosts for you. You will likely want to store this information somewhere consistently, probably in a instance tags, a key-value store such as redis, database, or in files, before you spin up the hosts and bootstrap them. Then run a second playbook to include the role.
If you are not in a public cloud, and for some reason cannot tag instances or group them inventory, you can also try using facts.d to set the facts on the server and have them persist across runs, not just plays. Note that once you write to facts.d files, you should re-run setup module to gather facts again. Even though i use public cloud, I often make use of facts.d still.