I'm using Vagrant (Virtual Box provider) to setup a local Virtual Machine. I'm also using ansible and more specific ansible_local (Vagrant plugin) to deploy some tools into the VM.
Initially I'm trying to create a new user following the ansible documentation.
---
- name: Master Node
hosts: 127.0.0.1
connection: local
user: root
vars_files:
- vars/vars.yml
vars:
username: nikolas
tasks:
- name: Adding user
user: name={{username}} shell=/bin/bash groups=root append=yes password={{pass}}
sudo: yes
- name: Placing RSA key
authorized_key: user={{username}} key="{{ lookup('file', 'id_rsa.pub') }}"
sudo: yes
When I run the playbook, I get this message:
PLAY [Master Node] ************************************************************
GATHERING FACTS ***************************************************************
ok: [127.0.0.1]
TASK: [Adding user] **************************************************
changed: [127.0.0.1] => {"changed": true, "comment": "", "createhome": >true, "group": 1001, "groups": "root", "home": "/home/nikolas", "name": >"nikolas", "password": "NOT_LOGGING_PASSWORD", "shell": "/bin/bash", >"state": "present", "system": false, "uid": 1001}
TASK: [Placing RSA key] *******************************************************
changed: [127.0.0.1] => {"changed": true, "key": "ssh-rsa >AAAAB3N....public_rsa_key", "key_options": null, >"keyfile": "/home/desmotes/.ssh/authorized_keys", "manage_dir": true, >"path": null, "state": "present", "unique": false, "user": "nikolas"}
PLAY RECAP ********************************************************************
127.0.0.1 : ok=4 changed=2 unreachable=0 >failed=0
"password": "NOT_LOGGING_PASSWORD"
As a result, when i am trying to logged in as nikolas in the VM to get authentication error.
Do you know where is my mistake ?
Thank you
I think you need to modified your user creation task like this:
- name: Adding user
user: name={{username}} shell=/bin/bash groups=root append=yes password={{ pass | password_hash('sha512') }}
sudo: yes
Hope that help you.
Related
I am trying to execute a playbook for setting up Dell servers and I have some problems with a dictionary in module idrac_redfish_config. I need to enable SOL for a specific user, but for this I want to use a key in the dictionary with a variable because ID of user can be different from server to server.
How I try to add a variable to a dictionary key like this:
- name: Store id test-user
set_fact:
ID: "{{ result.redfish_facts.user.entries | json_query(\"[?UserName=='test-user'].Id\") }}"
- name: Enable SOL for test-user
community.general.idrac_redfish_config:
category: Manager
command: SetManagerAttributes
resource_id: iDRAC.Embedded.1
manager_attributes:
Users.{{ ID[0] }}.SolEnable: "Enabled" <---
Users.{{ ID[0] }}.IpmiLanPrivilege: "Administrator" <---
baseuri: "testhost"
username: "admin"
password: "admin"
I get this error:
TASK [Store id test-user] **************************************************************************************************************************************************************************************
ok: [localhost] => {
"ansible_facts": {
"ID": [
"8"
]
},
"changed": false
}
TASK [Enable SOL for test-user] ********************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {
"changed": false,
"invocation": {
"module_args": {
"baseuri": "testhost",
"category": "Manager",
"command": [
"SetManagerAttributes"
],
"manager_attribute_name": null,
"manager_attribute_value": null,
"manager_attributes": {
"Users.{{ ID[0] }}.IpmiLanPrivilege": "Administrator",
"Users.{{ ID[0] }}.SolEnable": "Enabled"
},
"password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"resource_id": "iDRAC.Embedded.1",
"timeout": 10,
"username": "admin"
}
},
"msg": "SetManagerAttributes: Manager attribute Users.{{ ID[0] }}.SolEnable not found"
}
If I do this:
manager_attributes: "{
'Users.{{ ID[0] }}.SolEnable': Enabled
'Users.{{ ID[0] }}.IpmiLanPrivilege': Administrator
}"
I get:
fatal: [localhost]: FAILED! => {
"changed": false,
"invocation": {
"module_args": {
"baseuri": "testhost",
"category": "Manager",
"command": [
"SetManagerAttributes"
],
"manager_attributes": "{ 'Users.8.SolEnable': Enabled 'Users.8.IpmiLanPrivilege': Administrator }",
"password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"resource_id": "iDRAC.Embedded.1",
"timeout": 10,
"username": "admin"
}
},
"msg": "argument manager_attributes is of type <class 'str'> and we were unable to convert to dict: unable to evaluate string as dictionary"
}
I didn't find in Ansible documentation how to do this correctly.
According to documentation, manager_attributes should be a dict of key/value pairs to set on your device. The keys have dots in their names and you cannot "statically" create dynamic key names as you tried above (i.e. "prefix{{ dynamic_value }}suffix": "some content" does not work as you experienced by yourself since the key name does not go through jinja2 templating).
Below is a solution. It's far from being the only one but that's the first that came to my mind and I could setup an example for you quickly. In this case, I create a list of {key: X, value: Y} dicts with your dynamic names as keys and use the items2dict filter to transform this back to a dict itself.
I don't have a network device to play this against so I could not verify that the final result is actually accepted by the module. My example simply uses a debug with your input data to illustrate and outputs a dictionary as the module expects. You will have to tune the exact key names if they are wrong but at least you should be able to move forward.
- name: Dynamic dict
hosts: localhost
gather_facts: false
vars:
ID:
- "8"
my_attributes:
- key: "Users.{{ ID[0] }}.IpmiLandPrivilege"
value: Administrator
- key: "Users.{{ ID[0] }}.SolEnable"
value: Enabled
tasks:
- name: construct a dynamic dict and debug
vars:
manager_attributes: "{{ my_attributes | items2dict }}"
debug:
var: manager_attributes
Which gives:
PLAY [Dynamic dict demo] ***************************************************************************************************************************************************************************************************************
TASK [construct a dynamic dict and debug] **********************************************************************************************************************************************************************************************
ok: [localhost] => {
"manager_attributes": {
"Users.8.IpmiLandPrivilege": "Administrator",
"Users.8.SolEnable": "Enabled"
}
}
PLAY RECAP *****************************************************************************************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Edit: An additional (out of many others) example to achieve the same goal. The output is exactly the same as above:
- name: Dynamic dict
hosts: localhost
gather_facts: false
vars:
ID:
- "8"
manager_attributes: "{{
{
'Users.' + ID[0] + '.IpmiLandPrivilege': 'Administrator',
'Users.' + ID[0] + '.SolEnable': 'Enabled'
}
}}"
tasks:
- name: construct a dynamic dict and debug
debug:
var: manager_attributes
I'm trying sort out my inventory.yaml file to arrange hosts by groups and then call them in an Ansible playbook.
The inventory.yaml file looks like this:
---
all:
hosts:
children:
MY_Lab:
Ubuntu_18:
hosts:
BWT_BKP_A:
ansible_host: "10.2.8.19"
BWT_BKP_B:
ansible_host: "10.2.8.22"
BWT_BKP_C:
ansible_host: "10.2.9.12"
vars:
ansible_connection: ssh
ansible_user: administrator
ansible_ssh_pass: P#ssword
ansible_sudo_pass: P#ssword
From my Ansible playbook I'd like to access hosts on Ubuntu_18 section, but I can't:
name: Test connectivity
hosts: BWT_BKP_A
vars:
ansible_python_interpreter: /usr/bin/python3
tasks:
- name: Ping test
ping:
I get the following error:
ansible-playbook ping-test.yaml -i inventory.yaml
[WARNING]: Could not match supplied host pattern, ignoring: BWT_BKP_A
PLAY [Test connectivity] *****************************************************************************************************
skipping: no hosts matched
If I try the whole group, like :
hosts: Ubuntu_18
I get the same error.
Not sure what I'm missing. I'm using ansible 2.9.12
You have an error in your inventory file. The children key should be a peer of hosts, not a child, and every time you are trying to create a "subgroup" you need another children: key.
Using this as my test inventory:
---
all:
children:
MY_Lab:
children:
Ubuntu_18:
hosts:
BWT_BKP_A:
ansible_host: "127.0.0.1"
BWT_BKP_B:
ansible_host: "127.0.0.1"
BWT_BKP_C:
ansible_host: "127.0.0.1"
I can run:
$ ansible -i hosts.yml -m ping MY_Lab
BWT_BKP_B | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
BWT_BKP_A | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
BWT_BKP_C | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
Or:
$ ansible -i hosts.yml -m ping BWT_BKP_A
BWT_BKP_A | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
Etc.
I'm trying to extract value of vm datastore with ansible snippet:
- name: Gather disk facts from virtual machine using name
vmware_guest_disk_facts:
hostname: "{{ vcenter_server }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
datacenter: "{{ datacenter }}"
validate_certs: no
name: "{{ item }}"
delegate_to: localhost
register: disk_facts
with_items: "{{ vm_list }}"
- name: Get disk info
debug:
var: disk_facts.results.guest_disk_facts.backing_datastore
Output:
[root#sysmgttl1 lvm]# ansible-playbook -i hosts vmfacts.yml -e vcenter_server=vmimgtpw002 -e vm_list=sndprfql8
PLAY [sndprfql8] ***********************************************************************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************************************************************************
ok: [sndprfql8]
TASK [Gather disk facts from virtual machine using name] *******************************************************************************************************************
ok: [sndprfql8 -> localhost] => (item=sndprfql8)
TASK [Get disk info] *******************************************************************************************************************************************************
ok: [sndprfql8] => {
"disk_facts.results.guest_disk_facts.backing_datastore": "VARIABLE IS NOT DEFINED!"
}
PLAY RECAP *****************************************************************************************************************************************************************
sndprfql8 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
This is what my disk_facts looks like.
ok: [sndprfql8] => {
"disk_facts": {
"changed": false,
"msg": "All items completed",
"results": [
{
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"guest_disk_facts": {
"0": {
"backing_datastore": "QADEV07",
"backing_eagerlyscrub": false,
"backing_filename": "[QADEV07] sndprfql8/sndprfql8.vmdk",
"backing_thinprovisioned": true,
"backing_type": "FlatVer2",
"backing_uuid": "6000C292-7716-6296-de04-69bac9186661",
"backing_writethrough": false,
"capacity_in_bytes": 68719476736,
"capacity_in_kb": 67108864,
"controller_key": 1000,
"key": 2000,
"label": "Hard disk 1",
"summary": "67,108,864 KB",
"unit_number": 0
}
},
"invocation": {
"module_args": {
"datacenter": "RDC",
"folder": null,
"hostname": "vmimgtpw002",
"name": "sndprfql8",
"password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"port": 443,
"use_instance_uuid": false,
"username": "svcvread#chop.edu",
"uuid": null,
"validate_certs": false
}
},
"item": "sndprfql8"
}
]
}
}
If this is really for a one shot use, the following should do:
- name: Get disk info
debug:
var: disk_facts.results[0].guest_disk_facts['0'].backing_datastore
If you goal is to get all values for a list of vms in the result possibly having several disks, the following will give you a flattened list (that you can de-duplicate with the unique filter if needed)
- debug:
msg: "{{ disk_facts | json_query('results[].guest_disk_facts.*[].backing_datastore') }}"
I have created a user using ansible and now would like to copy the .ssh/id_rsa.pub file to the authorized_keys file.
I checked the authorized_keys module but that is used to copy the keys from the host machine to the guest.
Wondering what would the right approach.
- name: Adding user - {{ user }}
user: name={{ user }}
group={{ group }}
shell=/bin/bash
password=${password}
groups=sudo
append=yes
generate_ssh_key=yes
ssh_key_bits=2048
ssh_key_file=.ssh/id_rsa
The generated key is returned by the user module, so you can register the result and then use the key in a subsequent authorized_key task. That is, if I have a playbook like this:
- hosts: localhost
tasks:
- name: add user
user:
name: testuser
shell: /bin/bash
password: secret
append: yes
generate_ssh_key: yes
ssh_key_bits: 2048
register: newuser
- debug:
var: newuser
I will see as output something like:
TASK [debug] *******************************************************************
ok: [localhost] => {
"newuser": {
"append": true,
"changed": true,
"comment": "",
"group": 21946,
"home": "/home/testuser",
"move_home": false,
"name": "testuser",
"password": "NOT_LOGGING_PASSWORD",
"shell": "/bin/bash",
"ssh_fingerprint": "2048 SHA256:Tn6UOl/WYToJCaW3QUnLMWgEfthILIsoCP+534qWzfw ansible-generated on lkellogg-pc0dzzve (RSA)",
"ssh_key_file": "/home/testuser/.ssh/id_rsa",
"ssh_public_key": "ssh-rsa ... ansible-generated on examplehost",
"state": "present",
"uid": 21940
}
}
So you can add a task like this:
- authorized_key:
user: root
state: present
key: "{{ newuser.ssh_public_key }}"
What would be the correct approach to loop through a complex dictionary variable in an Ansible play in order to be able to call items from different layers of the variable in the same module/task?
The variable in question looks like this (but it could be any number of layers down, so far I only have about 3 layers down):
installation:
v10:
installs: yes
das_username: dasusr
das_group: dasadm
package_name: v10.tar.gz
binaries_folder: binaries
install_path: /opt/V10
instances:
inst1:
enabled: yes
username: inst1
group: dbiadm
port: 50000
databases:
jts:
name: 'JTS'
state: present
pagesize: 32768
rtc:
name: 'CCM'
state: absent
pagesize: 16384
rqm:
name: 'QM'
state: absent
pagesize: 32768
inst2:
enabled: no
username: inst2
group: dbiadm
port: 50005
databases:
warehouse:
name: 'DW'
state: present
pagesize: 32768
v9:
installs: no
instances:
inst3:
enabled: no
databases:
rqm:
name: 'RM'
state: absent
pagesize: 32768
lqe:
name: 'LQE'
state: absent
pagesize: 16384
Tasks include creating databases using the install_path (layer 1) and databases parameters (layer 3) under the same shell module or in a template.
For example (the task should look something like this) but with the correct method of looping:
- name: Creating the databases
become_user: "{{ item.0.instances.username }}"
shell: "./db2 create database {{ item.1.name }} using pagesize {{ item.1.pagesize }}"
args:
chdir: "{{ item.0.install_path }}/bin"
with_subelements:
- "{{ installation }}"
- instances.databases.clm
Thank you!
It's not a trivial feat to do such thing in ansible, becase loops in ansible are one-dimensional. There is a hackish way though, you can use nested includes with loop control. So let's say i put all of your variables inside vars.yml and have a following files:
playbook-nested.yml
- hosts: localhost
tasks:
- name: pass version forward
include: instances.yml v="{{ version_item }}"
with_items: "{{ installation }}"
loop_control:
loop_var: version_item
instances.yml
- name: Pass instance forward
include: databases.yml i={{ instance_item }}
with_items: "{{ installation[v].instances }}"
loop_control:
loop_var: instance_item
databases.yml
- name: echo command
debug: msg="./db2 create database {{ item.name }} using pagesize {{ item.pagesize }}"
with_items: "{{ installation[v].instances[i].databases.clm }}"
when: installation[v].instances[i].databases.clm is defined
So the output of command ansible-playbook playbook-nested.yml -e #vars.yml will be:
PLAY [localhost] ***************************************************************
TASK [setup] *******************************************************************
ok: [localhost]
TASK [pass version forward] ****************************************************
included: /home/user/instances.yml for localhost
included: /home/user/instances.yml for localhost
TASK [Pass instance forward] ***************************************************
included: /home/user/databases.yml for localhost
TASK [echo command] ************************************************************
ok: [localhost] => (item={u'state': u'absent', u'name': u'RQM', u'pagesize': 32768}) => {
"item": {
"name": "RQM",
"pagesize": 32768,
"state": "absent"
},
"msg": "./db2 create database RQM using pagesize 32768"
}
ok: [localhost] => (item={u'state': u'absent', u'name': u'LQE', u'pagesize': 16384}) => {
"item": {
"name": "LQE",
"pagesize": 16384,
"state": "absent"
},
"msg": "./db2 create database LQE using pagesize 16384"
}
TASK [Pass instance forward] ***************************************************
included: /home/user/databases.yml for localhost
included: /home/user/databases.yml for localhost
TASK [echo command] ************************************************************
ok: [localhost] => (item={u'state': u'present', u'name': u'JTS', u'pagesize': 32768}) => {
"item": {
"name": "JTS",
"pagesize": 32768,
"state": "present"
},
"msg": "./db2 create database JTS using pagesize 32768"
}
ok: [localhost] => (item={u'state': u'absent', u'name': u'CCM', u'pagesize': 16384}) => {
"item": {
"name": "CCM",
"pagesize": 16384,
"state": "absent"
},
"msg": "./db2 create database CCM using pagesize 16384"
}
ok: [localhost] => (item={u'state': u'absent', u'name': u'QM', u'pagesize': 32768}) => {
"item": {
"name": "QM",
"pagesize": 32768,
"state": "absent"
},
"msg": "./db2 create database QM using pagesize 32768"
}
TASK [echo command] ************************************************************
skipping: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=8 changed=0 unreachable=0 failed=0
I'm not sure what does clm mean and do i have to loop over databases as well, but i think the concept is clear to you now.
You can also use the nested_loops on the lower level i guess.