Repository: ansible-collections/community.general

Issue:
proxmox inventory: collect also guest agent network informations
### Summary

Current inventory with `want_facts: yes`  looks like this

```
        "hostvars": {
            "adguard": {
                "proxmox_agent": "1",
                "proxmox_balloon": 512,
                "proxmox_boot": "order=scsi0;ide2;net0",
                "proxmox_cores": 1,
                "proxmox_description": "10.85.100.100",
                "proxmox_digest": "2ad048ab859879caa42c894ea6fe68fdef835deb",
                "proxmox_ide2": {
                    "disk_image": "local:iso/ubuntu-20.04.2-live-server-amd64.iso",
                    "media": "cdrom"
                },
                "proxmox_memory": 1024,
                "proxmox_name": "adguard",
                "proxmox_net0": {
                    "bridge": "vmbr0",
                    "firewall": "1",
                    "virtio": "8E:ED:82:8E:3B:CB"
                },
                "proxmox_numa": 0,
                "proxmox_onboot": 1,
                "proxmox_ostype": "l26",
                "proxmox_protection": 1,
                "proxmox_scsi0": {
                    "disk_image": "local:104/vm-104-disk-0.qcow2",
                    "size": "8G"
                },
                "proxmox_scsihw": "disk_image=virtio-scsi-pci",
                "proxmox_smbios1": "uuid=6bebd2cb-3901-405d-9603-e22489f2259e",
                "proxmox_sockets": 1,
                "proxmox_status": "running",
                "proxmox_vmgenid": "a1aa0141-4cfa-4ba3-8533-6a6a74263ebf",
                "proxmox_vmid": "104",
                "proxmox_vmtype": "qemu"
            },
```

What is missing are the network informations that exists when the qemu guest agent is installed

![image](https://gist.githubusercontent.com/markuman/d431314ff904738ccc1f33df432950e2/raw/9a338ef67a8c5195577cdba17d5b55a76cd7bfb5/image.png)



### Issue Type

Feature Idea

### Component Name

community.general.proxmox

### Additional Information

_No response_

### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct


Discussion:
Files identified in the description:
None

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
Nice idea!
!component =plugins/inventory/proxmox.py
Files identified in the description:
* [`plugins/inventory/proxmox.py`](https://github.com/ansible-collections/community.general/blob/master/plugins/inventory/proxmox.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->

Resolving patch:
diff --git a/plugins/inventory/proxmox.py b/plugins/inventory/proxmox.py
--- a/plugins/inventory/proxmox.py
+++ b/plugins/inventory/proxmox.py
@@ -206,6 +206,29 @@ def _get_node_ip(self, node):
             except Exception:
                 return None
 
+    def _get_agent_network_interfaces(self, node, vmid, vmtype):
+        result = []
+
+        try:
+            ifaces = self._get_json(
+                "%s/api2/json/nodes/%s/%s/%s/agent/network-get-interfaces" % (
+                    self.proxmox_url, node, vmtype, vmid
+                )
+            )['result']
+
+            for iface in ifaces:
+                result.append({
+                    'name': iface['name'],
+                    'mac-address': iface['hardware-address'],
+                    'ip-addresses': [
+                        "%s/%s" % (ip['ip-address'], ip['prefix']) for ip in iface['ip-addresses']
+                    ]
+                })
+        except requests.HTTPError:
+            pass
+
+        return result
+
     def _get_vm_config(self, node, vmid, vmtype, name):
         ret = self._get_json("%s/api2/json/nodes/%s/%s/%s/config" % (self.proxmox_url, node, vmtype, vmid))
 
@@ -236,6 +259,12 @@ def _get_vm_config(self, node, vmid, vmtype, name):
                     parsed_value = [tag.strip() for tag in value.split(",")]
                     self.inventory.set_variable(name, parsed_key, parsed_value)
 
+                if config == 'agent' and int(value):
+                    agent_iface_key = self.to_safe('%s%s' % (key, "_interfaces"))
+                    agent_iface_value = self._get_agent_network_interfaces(node, vmid, vmtype)
+                    if agent_iface_value:
+                        self.inventory.set_variable(name, agent_iface_key, agent_iface_value)
+
                 if not (isinstance(value, int) or ',' not in value):
                     # split off strings with commas to a dict
                     # skip over any keys that cannot be processed


Test patch:
diff --git a/tests/unit/plugins/inventory/test_proxmox.py b/tests/unit/plugins/inventory/test_proxmox.py
--- a/tests/unit/plugins/inventory/test_proxmox.py
+++ b/tests/unit/plugins/inventory/test_proxmox.py
@@ -71,8 +71,7 @@ def get_json(url):
                  "status": "running",
                  "vmid": "100",
                  "disk": "1000",
-                 "uptime": 1000,
-                 "tags": "test, tags, here"}]
+                 "uptime": 1000}]
     elif url == "https://localhost:8006/api2/json/nodes/testnode/qemu":
         # _get_qemu_per_node
         return [{"name": "test-qemu",
@@ -106,8 +105,7 @@ def get_json(url):
                  "vmid": "9001",
                  "uptime": 0,
                  "disk": 0,
-                 "status": "stopped",
-                 "tags": "test, tags, here"}]
+                 "status": "stopped"}]
     elif url == "https://localhost:8006/api2/json/pools/test":
         # _get_members_per_pool
         return {"members": [{"uptime": 1000,
@@ -164,6 +162,125 @@ def get_json(url):
                  "method6": "manual",
                  "autostart": 1,
                  "active": 1}]
+    elif url == "https://localhost:8006/api2/json/nodes/testnode/lxc/100/config":
+        # _get_vm_config (lxc)
+        return {
+            "console": 1,
+            "rootfs": "local-lvm:vm-100-disk-0,size=4G",
+            "cmode": "tty",
+            "description": "A testnode",
+            "cores": 1,
+            "hostname": "test-lxc",
+            "arch": "amd64",
+            "tty": 2,
+            "swap": 0,
+            "cpulimit": "0",
+            "net0": "name=eth0,bridge=vmbr0,gw=10.1.1.1,hwaddr=FF:FF:FF:FF:FF:FF,ip=10.1.1.3/24,type=veth",
+            "ostype": "ubuntu",
+            "digest": "123456789abcdef0123456789abcdef01234567890",
+            "protection": 0,
+            "memory": 1000,
+            "onboot": 0,
+            "cpuunits": 1024,
+            "tags": "one, two, three",
+        }
+    elif url == "https://localhost:8006/api2/json/nodes/testnode/qemu/101/config":
+        # _get_vm_config (qemu)
+        return {
+            "tags": "one, two, three",
+            "cores": 1,
+            "ide2": "none,media=cdrom",
+            "memory": 1000,
+            "kvm": 1,
+            "digest": "0123456789abcdef0123456789abcdef0123456789",
+            "description": "A test qemu",
+            "sockets": 1,
+            "onboot": 1,
+            "vmgenid": "ffffffff-ffff-ffff-ffff-ffffffffffff",
+            "numa": 0,
+            "bootdisk": "scsi0",
+            "cpu": "host",
+            "name": "test-qemu",
+            "ostype": "l26",
+            "hotplug": "network,disk,usb",
+            "scsi0": "local-lvm:vm-101-disk-0,size=8G",
+            "net0": "virtio=ff:ff:ff:ff:ff:ff,bridge=vmbr0,firewall=1",
+            "agent": "1",
+            "bios": "seabios",
+            "ide0": "local-lvm:vm-101-cloudinit,media=cdrom,size=4M",
+            "boot": "cdn",
+            "scsihw": "virtio-scsi-pci",
+            "smbios1": "uuid=ffffffff-ffff-ffff-ffff-ffffffffffff"
+        }
+    elif url == "https://localhost:8006/api2/json/nodes/testnode/qemu/101/agent/network-get-interfaces":
+        # _get_agent_network_interfaces
+        return {"result": [
+            {
+                "hardware-address": "00:00:00:00:00:00",
+                "ip-addresses": [
+                    {
+                        "prefix": 8,
+                        "ip-address-type": "ipv4",
+                        "ip-address": "127.0.0.1"
+                    },
+                    {
+                        "ip-address-type": "ipv6",
+                        "ip-address": "::1",
+                        "prefix": 128
+                    }],
+                "statistics": {
+                    "rx-errs": 0,
+                    "rx-bytes": 163244,
+                    "rx-packets": 1623,
+                    "rx-dropped": 0,
+                    "tx-dropped": 0,
+                    "tx-packets": 1623,
+                    "tx-bytes": 163244,
+                    "tx-errs": 0},
+                "name": "lo"},
+            {
+                "statistics": {
+                    "rx-packets": 4025,
+                    "rx-dropped": 12,
+                    "rx-bytes": 324105,
+                    "rx-errs": 0,
+                    "tx-errs": 0,
+                    "tx-bytes": 368860,
+                    "tx-packets": 3479,
+                    "tx-dropped": 0},
+                "name": "eth0",
+                "ip-addresses": [
+                    {
+                        "prefix": 24,
+                        "ip-address-type": "ipv4",
+                        "ip-address": "10.1.2.3"
+                    },
+                    {
+                        "prefix": 64,
+                        "ip-address": "fd8c:4687:e88d:1be3:5b70:7b88:c79c:293",
+                        "ip-address-type": "ipv6"
+                    }],
+                "hardware-address": "ff:ff:ff:ff:ff:ff"
+            },
+            {
+                "hardware-address": "ff:ff:ff:ff:ff:ff",
+                "ip-addresses": [
+                    {
+                        "prefix": 16,
+                        "ip-address": "10.10.2.3",
+                        "ip-address-type": "ipv4"
+                    }],
+                "name": "docker0",
+                "statistics": {
+                    "rx-bytes": 0,
+                    "rx-errs": 0,
+                    "rx-dropped": 0,
+                    "rx-packets": 0,
+                    "tx-packets": 0,
+                    "tx-dropped": 0,
+                    "tx-errs": 0,
+                    "tx-bytes": 0
+                }}]}
 
 
 def get_vm_status(node, vmtype, vmid, name):
@@ -173,6 +290,10 @@ def get_vm_status(node, vmtype, vmid, name):
 def get_option(option):
     if option == 'group_prefix':
         return 'proxmox_'
+    if option == 'facts_prefix':
+        return 'proxmox_'
+    elif option == 'want_facts':
+        return True
     else:
         return False
 
@@ -201,6 +322,9 @@ def test_populate(inventory, mocker):
     group_qemu = inventory.inventory.groups['proxmox_pool_test']
     assert group_qemu.hosts == [host_qemu]
 
+    # check if qemu-test has eth0 interface in agent_interfaces fact
+    assert 'eth0' in [d['name'] for d in host_qemu.get_vars()['proxmox_agent_interfaces']]
+
     # check if lxc-test has been discovered correctly
     group_lxc = inventory.inventory.groups['proxmox_all_lxc']
     assert group_lxc.hosts == [host_lxc]