mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Proxmox add storage content listing (#7725)
Add module to list content on proxmox storage We first add a method to list storage content for proxmox, then use that new methode to add an Ansible module to list content on storage attached to a proxmox node. User can also use content filtering to define what they want to list (backup, iso, images,...). This commit also include the integration and unit test for that new module. Co-authored-by: Julian Vanden Broeck <julian.vandenbroeck@dalibo.com>
This commit is contained in:
parent
3318034403
commit
4f92f39720
5 changed files with 269 additions and 0 deletions
2
.github/BOTMETA.yml
vendored
2
.github/BOTMETA.yml
vendored
|
@ -1053,6 +1053,8 @@ files:
|
|||
maintainers: Kogelvis
|
||||
$modules/proxmox_node_info.py:
|
||||
maintainers: jwbernin
|
||||
$modules/proxmox_storage_contents_info.py:
|
||||
maintainers: l00ptr
|
||||
$modules/proxmox_tasks_info:
|
||||
maintainers: paginabianca
|
||||
$modules/proxmox_template.py:
|
||||
|
|
|
@ -180,3 +180,17 @@ class ProxmoxAnsible(object):
|
|||
return self.proxmox_api.storage.get(type=type)
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Unable to retrieve storages information with type %s: %s" % (type, e))
|
||||
|
||||
def get_storage_content(self, node, storage, content=None, vmid=None):
|
||||
try:
|
||||
return (
|
||||
self.proxmox_api.nodes(node)
|
||||
.storage(storage)
|
||||
.content()
|
||||
.get(content=content, vmid=vmid)
|
||||
)
|
||||
except Exception as e:
|
||||
self.module.fail_json(
|
||||
msg="Unable to list content on %s, %s for %s and %s: %s"
|
||||
% (node, storage, content, vmid, e)
|
||||
)
|
||||
|
|
144
plugins/modules/proxmox_storage_contents_info.py
Normal file
144
plugins/modules/proxmox_storage_contents_info.py
Normal file
|
@ -0,0 +1,144 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright Julian Vanden Broeck (@l00ptr) <julian.vandenbroeck at dalibo.com>
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: proxmox_storage_contents_info
|
||||
short_description: List content from a Proxmox VE storage
|
||||
version_added: 8.2.0
|
||||
description:
|
||||
- Retrieves information about stored objects on a specific storage attached to a node.
|
||||
options:
|
||||
storage:
|
||||
description:
|
||||
- Only return content stored on that specific storage.
|
||||
aliases: ['name']
|
||||
type: str
|
||||
required: true
|
||||
node:
|
||||
description:
|
||||
- Proxmox node to which the storage is attached.
|
||||
type: str
|
||||
required: true
|
||||
content:
|
||||
description:
|
||||
- Filter on a specific content type.
|
||||
type: str
|
||||
choices: ["all", "backup", "rootdir", "images", "iso"]
|
||||
default: "all"
|
||||
vmid:
|
||||
description:
|
||||
- Filter on a specific VMID.
|
||||
type: int
|
||||
author: Julian Vanden Broeck (@l00ptr)
|
||||
extends_documentation_fragment:
|
||||
- community.general.proxmox.documentation
|
||||
- community.general.attributes
|
||||
- community.general.attributes.info_module
|
||||
"""
|
||||
|
||||
|
||||
EXAMPLES = """
|
||||
- name: List existing storages
|
||||
community.general.proxmox_storage_contents_info:
|
||||
api_host: helldorado
|
||||
api_user: root@pam
|
||||
api_password: "{{ password | default(omit) }}"
|
||||
api_token_id: "{{ token_id | default(omit) }}"
|
||||
api_token_secret: "{{ token_secret | default(omit) }}"
|
||||
storage: lvm2
|
||||
content: backup
|
||||
vmid: 130
|
||||
"""
|
||||
|
||||
|
||||
RETURN = """
|
||||
proxmox_storage_content:
|
||||
description: Content of of storage attached to a node.
|
||||
type: list
|
||||
returned: success
|
||||
elements: dict
|
||||
contains:
|
||||
content:
|
||||
description: Proxmox content of listed objects on this storage.
|
||||
type: str
|
||||
returned: success
|
||||
ctime:
|
||||
description: Creation time of the listed objects.
|
||||
type: str
|
||||
returned: success
|
||||
format:
|
||||
description: Format of the listed objects (can be V(raw), V(pbs-vm), V(iso),...).
|
||||
type: str
|
||||
returned: success
|
||||
size:
|
||||
description: Size of the listed objects.
|
||||
type: int
|
||||
returned: success
|
||||
subtype:
|
||||
description: Subtype of the listed objects (can be V(qemu) or V(lxc)).
|
||||
type: str
|
||||
returned: When storage is dedicated to backup, typically on PBS storage.
|
||||
verification:
|
||||
description: Backup verification status of the listed objects.
|
||||
type: dict
|
||||
returned: When storage is dedicated to backup, typically on PBS storage.
|
||||
sample: {
|
||||
"state": "ok",
|
||||
"upid": "UPID:backup-srv:00130F49:1A12D8375:00001CD7:657A2258:verificationjob:daily\\x3av\\x2dd0cc18c5\\x2d8707:root@pam:"
|
||||
}
|
||||
volid:
|
||||
description: Volume identifier of the listed objects.
|
||||
type: str
|
||||
returned: success
|
||||
"""
|
||||
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.proxmox import (
|
||||
ProxmoxAnsible, proxmox_auth_argument_spec)
|
||||
|
||||
|
||||
def proxmox_storage_info_argument_spec():
|
||||
return dict(
|
||||
storage=dict(type="str", required=True, aliases=["name"]),
|
||||
content=dict(type="str", required=False, default="all", choices=["all", "backup", "rootdir", "images", "iso"]),
|
||||
vmid=dict(type="int"),
|
||||
node=dict(required=True, type="str"),
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
module_args = proxmox_auth_argument_spec()
|
||||
storage_info_args = proxmox_storage_info_argument_spec()
|
||||
module_args.update(storage_info_args)
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=module_args,
|
||||
required_one_of=[("api_password", "api_token_id")],
|
||||
required_together=[("api_token_id", "api_token_secret")],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
result = dict(changed=False)
|
||||
proxmox = ProxmoxAnsible(module)
|
||||
res = proxmox.get_storage_content(
|
||||
node=module.params["node"],
|
||||
storage=module.params["storage"],
|
||||
content=None if module.params["content"] == "all" else module.params["content"],
|
||||
vmid=module.params["vmid"],
|
||||
)
|
||||
result["proxmox_storage_content"] = res
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -129,6 +129,25 @@
|
|||
- results_storage.proxmox_storages|length == 1
|
||||
- results_storage.proxmox_storages[0].storage == "{{ storage }}"
|
||||
|
||||
- name: List content on storage
|
||||
proxmox_storage_contents_info:
|
||||
api_host: "{{ api_host }}"
|
||||
api_user: "{{ user }}@{{ domain }}"
|
||||
api_password: "{{ api_password | default(omit) }}"
|
||||
api_token_id: "{{ api_token_id | default(omit) }}"
|
||||
api_token_secret: "{{ api_token_secret | default(omit) }}"
|
||||
validate_certs: "{{ validate_certs }}"
|
||||
storage: "{{ storage }}"
|
||||
node: "{{ node }}"
|
||||
content: images
|
||||
register: results_list_storage
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- results_storage is not changed
|
||||
- results_storage.proxmox_storage_content is defined
|
||||
- results_storage.proxmox_storage_content |length == 1
|
||||
|
||||
- name: VM creation
|
||||
tags: [ 'create' ]
|
||||
block:
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2023, Julian Vanden Broeck <julian.vandenbroeck at dalibo.com>
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import pytest
|
||||
|
||||
proxmoxer = pytest.importorskip("proxmoxer")
|
||||
|
||||
from ansible_collections.community.general.plugins.modules import proxmox_storage_contents_info
|
||||
from ansible_collections.community.general.tests.unit.compat.mock import patch
|
||||
from ansible_collections.community.general.tests.unit.plugins.modules.utils import (
|
||||
AnsibleExitJson,
|
||||
AnsibleFailJson,
|
||||
ModuleTestCase,
|
||||
set_module_args,
|
||||
)
|
||||
import ansible_collections.community.general.plugins.module_utils.proxmox as proxmox_utils
|
||||
|
||||
NODE1 = "pve"
|
||||
RAW_LIST_OUTPUT = [
|
||||
{
|
||||
"content": "backup",
|
||||
"ctime": 1702528474,
|
||||
"format": "pbs-vm",
|
||||
"size": 273804166061,
|
||||
"subtype": "qemu",
|
||||
"vmid": 931,
|
||||
"volid": "datastore:backup/vm/931/2023-12-14T04:34:34Z",
|
||||
},
|
||||
{
|
||||
"content": "backup",
|
||||
"ctime": 1702582560,
|
||||
"format": "pbs-vm",
|
||||
"size": 273804166059,
|
||||
"subtype": "qemu",
|
||||
"vmid": 931,
|
||||
"volid": "datastore:backup/vm/931/2023-12-14T19:36:00Z",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def get_module_args(node, storage, content="all", vmid=None):
|
||||
return {
|
||||
"api_host": "host",
|
||||
"api_user": "user",
|
||||
"api_password": "password",
|
||||
"node": node,
|
||||
"storage": storage,
|
||||
"content": content,
|
||||
"vmid": vmid,
|
||||
}
|
||||
|
||||
|
||||
class TestProxmoxStorageContentsInfo(ModuleTestCase):
|
||||
def setUp(self):
|
||||
super(TestProxmoxStorageContentsInfo, self).setUp()
|
||||
proxmox_utils.HAS_PROXMOXER = True
|
||||
self.module = proxmox_storage_contents_info
|
||||
self.connect_mock = patch(
|
||||
"ansible_collections.community.general.plugins.module_utils.proxmox.ProxmoxAnsible._connect",
|
||||
).start()
|
||||
self.connect_mock.return_value.nodes.return_value.storage.return_value.content.return_value.get.return_value = (
|
||||
RAW_LIST_OUTPUT
|
||||
)
|
||||
self.connect_mock.return_value.nodes.get.return_value = [{"node": NODE1}]
|
||||
|
||||
def tearDown(self):
|
||||
self.connect_mock.stop()
|
||||
super(TestProxmoxStorageContentsInfo, self).tearDown()
|
||||
|
||||
def test_module_fail_when_required_args_missing(self):
|
||||
with pytest.raises(AnsibleFailJson) as exc_info:
|
||||
set_module_args({})
|
||||
self.module.main()
|
||||
|
||||
def test_storage_contents_info(self):
|
||||
with pytest.raises(AnsibleExitJson) as exc_info:
|
||||
set_module_args(get_module_args(node=NODE1, storage="datastore"))
|
||||
expected_output = {}
|
||||
self.module.main()
|
||||
|
||||
result = exc_info.value.args[0]
|
||||
assert not result["changed"]
|
||||
assert result["proxmox_storage_content"] == RAW_LIST_OUTPUT
|
Loading…
Reference in a new issue