community.general/plugins/modules/zfs_facts.py
Felix Fontein e8f965fbf8
Adjust YAML in module docs (#10240)
* Adjust YAML in module docs.

* adjust modules

---------

Co-authored-by: Alexei Znamensky <russoz@gmail.com>
2025-06-16 17:45:12 +02:00

255 lines
7 KiB
Python

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2016, Adam Števko <adam.stevko@gmail.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 = r"""
module: zfs_facts
short_description: Gather facts about ZFS datasets
description:
- Gather facts from ZFS dataset properties.
author: Adam Števko (@xen0l)
extends_documentation_fragment:
- community.general.attributes
- community.general.attributes.facts
- community.general.attributes.facts_module
options:
name:
description:
- ZFS dataset name.
required: true
aliases: ["ds", "dataset"]
type: str
recurse:
description:
- Specifies if properties for any children should be recursively displayed.
type: bool
default: false
parsable:
description:
- Specifies if property values should be displayed in machine friendly format.
type: bool
default: false
properties:
description:
- Specifies which dataset properties should be queried in comma-separated format. For more information about dataset
properties, check zfs(1M) man page.
default: all
type: str
type:
description:
- Specifies which datasets types to display. Multiple values have to be provided as a list or in comma-separated form.
- Value V(all) cannot be used together with other values.
choices: ['all', 'filesystem', 'volume', 'snapshot', 'bookmark']
default: [all]
type: list
elements: str
depth:
description:
- Specifies recursion depth.
type: int
default: 0
"""
EXAMPLES = r"""
- name: Gather facts about ZFS dataset rpool/export/home
community.general.zfs_facts:
dataset: rpool/export/home
- name: Report space usage on ZFS filesystems under data/home
community.general.zfs_facts:
name: data/home
recurse: true
type: filesystem
- ansible.builtin.debug:
msg: 'ZFS dataset {{ item.name }} consumes {{ item.used }} of disk space.'
with_items: '{{ ansible_zfs_datasets }}'
"""
RETURN = r"""
name:
description: ZFS dataset name.
returned: always
type: str
sample: rpool/var/spool
parsable:
description: If parsable output should be provided in machine friendly format.
returned: if O(parsable=True)
type: bool
sample: true
recurse:
description: If we should recurse over ZFS dataset.
returned: if O(recurse=True)
type: bool
sample: true
zfs_datasets:
description: ZFS dataset facts.
returned: always
type: str
sample:
"aclinherit": "restricted"
"aclmode": "discard"
"atime": "on"
"available": "43.8G"
"canmount": "on"
"casesensitivity": "sensitive"
"checksum": "on"
"compression": "off"
"compressratio": "1.00x"
"copies": "1"
"creation": "Thu Jun 16 11:37 2016"
"dedup": "off"
"devices": "on"
"exec": "on"
"filesystem_count": "none"
"filesystem_limit": "none"
"logbias": "latency"
"logicalreferenced": "18.5K"
"logicalused": "3.45G"
"mlslabel": "none"
"mounted": "yes"
"mountpoint": "/rpool"
"name": "rpool"
"nbmand": "off"
"normalization": "none"
"org.openindiana.caiman:install": "ready"
"primarycache": "all"
"quota": "none"
"readonly": "off"
"recordsize": "128K"
"redundant_metadata": "all"
"refcompressratio": "1.00x"
"referenced": "29.5K"
"refquota": "none"
"refreservation": "none"
"reservation": "none"
"secondarycache": "all"
"setuid": "on"
"sharenfs": "off"
"sharesmb": "off"
"snapdir": "hidden"
"snapshot_count": "none"
"snapshot_limit": "none"
"sync": "standard"
"type": "filesystem"
"used": "4.41G"
"usedbychildren": "4.41G"
"usedbydataset": "29.5K"
"usedbyrefreservation": "0"
"usedbysnapshots": "0"
"utf8only": "off"
"version": "5"
"vscan": "off"
"written": "29.5K"
"xattr": "on"
"zoned": "off"
"""
from collections import defaultdict
from ansible.module_utils.basic import AnsibleModule
SUPPORTED_TYPES = ['all', 'filesystem', 'volume', 'snapshot', 'bookmark']
class ZFSFacts(object):
def __init__(self, module):
self.module = module
self.name = module.params['name']
self.recurse = module.params['recurse']
self.parsable = module.params['parsable']
self.properties = module.params['properties']
self.type = module.params['type']
self.depth = module.params['depth']
self._datasets = defaultdict(dict)
self.facts = []
def dataset_exists(self):
cmd = [self.module.get_bin_path('zfs'), 'list', self.name]
(rc, out, err) = self.module.run_command(cmd)
return rc == 0
def get_facts(self):
cmd = [self.module.get_bin_path('zfs'), 'get', '-H']
if self.parsable:
cmd.append('-p')
if self.recurse:
cmd.append('-r')
if int(self.depth) != 0:
cmd.append('-d')
cmd.append('%s' % self.depth)
if self.type:
cmd.append('-t')
cmd.append(','.join(self.type))
cmd.extend(['-o', 'name,property,value', self.properties, self.name])
(rc, out, err) = self.module.run_command(cmd)
if rc != 0:
self.module.fail_json(msg='Error while trying to get facts about ZFS dataset: %s' % self.name,
stderr=err,
rc=rc)
for line in out.splitlines():
dataset, property, value = line.split('\t')
self._datasets[dataset].update({property: value})
for k, v in self._datasets.items():
v.update({'name': k})
self.facts.append(v)
return {'ansible_zfs_datasets': self.facts}
def main():
module = AnsibleModule(
argument_spec=dict(
name=dict(required=True, aliases=['ds', 'dataset'], type='str'),
recurse=dict(default=False, type='bool'),
parsable=dict(default=False, type='bool'),
properties=dict(default='all', type='str'),
type=dict(default='all', type='list', elements='str', choices=SUPPORTED_TYPES),
depth=dict(default=0, type='int')
),
supports_check_mode=True
)
if 'all' in module.params['type'] and len(module.params['type']) > 1:
module.fail_json(msg="Value 'all' for parameter 'type' is mutually exclusive with other values")
zfs_facts = ZFSFacts(module)
result = {}
result['changed'] = False
result['name'] = zfs_facts.name
if zfs_facts.parsable:
result['parsable'] = zfs_facts.parsable
if zfs_facts.recurse:
result['recurse'] = zfs_facts.recurse
if not zfs_facts.dataset_exists():
module.fail_json(msg='ZFS dataset %s does not exist!' % zfs_facts.name)
result['ansible_facts'] = zfs_facts.get_facts()
module.exit_json(**result)
if __name__ == '__main__':
main()