I am trying to automate ACI with ansible, very new to ansible, as a start point, I started to create simple Tenant and VRF and I am using a variable with my playbook, here it is my playbook like below.
---
- name: Playbook
hosts: APIC
connection: local
gather_facts: no
tasks:
- name: Create new tenant
aci_tenant:
host: "{{ apic_host }}"
username: "{{ apic_username }}"
password: "{{ apic_password }}"
tenant: "{{ tenant_name }}"
validate_certs: False
description: "{{ tenant_description }}"
state: present
# - pause:
# seconds: 10
- name: Add a new VRF
aci_vrf:
host: "{{ apic_host }}"
username: "{{ apic_username }}"
password: "{{ apic_password }}"
tenant: "{{ tenant_name }}"
validate_certs: false
vrf: "{{ vrf_name }}"
policy_control_preference: enforced
policy_control_direction: ingress
state: present
# - pause:
# seconds: 30
and here is my variable file
---
apic_host: sandboxapicdc.cisco.com
apic_username: admin
apic_password: ciscopsdt
tenant_name: zhajili_TN
tenant_description: 'zhajili_first_ansible_tenant'
ap_name: 'AP'
ap_description: 'AP created with Ansible'
vrf_name: 'zhajili_VRF'
When I execute the playbook I receive the following error.
$ ansible-playbook tenants_vrfs.yml -i inventory -v
No config file found; using defaults
PLAY [Playbook] ************************************************************************************************************************************************************************************************
TASK [Create new tenant] ***************************************************************************************************************************************************************************************
fatal: [apicsim_sandbox]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'apic_host' is undefined\n\nThe error appears to be in '/Users/zhajili/Desktop/ansible/ACI/Cisco Sandbox/Tenants_and_VRFs/tasks/tenants_vrfs.yml': line 8, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n tasks:\n - name: Create new tenant\n ^ here\n"}
PLAY RECAP *****************************************************************************************************************************************************************************************************
apicsim_sandbox : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
Related
I want to be able to reference the variable vpc_info registered by file create-public-vpc from file create-public-sunbet
/etc/ansible/roles/ec2/tasks/main.yml
# tasks file for ec2-provision
- name:
import_tasks: create-vpc.yml
import_tasks: create-public-subnet.yml
/etc/ansible/roles/ec2/vars/main.yml
---
# vars file for ec2-provision
################################### designate python interpreter ########################
ansible_python_interpreter: /usr/local/bin/python3.8
############################## VPC INFO #########################################
vpc_name: "My VPC"
vpc_cidr_block: "10.0.0.0/16"
aws_region: "us-east-1"
################################### VPC Subnet ###############################################
aws_zone: "us-east-1a"
# Subnets
vpc_public_subnet_cidr: "10.0.0.0/24"
# Subnet
vpc_private_subnet_cidr: "10.0.1.0/24"
create-vpc.yml
- name: Create AWS VPC
ec2_vpc_net:
name: "{{ vpc_name }}"
cidr_block: "{{ vpc_cidr_block }}"
region: "{{ aws_region }}"
aws_access_key: "{{ access_key }}"
aws_secret_key: "{{ secret_key }}"
state: present
register: vpc_info
- name: Set vpc_info as fact
set_fact:
vpc_info_fact: "{{ vpc_info }}"
create-public-sunbet.yml
- name: print vpc_info_fact
debug:
msg: "{{ hostvars['localhost']['vpc_info_fact'] }}"
- name: Create Public Subnet in VPC
ec2_vpc_subnet:
vpc_id: "{{ vpc_info['vpc']['id'] }}"
cidr: "{{ vpc_public_subnet_cidr }}"
region: "{{ aws_region }}"
az: "{{ aws_zone }}"
aws_access_key: "{{ access_key }}"
aws_secret_key: "{{ secret_key }}"
state: present
tags:
Name: Public Subnet
register: public_subnet_info
When I run ansible-playbook ec2-provision.yml, the error message is as follows:
[root#VM-0-14-centos tasks]# ansible-playbook ec2-provision.yml
[WARNING]: While constructing a mapping from /etc/ansible/roles/EC2/tasks/main.yml, line 4, column 3, found a duplicate dict key (import_tasks). Using last defined value
only.
PLAY [localhost] ************************************************************************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************************************************************
ok: [localhost]
TASK [EC2 : print vpc_info_fact] ********************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'vpc_info_fact' is undefined\n\nThe error appears to be in '/etc/ansible/roles/EC2/tasks/create-public-subnet.yml': line 3, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: print vpc_info_fact\n ^ here\n"}
PLAY RECAP ******************************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
Try to set the variable value as a fact once the variable is created and then you'd access the corresponding fact via hostvars.
For example:
- name: Create AWS VPC
ec2_vpc_net:
name: "{{ vpc_name }}"
cidr_block: "{{ vpc_cidr_block }}"
region: "{{ aws_region }}"
aws_access_key: "{{ access_key }}"
aws_secret_key: "{{ secret_key }}"
state: present
register: vpc_info
- name: Set vpc_info as fact
set_fact: vpc_info_fact="{{ vpc_info }}"
To access it from a different file, we have the following task:
- name: Create Public Subnet in VPC
ec2_vpc_subnet:
vpc_id: "{{ hostvars['localhost']['vpc_info']['vpc']['id'] }}"
cidr: "{{ vpc_public_subnet_cidr }}"
region: "{{ aws_region }}"
az: "{{ aws_zone }}"
aws_access_key: "{{ access_key }}"
aws_secret_key: "{{ secret_key }}"
state: present
tags:
Name: Public Subnet
register: public_subnet_info
Your main.yml contains a tasks with two modules. It should be
- name: Create VPC
import_tasks: create-vpc.yml
- name: Create Public Subnets
import_tasks: create-public-subnet.yml
The running playbooks prints the warning about that issue.
[WARNING]: While constructing a mapping from /etc/ansible/roles/EC2/tasks/main.yml, line 4, column 3, found a duplicate dict key (import_tasks). Using last defined value
only.
Ansible cannot have more then one module per task - and include_tasks is a module. It picks the last module, if there are multiple modules in one task (after writing the warning message and not exiting).
This is the main problem of all your issues. Everything else looks ok to me.
I'm facing a mysterious ansible behaviour.
I've set groups, hosts and groups vars in my inventory file, but the ansible-playbook command is raising Undefined Variable for all my group vars, while printing them with the ansible debug module show the variable well.
Here is my inventory.ini file:
[windows]
ad_server ansible_host=mrspw00550.mydomain.com
[windows:vars]
ansible_connection=winrm
ansible_winrm_transport=ntlm
ansible_port=5985
ansible_become_method=runas
dns_zone=mydomain.com
ptr_zone=10.in-addr.arpa
dns_server=10.0.100.100
[linux]
web_server ansible_host=10.0.101.129
[linux:vars]
ansible_connection=ssh
ansible_become=yes
ansible_become_method=sudo
dns_zone=mydomain.com
ptr_zone=10.in-addr.arpa
dns_server=10.0.100.100
linux_home_dir=/home/ldaphome
the playbook file (set-hostname-and-dns.yml):
- name: Debug vars
debug: var=hostvars[inventory_hostname]['dns_zone']
delegate_to: ad_server
- name: Set hostname and make DNS registrations
block:
- name: Set hostname
hostname:
name: "web.{{ dns_zone }}"
delegate_to: web_server
- name: Create a DNS registration of type A
win_dns_record:
name: "web"
type: "A"
value: "{{ inventory_hostname }}"
zone: "{{ dns_zone }}"
computer_name: "{{ dns_server }}"
delegate_to: "{{ ad_server }}"
- name: Create a DNS registration of type PTR
win_dns_record:
name: "{{ inventory_hostname }}"
type: "PTR"
value: "web"
zone: "{{ ptr_zone }}"
computer_name: "{{ dns_server }}"
delegate_to: "{{ ad_server }}"
Running the ansible-playbook command gives :
$ ansible-playbook playbook.yml -i inventory-files/inventory.ini
PLAY [localhost] *********************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************************************************************************
ok: [localhost]
TASK [create-linux-vm : Debug vars] **************************************************************************************************************************************************************************
ok: [localhost -> mrspw00550.mydomain.com] => {
"hostvars[inventory_hostname]['dns_zone']": "VARIABLE IS NOT DEFINED!"
}
TASK [create-linux-vm : Set web_server hostname] **************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dns_zone' is undefined\n\nThe error appears to be in 'set-hostname-and-dns.yml': line 14, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n block:\n - name: Set {{ vm_name }} hostname\n ^ here\nWe could be wrong, but this one looks like it might be an issue with\nmissing quotes. Always quote template expression brackets when they\nstart a value. For instance:\n\n with_items:\n - {{ foo }}\n\nShould be written as:\n\n with_items:\n - \"{{ foo }}\"\n"}
PLAY RECAP ***************************************************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
Running debug module:
$ ansible -m debug -i inventory-files/inventory.ini -a "var=hostvars[inventory_hostname]['dns_zone']" all
ad_server | SUCCESS => {
"hostvars[inventory_hostname]['dns_zone']": "mydomain.com"
}
web_server | SUCCESS => {
"hostvars[inventory_hostname]['dns_zone']": "mydomain.com"
}
$
So as you can see, ansible-playbook command is unable to retrieve my host vars, while ansible debug module does.
The result is the same even if I define those variables in inventory-files/group_vars/linux.yml or inventory-files/group_vars/windows.yml, the variable is still as undefined by ansible. The problem is the same if try to access any other variable than special variables from inventory running ansible-playbook
What could be wrong there?
I tried with delegate_facts set to true, it didn't work.
Then defined a local group in the inventory containing localhost and defined my local group vars there like this :
[local]
localhost
[local:vars]
ansible_connection=local
dns_zone=mydomain.com
ptr_zone=10.in-addr.arpa
dns_server=10.0.100.100
linux_home_dir=/home/ldaphome
and remove those var from remote hosts facts, as I don't really those variables there. All my tasks are executed on the localhost and delegated to the remote hosts depending to the action.
I'd also like to precise that specifically ask for var/fact like #Zeitounator mentioned above ({{ hostvars['ad_server'].ptr_zone }}) in his comment works too.
I am trying to create new users and groups using Ansible playbook. Below is my folder structure.
tree
.
├── create-users.yaml
└── ubuntu
create-users.yaml playbook contains create user and group tasks. Note, I am not having any group (admin_group) and users (Rajini, Kamal) in my target machine, instead they will be created when running the playbook.
---
- name: Create Users & Groups
hosts: target1
gather_facts: false
tasks:
- name: Create Users Task
user:
name: "{{ item }}"
state: present
password: "{{ 'default_user_password' | password_hash('sha512','A512') }}"
shell: /bin/bash
groups: "{{ admin_group }}"
loop:
- Rajini
- Kamal
I have another file called ubuntu to pick group name and password. When running the playbook I am getting below error.
ansible-playbook --vault-id #prompt create-users.yaml -K
BECOME password:
Vault password (default):
PLAY [Create Users & Groups] *****************************************************************************************************************************************************************
TASK [Create Users Task] *********************************************************************************************************************************************************************
fatal: [target1]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'admin_group' is undefined\n\nThe error appears to be in '/home/osboxes/Ansible_Project/web_deployment/Ansible/groups_vars/create-users.yaml': line 6, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n tasks:\n - name: Create Users Task\n ^ here\n"}
PLAY RECAP ***********************************************************************************************************************************************************************************
target1 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
admin_group: admin
default_user_password: Password1
Can somebody please help me on this?
Updating Output after getting help from user Moon.
ansible-playbook --vault-id #prompt create-users.yaml -K
BECOME password:
Vault password (default):
PLAY [Create Users & Groups] *****************************************************************************************************************************************************************
TASK [Create Users Task] *********************************************************************************************************************************************************************
changed: [target1] => (item=Rajini)
changed: [target1] => (item=Kamal)
PLAY RECAP ***********************************************************************************************************************************************************************************
target1 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ssh Kamal#192.168.0.1
Kamal#192.168.0.1's password:
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 5.0.0-23-generic x86_64)
Kamal#Ansible_Target1:~$ id
uid=1005(Kamal) gid=1001(admin) groups=1001(admin)
Couple of things:
To use variables from ubuntu file you need specify the vars file in playbook.
To use default_user_password as a variable, remove the quotes '
If you want admin as the users primary group then use group attribute instead. groups on the other hand takes a list and add the users to the listed groups.
And, if the group isn't created yet on the target machine then first create the group using group module.
Playbook after the above changes.
---
- name: Create Users & Groups
hosts: target1
gather_facts: false
vars_files: ubuntu
tasks:
- name: Create group
group:
name: "{{ admin_group }}"
state: present
- name: Create Users Task
user:
name: "{{ item }}"
state: present
password: "{{ default_user_password | password_hash('sha512','A512') }}"
shell: /bin/bash
group: "{{ admin_group }}"
loop:
- Rajini
- Kamal
This will help you make your playbook more dynamic:
create a secret.yml file for storing user password using below command:
ansible-vault create secret.yml
#sample:
user_password: mypass#155
create userlist.yml to specify the list of user and their department:
vim userlist.yml
#sample:
##user matching job role mentioned in create-user.yml playbook will be created
- users:
- name: "user1"
job: "developer"
- name: "user2"
job: "devops"
- name: "user3"
job: "developer"
Now create your playbook as follows:
vim user-create.yml
- hosts: appserver1
vars_files:
- secret.yml
- userlist.yml
tasks:
- name: "create group"
group:
name: "{{ item }}"
loop:
- "dev"
- "devops"
- name: "create user when Job=developer from userlist.yml file with password from secret.yml file and add to secondary group 'dev' "
user:
name: "{{ item['name'] }}"
password: "{{ user_password | password_hash('sha512') }}"
update_password: on_create
groups: "dev"
append: yes
loop: "{{ users }}"
when: "item['job'] == 'developer'"
- name: "create user when Job=devops from userlist.yml file with password from secret.yml file and add to secondary group 'devops' "
user:
name: "{{ item['name'] }}"
password: "{{ user_password | password_hash('sha512') }}"
update_password: on_create
groups: "devops"
append: yes
loop: "{{ users }}"
when: "item['job'] == 'devops'"
Run the playbook
ansible-playbook -i inventory user-create.yml --ask-vault-pass
Things to remember
If you do not specify the update_password: on_create option, Ansible re-sets the user password every time the playbook is run: if the user has changed the password since the last time the playbook was run, Ansible re-sets password.
I am following the redhat ansible course online and I followed the below steps to use multi-valued variable in a playbook. But I am hitting an error stating there's an undefined variable
Below is my arrays.yaml file
---
- name: show arrays
hosts: ansible1.example.com
vars_files:
- vars/users
tasks:
- name: print array values
debug:
msg: "User {{ item.username }} has homedirectory {{ item.homedir }} and shell {{ item.shell }}"
with_items: "{{ users }}"
And below is vars/users file
users:
linda:
username: linda
homedir: /home/linda
shell: /bin/bash
gokul:
username: gokul
homedir: /home/gokul
shell: /bin/bash
saha:
username: saha
homedir: /home/gokul/saha
shell: /bin/bash
And below is the error that I am hitting
ansible-playbook arrays.yaml
PLAY [show arrays] *****************************************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************************************************************************************************************
ok: [ansible1.example.com]
TASK [print array values] **********************************************************************************************************************************************************************************************************************************
fatal: [ansible1.example.com]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'ansible.utils.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'username'\n\nThe error appears to be in '/home/ansible/install/arrays.yaml': line 7, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n tasks:\n - name: print array values\n ^ here\n"}
PLAY RECAP *************************************************************************************************************************************************************************************************************************************************
ansible1.example.com : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
However, when I try to refer individual values like below in the playbook, it works fine.
---
- name: show arrays
hosts: ansible1.example.com
vars_files:
- vars/users
tasks:
- name: print array values
debug:
msg: "User {{ users.gokul.username }} has homedirectory {{ users.gokul.homedir }} and shell {{ users.gokul.shell }}"
It's not possible to iterate a dictionary. Either the code or the data should be changed.
1. Change data
Use a list of users instead of a dictionary. For example, the list below
users:
- username: linda
homedir: /home/linda
shell: /bin/bash
- username: gokul
homedir: /home/gokul
shell: /bin/bash
- username: saha
homedir: /home/gokul/saha
shell: /bin/bash
would work as expected
- name: print array values
debug:
msg: "User {{ item.username }}
has homedirectory {{ item.homedir }}
and shell {{ item.shell }}"
loop: "{{ users }}"
2. Change code
It's possible to use the users dictionary with the filter dict2items. For example, the task below would give the same result
- name: print array values
debug:
msg: "User {{ item.value.username }}
has homedirectory {{ item.value.homedir }}
and shell {{ item.value.shell }}"
loop: "{{ users|dict2items }}"
I am iterating over yml file and filtering and keeping those microservice metadata in the list which is in the command line argument passed
ansible-playbook -i inventory/inventory sp-deployer.yml --ask-vault-pass --extra-vars '{"microservices_list":[iwan,csrservice]}'
Finally I need these three value from the yml file based on the criteria mentioned above. I have created ansible sp-deployer.yml for this purpose. I have used set_facts for creating dynamic list. First list works fine but the moment I create second one it fails.
name: "ms_service"
port: "830"
streams: "noti,jk-noti"
vars.yml
version: 1
name: user
jobs:
ns1:
ip: "1.1.1.1"
ns_version: "4.2"
f_packs:
- f-pack-1:
name: "pack1"
microservices:
- microservice-1:
name: "ms_service"
port: "830"
streams: "noti,jk-noti"
- microservice-2:
name: "ms_service1"
port: "830"
streams: "noti1,jk-noti1"
- f-pack-2:
name: "pack4"
microservices:
- microservice-1:
name: "ms_service3"
port: "830"
streams: "noti,jk-noti3"
- microservice-2:
name: "ms_service4"
port: "830"
streams: "noti,jk-noti4"
- microservice-3:
name: "ms_service5"
port: "830"
streams: "noti,jk-noti5"
Script:sp-deployer.yml
---
- hosts: localhost
vars_files:
- ./vars.yml
sudo: yes
tasks:
- name: Reading vars.yml file and preparing list of microservice with its metadata
set_fact: foo_item="{{ item.1 }}"
register: result
with_subelements:
- "{{ jobs.ns1.f_packs }}" ###item.0
- microservices ###item.1
- name: make first list
set_fact: foo="{{ result.results | map(attribute='ansible_facts.foo_item') | list }}"
- name: print register
debug: msg="{{ item }}" verbosity=3
with_items:
- "{{ foo }}"
- name: Filtering micro service list with match found from command line input
when: item[0].name == item[1]
set_fact: foo_item1="{{ item.0 }}"
register: result_final
with_nested:
- "{{ foo }}"
- "{{ microservices_list }}"
- name: make a list
set_fact: foo1="{{ result_final.results | map(attribute='ansible_facts.foo_item1') | list }}"
ERROR
TASK [make a list] *************************************************************
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: 'dict object' has no attribute 'ansible_facts'\n\nThe error appears to have been in '/home/user/ansible/sp-deployer1.yml': line 40, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: make a list\n ^ here\n"}
to retry, use: --limit #/home/user/ansible/sp-deployer1.retry
PLAY RECAP *********************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=1
Friendly advice: always check registered variables with debug if you bump on such errors.
The reason for your error is that set_fact don't yield ansible_facts dict if the loop iteration is skipped.
And I see you have when statement in your loop.
To overcome this error, you should select only those loop iterations, that have ansible_facts dict defined:
- name: make a list
set_fact: foo1="{{ result_final.results | selectattr('ansible_facts','defined') | map(attribute='ansible_facts.foo_item1') | list }}"