summaryrefslogtreecommitdiff
path: root/roles/storage/zfs
diff options
context:
space:
mode:
authorChristian Pointner <equinox@spreadspace.org>2024-01-11 23:31:54 +0100
committerChristian Pointner <equinox@spreadspace.org>2024-01-11 23:31:54 +0100
commitb439a44bc80cac4e8671b776406f4259e8ce06d1 (patch)
tree4c470484091578fb01bf5836c5c8df906583f452 /roles/storage/zfs
parentstorage/lvm/base: allow global volumes (diff)
make generic use of storage/zfs, storage/lvm and storage/directory possible
Diffstat (limited to 'roles/storage/zfs')
-rw-r--r--roles/storage/zfs/base/defaults/main.yml30
-rw-r--r--roles/storage/zfs/base/filter_plugins/zfs.py43
-rw-r--r--roles/storage/zfs/base/tasks/main.yml9
-rw-r--r--roles/storage/zfs/volume/defaults/main.yml5
-rw-r--r--roles/storage/zfs/volume/tasks/main.yml46
5 files changed, 111 insertions, 22 deletions
diff --git a/roles/storage/zfs/base/defaults/main.yml b/roles/storage/zfs/base/defaults/main.yml
index 1566890d..df56f0c8 100644
--- a/roles/storage/zfs/base/defaults/main.yml
+++ b/roles/storage/zfs/base/defaults/main.yml
@@ -17,3 +17,33 @@ zfs_pool_default_properties:
# properties:
# ashift: 12
# prop: value
+
+zfs_volumes: {}
+
+# zfs_volumes:
+# storage:
+# test:
+# properties:
+# quota: 1G
+# bar:
+# properties:
+# quota: 4G
+# children:
+# blub:
+# properties:
+# quota: 3G
+# xattr: sa
+# acltype: posix
+# hugo:
+# properties:
+# mountpoint: /var/lib/hugo
+# quota: 2G
+# children:
+# ben: {}
+# after:
+# properties:
+# quota: 100M
+# test:
+# sub1:
+# properties:
+# quota: 512M
diff --git a/roles/storage/zfs/base/filter_plugins/zfs.py b/roles/storage/zfs/base/filter_plugins/zfs.py
new file mode 100644
index 00000000..a336c197
--- /dev/null
+++ b/roles/storage/zfs/base/filter_plugins/zfs.py
@@ -0,0 +1,43 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from functools import partial
+from copy import deepcopy
+
+from ansible import errors
+
+
+def _recurse_pool_volumes(pool, prefix, volumes):
+ result = []
+ if prefix != '':
+ prefix = prefix + '/'
+ for name, volume in volumes.items():
+ entry = deepcopy(volume)
+ entry.pop('children', None)
+ entry['pool'] = pool
+ entry['name'] = prefix+name
+ result.append(entry)
+ if 'children' in volume:
+ result = result + _recurse_pool_volumes(pool, entry['name'], volume['children'])
+
+ return result
+
+
+def zfs_volume_list(data):
+ try:
+ result = []
+ for pool, volumes in data.items():
+ result = result + _recurse_pool_volumes(pool, '', volumes)
+ return result
+ except Exception as e:
+ raise errors.AnsibleFilterError("zfs_volume_list(): %s" % str(e))
+
+
+class FilterModule(object):
+
+ filter_map = {
+ 'zfs_volume_list': zfs_volume_list,
+ }
+
+ def filters(self):
+ return self.filter_map
diff --git a/roles/storage/zfs/base/tasks/main.yml b/roles/storage/zfs/base/tasks/main.yml
index 99b8e228..b731bb1f 100644
--- a/roles/storage/zfs/base/tasks/main.yml
+++ b/roles/storage/zfs/base/tasks/main.yml
@@ -59,3 +59,12 @@
label: "{{ item.key }}"
when: item.key not in zfs_existing_pools
command: "zpool create -m {{ item.value.mountpoint }} {% for prop, value in (item.value.properties | default(zfs_pool_default_properties)).items() %}-o {{ prop }}={{ value }} {% endfor %}{{ item.key }} {{ item.value.create_vdevs }}"
+
+- name: create zfs volumes
+ loop: "{{ zfs_volumes | zfs_volume_list }}"
+ loop_control:
+ label: "{{ item.pool }}/{{ item.name }}"
+ vars:
+ zfs_volume: "{{ item }}"
+ include_role:
+ name: storage/zfs/volume
diff --git a/roles/storage/zfs/volume/defaults/main.yml b/roles/storage/zfs/volume/defaults/main.yml
index bb1c0c6d..8b799655 100644
--- a/roles/storage/zfs/volume/defaults/main.yml
+++ b/roles/storage/zfs/volume/defaults/main.yml
@@ -1,13 +1,12 @@
---
# zfs_volume:
# parent:
-# type: zfs
# ...
# pool: tank
-# name: foo/bar
+# name: bar
# properties:
# quota: 10G
-# dest: /srv/foo/bar
+# dest: /srv/bar
# mode: 0750
# owner: root
# group: users
diff --git a/roles/storage/zfs/volume/tasks/main.yml b/roles/storage/zfs/volume/tasks/main.yml
index 260d706d..07a70dfc 100644
--- a/roles/storage/zfs/volume/tasks/main.yml
+++ b/roles/storage/zfs/volume/tasks/main.yml
@@ -1,37 +1,45 @@
---
-- name: check volume parent
- when: "'parent' in zfs_volume"
- assert:
- msg: "the volume parent must be of type zfs and must not have a parent"
- that:
- - zfs_volume.parent.type == 'zfs'
- - "'parent' not in zfs_volume.parent"
+- name: compute full zfs volume path
+ set_fact:
+ zfs_volume_path_full: "{{ ('parent' in zfs_volume) | ternary((zfs_volume.parent.pool | default(''))~'/'~(zfs_volume.parent.name | default('')), zfs_volume.pool) }}/{{ zfs_volume.name }}"
- name: create zfs dataset
zfs:
- name: "{{ ('parent' in zfs_volume) | ternary((zfs_volume.parent.pool | default(''))~'/'~(zfs_volume.parent.name | default('')), zfs_volume.pool) }}/{{ zfs_volume.name }}"
+ name: "{{ zfs_volume_path_full }}"
extra_zfs_properties: "{{ zfs_volume.properties | dehumanize_zfs_properties | default(omit) }}"
state: present
-- name: compute derivated mountpoint
+- name: gather volume mountpoint info
+ zfs_facts:
+ name: "{{ zfs_volume_path_full }}"
+ properties: mountpoint
+ register: zfs_volume_info
+
+- name: export volume mountpoint
set_fact:
- zfs_volume_mountpoint: "{{ (zfs_pools[zfs_volume.parent.pool | default(zfs_volume.pool)].mountpoint, ('parent' in zfs_volume) | ternary((zfs_volume.parent.name | default('')), ''), zfs_volume.name) | path_join }}"
+ storage_volume_mountpoint: "{{ zfs_volume_info.ansible_facts.ansible_zfs_datasets[0].mountpoint }}"
-- name: bind mount filesystem
+- name: bind mount volume
when:
- "'dest' in zfs_volume"
- - zfs_volume.dest != zfs_volume_mountpoint
- mount:
- src: "{{ zfs_volume_mountpoint }}"
- path: "{{ zfs_volume.dest }}"
- fstype: none
- opts: bind,x-systemd.automount,nofail
- state: mounted
+ - zfs_volume.dest != storage_volume_mountpoint
+ block:
+ - name: create bind mount
+ mount:
+ src: "{{ zfs_volume_info.ansible_facts.ansible_zfs_datasets[0].mountpoint }}"
+ path: "{{ zfs_volume.dest }}"
+ fstype: none
+ opts: bind,x-systemd.automount,nofail
+ state: mounted
+
+ - name: update volume mountpoint
+ set_fact:
+ storage_volume_mountpoint: "{{ zfs_volume.dest }}"
- name: set volume owner/group and mode
file:
state: directory
- path: "{{ zfs_volume.dest | default(zfs_volume_mountpoint) }}"
+ path: "{{ storage_volume_mountpoint }}"
mode: "{{ zfs_volume.mode | default(omit) }}"
owner: "{{ zfs_volume.owner | default(omit) }}"
group: "{{ zfs_volume.group | default(omit) }}"