From f6dac99f96cdd878f7deefa0668c584704d3dc9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Wir=C3=A9n?= Date: Thu, 14 Feb 2013 14:16:08 +0100 Subject: [PATCH 1/2] Added zfs module --- zfs | 260 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 zfs diff --git a/zfs b/zfs new file mode 100644 index 00000000000..04016773b45 --- /dev/null +++ b/zfs @@ -0,0 +1,260 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2013, Johan Wiren +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . +# + +DOCUMENTATION = ''' +--- +module: zfs +short_description: Manage zfs +description: + - Manages ZFS file systems on Solaris and FreeBSD. Can manage file systems, volumes + and snapshots. Supports the following options from zfs(1M) (See the man page for + more information): + aclinherit + aclmode + atime + canmount + casesensitivity + checksum + compression + copies + dedup + devices + exec + jailed + logbias + mountpoint + nbmand + normalization + primarycache + quota + readonly + recordsize + refquota + refreservation + reservation + secondarycache + setuid + shareiscsi + sharenfs + sharesmb + snapdir + sync + utf8only + volsize + volblocksize + vscan + xattr + zoned +options: + name: + description: + - File system, snapshot or volume name e.g. C(rpool/myfs) + required: true + state: + description: + - Whether to create (C(present)), or remove (C(absent)) a file system, snapshot or volume. + required: true + choices: [present, absent] +examples: + - code: zfs name=rpool/myfs state=present + description: Create a new file system called myfs in pool rpool + - code: zfs name=rpool/myvol state=present volsize=10M + description: Create a new volume called myvol in pool rpool. + - code: zfs name=rpool/myfs@mysnapshot state=present + description: Create a snapshot of rpool/myfs file system. + - code: zfs name=rpool/myfs2 state=present snapdir=enabled + description: Create a new file system called myfs2 whith snapdir enabled +author: Johan Wiren +''' +import os + +class Zfs(object): + def __init__(self, module, name, properties): + self.module = module + self.name = name + self.properties = properties + self.changed = False + + self.immutable_properties = [ 'casesensitivity', 'normalization', 'utf8only' ] + + def exists(self): + cmd = [self.module.get_bin_path('zfs', True)] + cmd.append('list') + cmd.append('-t all') + cmd.append(self.name) + (rc, out, err) = self.module.run_command(' '.join(cmd)) + if rc == 0: + return True + else: + return False + + def create(self): + properties=self.properties + volsize = properties.pop('volsize', None) + volblocksize = properties.pop('volblocksize', None) + if "@" in self.name: + action = 'snapshot' + else: + action = 'create' + + cmd = [self.module.get_bin_path('zfs', True)] + cmd.append(action) + if volblocksize: + cmd.append('-b %s' % volblocksize) + if properties: + for prop, value in properties.iteritems(): + cmd.append('-o %s=%s' % (prop, value)) + if volsize: + cmd.append('-V') + cmd.append(volsize) + cmd.append(self.name) + (rc, err, out) = self.module.run_command(' '.join(cmd)) + if rc == 0: + self.changed=True + else: + self.module.fail_json(msg=out) + + def destroy(self): + cmd = [self.module.get_bin_path('zfs', True)] + cmd.append('destroy') + cmd.append(self.name) + (rc, err, out) = self.module.run_command(' '.join(cmd)) + if rc == 0: + self.changed = True + else: + self.module.fail_json(msg=out) + + def set_property(self, prop, value): + cmd = [self.module.get_bin_path('zfs', True)] + cmd.append('set') + cmd.append(prop + '=' + value) + cmd.append(self.name) + (rc, err, out) = self.module.run_command(' '.join(cmd)) + if rc == 0: + self.changed = True + else: + self.module.fail_json(msg=out) + + def set_properties_if_changed(self): + current_properties = self.get_current_properties() + for prop, value in self.properties.iteritems(): + if current_properties[prop] != value: + if prop in self.immutable_properties: + self.module.fail_json(msg='Cannot change property %s after creation.' % prop) + else: + self.set_property(prop, value) + + def get_current_properties(self): + cmd = [self.module.get_bin_path('zfs', True)] + cmd.append('get -H all') + cmd.append(self.name) + rc, out, err = self.module.run_command(' '.join(cmd)) + properties=dict() + for l in out.splitlines(): + p, v = l.split()[1:3] + properties[p] = v + return properties + + def run_command(self, cmd): + progname = cmd[0] + cmd[0] = module.get_bin_path(progname, True) + return module.run_command(cmd) + +def main(): + module = AnsibleModule( + argument_spec = { + 'name': {'required': True}, + 'state': {'required': True, 'choices':['present', 'absent']}, + 'aclinherit': {'required': False, 'choices':['discard', 'noallow', 'restricted', 'passthrough', 'passthrough-x']}, + 'aclmode': {'required': False, 'choices':['discard', 'groupmask', 'passthrough']}, + 'atime': {'required': False, 'choices':['on', 'off']}, + 'canmount': {'required': False, 'choices':['on', 'off', 'noauto']}, + 'casesensitivity': {'required': False, 'choices':['sensitive', 'insensitive', 'mixed']}, + 'checksum': {'required': False, 'choices':['on', 'off', 'fletcher2', 'fletcher4', 'sha256']}, + 'compression': {'required': False, 'choices':['on', 'off', 'lzjb', 'gzip', 'gzip-1', 'gzip-2', 'gzip-3', 'gzip-4', 'gzip-5', 'gzip-6', 'gzip-7', 'gzip-8', 'gzip-9']}, + 'copies': {'required': False, 'choices':['1', '2', '3']}, + 'dedup': {'required': False, 'choices':['on', 'off']}, + 'devices': {'required': False, 'choices':['on', 'off']}, + 'exec': {'required': False, 'choices':['on', 'off']}, + # Not supported + #'groupquota': {'required': False}, + 'jailed': {'required': False, 'choices':['on', 'off']}, + 'logbias': {'required': False, 'choices':['latency', 'throughput']}, + 'mountpoint': {'required': False}, + 'nbmand': {'required': False, 'choices':['on', 'off']}, + 'normalization': {'required': False, 'choices':['none', 'formC', 'formD', 'formKC', 'formKD']}, + 'primarycache': {'required': False, 'choices':['all', 'none', 'metadata']}, + 'quota': {'required': False}, + 'readonly': {'required': False, 'choices':['on', 'off']}, + 'recordsize': {'required': False}, + 'refquota': {'required': False}, + 'refreservation': {'required': False}, + 'reservation': {'required': False}, + 'secondarycache': {'required': False, 'choices':['all', 'none', 'metadata']}, + 'setuid': {'required': False, 'choices':['on', 'off']}, + 'shareiscsi': {'required': False, 'choices':['on', 'off']}, + 'sharenfs': {'required': False}, + 'sharesmb': {'required': False}, + 'snapdir': {'required': False, 'choices':['hidden', 'visible']}, + 'sync': {'required': False, 'choices':['on', 'off']}, + # Not supported + #'userquota': {'required': False}, + 'utf8only': {'required': False, 'choices':['on', 'off']}, + 'volsize': {'required': False}, + 'volblocksize': {'required': False}, + 'vscan': {'required': False, 'choices':['on', 'off']}, + 'xattr': {'required': False, 'choices':['on', 'off']}, + 'zoned': {'required': False, 'choices':['on', 'off']}, + } + ) + state = module.params.pop('state') + name = module.params.pop('name') + # Remaining items in module.params are zfs properties + + # Remove 'null' value properties + properties = dict() + for prop, value in module.params.iteritems(): + if value: + properties[prop] = value + + result = {} + result['name'] = name + result['state'] = state + + zfs=Zfs(module, name, properties) + + if state == 'present': + if zfs.exists(): + zfs.set_properties_if_changed() + else: + zfs.create() + + elif state == 'absent': + if zfs.exists(): + zfs.destroy() + + result.update(zfs.properties) + result['changed'] = zfs.changed + module.exit_json(**result) + +# include magic from lib/ansible/module_common.py +#<> +main() From ffa5c86d736cea653292ee485dbd8c283d554759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Wir=C3=A9n?= Date: Sat, 16 Feb 2013 15:11:07 +0100 Subject: [PATCH 2/2] Updated documentation. Works with ansible-doc --- zfs | 213 ++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 173 insertions(+), 40 deletions(-) diff --git a/zfs b/zfs index 04016773b45..397e096f679 100644 --- a/zfs +++ b/zfs @@ -23,46 +23,9 @@ DOCUMENTATION = ''' --- module: zfs short_description: Manage zfs -description: - - Manages ZFS file systems on Solaris and FreeBSD. Can manage file systems, volumes - and snapshots. Supports the following options from zfs(1M) (See the man page for - more information): - aclinherit - aclmode - atime - canmount - casesensitivity - checksum - compression - copies - dedup - devices - exec - jailed - logbias - mountpoint - nbmand - normalization - primarycache - quota - readonly - recordsize - refquota - refreservation - reservation - secondarycache - setuid - shareiscsi - sharenfs - sharesmb - snapdir - sync - utf8only - volsize - volblocksize - vscan - xattr - zoned +description: > + Manages ZFS file systems on Solaris and FreeBSD. Can manage file systems, volumes + and snapshots. See zfs(1M) for more information about the properties. options: name: description: @@ -73,6 +36,176 @@ options: - Whether to create (C(present)), or remove (C(absent)) a file system, snapshot or volume. required: true choices: [present, absent] + aclinherit: + description: + - The aclinherit property. + required: False + choices: [discard,noallow,restricted,passthrough,passthrough-x] + aclmode: + description: + - The aclmode property. + required: False + choices: [discard,groupmask,passthrough] + atime: + description: + - The atime property. + required: False + choices: [on,off] + canmount: + description: + - The canmount property. + required: False + choices: [on,off,noauto] + casesensitivity: + description: + - The casesensitivity property. + required: False + choices: [sensitive,insensitive,mixed] + checksum: + description: + - The checksum property. + required: False + choices: [on,off,fletcher2,fletcher4,sha256] + compression: + description: + - The compression property. + required: False + choices: [on,off,lzjb,gzip,gzip-1,gzip-2,gzip-3,gzip-4,gzip-5,gzip-6,gzip-7,gzip-8,gzip-9] + copies: + description: + - The copies property. + required: False + choices: [1,2,3] + dedup: + description: + - The dedup property. + required: False + choices: [on,off] + devices: + description: + - The devices property. + required: False + choices: [on,off] + exec: + description: + - The exec property. + required: False + choices: [on,off] + jailed: + description: + - The jailed property. + required: False + choices: [on,off] + logbias: + description: + - The logbias property. + required: False + choices: [latency,throughput] + mountpoint: + description: + - The mountpoint property. + required: False + nbmand: + description: + - The nbmand property. + required: False + choices: [on,off] + normalization: + description: + - The normalization property. + required: False + choices: [none,formC,formD,formKC,formKD] + primarycache: + description: + - The primarycache property. + required: False + choices: [all,none,metadata] + quota: + description: + - The quota property. + required: False + readonly: + description: + - The readonly property. + required: False + choices: [on,off] + recordsize: + description: + - The recordsize property. + required: False + refquota: + description: + - The refquota property. + required: False + refreservation: + description: + - The refreservation property. + required: False + reservation: + description: + - The reservation property. + required: False + secondarycache: + description: + - The secondarycache property. + required: False + choices: [all,none,metadata] + setuid: + description: + - The setuid property. + required: False + choices: [on,off] + shareiscsi: + description: + - The shareiscsi property. + required: False + choices: [on,off] + sharenfs: + description: + - The sharenfs property. + required: False + sharesmb: + description: + - The sharesmb property. + required: False + snapdir: + description: + - The snapdir property. + required: False + choices: [hidden,visible] + sync: + description: + - The sync property. + required: False + choices: [on,off] + utf8only: + description: + - The utf8only property. + required: False + choices: [on,off] + volsize: + description: + - The volsize property. + required: False + volblocksize: + description: + - The volblocksize property. + required: False + vscan: + description: + - The vscan property. + required: False + choices: [on,off] + xattr: + description: + - The xattr property. + required: False + choices: [on,off] + zoned: + description: + - The zoned property. + required: False + choices: [on,off] examples: - code: zfs name=rpool/myfs state=present description: Create a new file system called myfs in pool rpool