Open yorick1989 opened 2 years ago
It seems to me that there is already functionality to not use the connection plugin, by simply removing the connection plugin configuration file?
Also, the resolving of libvirt domains to IP addresses is the sort of thing that belongs in an inventory plugin, surely?
If you're wanting to connect via SSH then the inventory plugin should resolve libvirt domains to IP addresses, then the normal SSH connection plugin does the usual from there.
Thank you for your feedback.
How do I remove the 'connection plugin configuration file'? I only use the inventory filename that contains:
plugin: community.libvirt.libvirt
uri: 'qemu:///system'
use_connection_plugin: False
filter: "test0(1|3)+"
By the way, my changes are done in the inventory code, not in the connection plugin code. There was no option to skip the connection plugin within the libvirt inventory file, that is why I added the option to skip the connection plugin by adding the use_connection_plugin
option to use an alternative way which pulls the IP address and adds the first found IP address to the host variables (as ansible_host
); so this IP address can used for SSH connections. There was also a comment in the inventory code to make the connection plugin optional. This is why I made these changes and I would like to give it back to the upstream; if it is a beneficial addition.
If there is a better alternative, please let me know. I just tried to create a way to get this inventory plugin to work without using the connection plugin; since that's by default not working for Red Hat servers (since the 'guest-file-open,guest-file-close,guest-file-read,guest-file-write,guest-file-seek,guest-file-flush,guest-exec,guest-exec-status' options are blocked within the configuration of the qemu-guest-agent
package / installation).
Thanks!
Hi @yorick1989 thanks for this contribution, I will test it out. i can see that on RHEL machines qemu guest agent does not support the required options so I think another option is useful :+1: I may have confused @odyssey4me when I was talking to him about this, as I incorrectly said it was in the connection not the inventory code. Sorry!
If we are going to rely on getting the IP from libvirt then I feel like it has to be very robust. Also, how will we handle failure scenarios? I'm wondering how this might work in edge cases, such as when an IP is not available yet, or perhaps only an IPv6 (still waiting for IPv4), or guests which have multiple network interfaces, etc. Also, how will it work with multiple inventories, or where one has specified ansible_host
already elsewhere? Have you had a chance to test any of those scenarios?
Also, are there any additional requirements for this to work? Thanks!
I've done some basic testing with an inventory file like so:
---
plugin: community.libvirt.libvirt
uri: 'qemu:///system'
use_connection_plugin: False
filter: "ansible-fedora-35"
it works as expected, SSHing into the guest:
(3.9) [09:40 csmart@dev ~/.../community/libvirt (connection_filter $%)]$ date
Tue 01 Feb 2022 09:40:05 AEDT
(3.9) [09:40 csmart@dev ~/.../community/libvirt (connection_filter $%)]$ ansible -i ../../kvm.yml all --limit ansible-fedora-35 -m command -a 'whoami'
ansible-fedora-35 | CHANGED | rc=0 >>
csmart
(3.9) [09:40 csmart@dev ~/.../community/libvirt (connection_filter $%)]$ ssh ansible-fedora-35 last |head -1
csmart pts/0 192.168.112.1 Tue Feb 1 09:40 - 09:40 (00:00)
I have tested with a filter
applied but use_connection_plugin
set to false
so that it uses guest agent rather than SSH:
---
plugin: community.libvirt.libvirt
uri: 'qemu:///system'
#use_connection_plugin: False
filter: "ansible-fedora-35"
It works as expected.
(3.9) [09:45 csmart@dev ~/.../community/libvirt (connection_filter $%)]$ ansible -i ../../kvm.yml all -m command -a 'whoami'
ansible-fedora-35 | CHANGED | rc=0 >>
root
I have tested using SSH but when there is no filter
specified in the inventory:
---
plugin: community.libvirt.libvirt
uri: 'qemu:///system'
use_connection_plugin: False
#filter: "ansible-fedora-35"
However Ansible is not able to parse the inventory. I think we would need to make sure that by default, an empty or missing filter resulted in a complete list of all VMs (the default without this code).
(3.9) [09:42 csmart@dev ~/.../community/libvirt (connection_filter $%)]$ ansible -i ../../kvm.yml all -m command -a 'whoami'
libvirt: Domain Config error : Requested operation is not valid: domain is not running
[WARNING]: * Failed to parse /home/csmart/ansible_collections/kvm.yml with
ansible_collections.community.libvirt.plugins.inventory.libvirt plugin: Requested operation is not valid: domain is not running
[WARNING]: Unable to parse /home/csmart/ansible_collections/kvm.yml as an inventory source
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
I've also tested with use_connection_plugin: True
and it works as expected.
Cheers!
@csmart thanks for testing and the great report! @yorick1989 @odyssey4me any thoughts / related questions/updates?
Aha, I get it now. I love the addition of the filter... that's a great idea! Then the ability to enable/disable the connection plugin seems like it makes sense. My apologies for the previous misunderstanding!
Thank you all for the feedback!
@csmart Thank you for testing! I also tested it myself and it works for me:
[yorick@yorick-pc ansible]$ cat libvirt_qemu.yml
plugin: community.libvirt.libvirt
uri: 'qemu:///system'
use_connection_plugin: False
#filter: "test-4[0-9]+"
[yorick@yorick-pc ansible]$ ansible -i libvirt_qemu.yml all -m ping
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details
kali | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: ansible@192.168.122.129: Permission denied (publickey,password).",
"unreachable": true
}
test04 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
test01 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
test03 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
So, it's not clear to me why it failed on your side. The filter uses regex and by default the filter value is set to .*
; so that should match every host by default.
Also thanks for the feedback in your first reply. Here my replies to your questions:
ansible_libvirt_ifaces
dict which can be used to filter out the proper IP-addresses and set that proper one as ansible_host
yourself in a (pre-executed) playbook. I know it's ugly, but if one of you can give me a better solution, please feel free to advice me! \
And I don't know how to act on servers which don't have an IP-address available (,yet). If the inventory plugin simply can't find it in libvirt, then the logic within the inventory plugin should set the ansible_libvirt_ifaces
variable to an empty list. Or is that too simple? =) \
And IPv6 addresses shouldn't be a problem I guess, if the host can be reached on it. Or am I missing something?_ansible_host
, before setting it. But shouldn't the last sourced inventory overwrite the already existing variables by default?_As you can see, I'm pretty new with this kind of modifications. I needed this modification to deploy / destroy my servers on a quickly manner using terraform. So any help to improve my changes is very welcome!
…ins / uuids using regex.
SUMMARY
I ran into issues that the connection plugin was not working for out-of-the-box Red Hat servers. Red Hat has disabled the required Qemu Guest Agent commands for the libvirt connection plugin by default:
Therefor I require to pull the IP addresses for each domain and set the first IP address found as the
ansible_host
variable.I also added the
ansible_libvirt_ifaces
variable which contains all the network interfaces information of the domain. It's not necessary, but I was already working on it to getansible_host
to work anyway :) .ISSUE TYPE
COMPONENT NAME
no_connection_plugin
ADDITIONAL INFORMATION
Connection plugin:
Before:
After (set:
use_connection_plugin: False
):Filter
Before:
After (set:
filter: "test0(1|3)+"
):