1022 lines
35 KiB
Diff
1022 lines
35 KiB
Diff
|
diff --git a/README.md b/README.md
|
||
|
index c2debc9..f808adc 100644
|
||
|
--- a/README.md
|
||
|
+++ b/README.md
|
||
|
@@ -73,6 +73,9 @@ The `mount_point` specifies the directory on which the file system will be mount
|
||
|
##### `mount_options`
|
||
|
The `mount_options` specifies custom mount options as a string, e.g.: 'ro'.
|
||
|
|
||
|
+#### `storage_safe_mode`
|
||
|
+When true (the default), an error will occur instead of automatically removing existing devices and/or formatting.
|
||
|
+
|
||
|
|
||
|
Example Playbook
|
||
|
----------------
|
||
|
diff --git a/defaults/main.yml b/defaults/main.yml
|
||
|
index 7b500e5..476616b 100644
|
||
|
--- a/defaults/main.yml
|
||
|
+++ b/defaults/main.yml
|
||
|
@@ -3,6 +3,7 @@
|
||
|
storage_provider: "blivet"
|
||
|
storage_use_partitions: null
|
||
|
storage_disklabel_type: null # leave unset to allow the role to select an appropriate label type
|
||
|
+storage_safe_mode: true # fail instead of implicitly/automatically removing devices or formatting
|
||
|
|
||
|
storage_pool_defaults:
|
||
|
state: "present"
|
||
|
diff --git a/library/blivet.py b/library/blivet.py
|
||
|
index d416944..1d8cd36 100644
|
||
|
--- a/library/blivet.py
|
||
|
+++ b/library/blivet.py
|
||
|
@@ -31,6 +31,9 @@ options:
|
||
|
disklabel_type:
|
||
|
description:
|
||
|
- disklabel type string (eg: 'gpt') to use, overriding the built-in logic in blivet
|
||
|
+ safe_mode:
|
||
|
+ description:
|
||
|
+ - boolean indicating that we should fail rather than implicitly/automatically removing devices or formatting
|
||
|
|
||
|
author:
|
||
|
- David Lehman (dlehman@redhat.com)
|
||
|
@@ -112,13 +115,15 @@ if BLIVET_PACKAGE:
|
||
|
|
||
|
use_partitions = None # create partitions on pool backing device disks?
|
||
|
disklabel_type = None # user-specified disklabel type
|
||
|
+safe_mode = None # do not remove any existing devices or formatting
|
||
|
+packages_only = None # only set things up enough to get a list of required packages
|
||
|
|
||
|
|
||
|
class BlivetAnsibleError(Exception):
|
||
|
pass
|
||
|
|
||
|
|
||
|
-class BlivetVolume:
|
||
|
+class BlivetVolume(object):
|
||
|
def __init__(self, blivet_obj, volume, bpool=None):
|
||
|
self._blivet = blivet_obj
|
||
|
self._volume = volume
|
||
|
@@ -206,11 +211,16 @@ class BlivetVolume:
|
||
|
|
||
|
def _reformat(self):
|
||
|
""" Schedule actions as needed to ensure the volume is formatted as specified. """
|
||
|
+ global packages_only
|
||
|
+
|
||
|
fmt = self._get_format()
|
||
|
if self._device.format.type == fmt.type:
|
||
|
return
|
||
|
|
||
|
- if self._device.format.status:
|
||
|
+ if safe_mode and (self._device.format.type is not None or self._device.format.name != get_format(None).name):
|
||
|
+ raise BlivetAnsibleError("cannot remove existing formatting on volume '%s' in safe mode" % self._volume['name'])
|
||
|
+
|
||
|
+ if self._device.format.status and not packages_only:
|
||
|
self._device.format.teardown()
|
||
|
self._blivet.format_device(self._device, fmt)
|
||
|
|
||
|
@@ -251,6 +261,19 @@ class BlivetDiskVolume(BlivetVolume):
|
||
|
def _type_check(self):
|
||
|
return self._device.is_disk
|
||
|
|
||
|
+ def _look_up_device(self):
|
||
|
+ super(BlivetDiskVolume, self)._look_up_device()
|
||
|
+ if not self._get_device_id():
|
||
|
+ # FAIL: no disks specified for volume
|
||
|
+ raise BlivetAnsibleError("no disks specified for volume '%s'" % self._volume['name']) # sure about this one?
|
||
|
+ elif not isinstance(self._volume['disks'], list):
|
||
|
+ raise BlivetAnsibleError("volume disks must be specified as a list")
|
||
|
+
|
||
|
+ if self._device is None:
|
||
|
+ # FAIL: failed to find the disk
|
||
|
+ raise BlivetAnsibleError("unable to resolve disk specified for volume '%s' (%s)" % (self._volume['name'], self._volume['disks']))
|
||
|
+
|
||
|
+
|
||
|
|
||
|
class BlivetPartitionVolume(BlivetVolume):
|
||
|
def _type_check(self):
|
||
|
@@ -342,7 +365,7 @@ def _get_blivet_volume(blivet_obj, volume, bpool=None):
|
||
|
return _BLIVET_VOLUME_TYPES[volume_type](blivet_obj, volume, bpool=bpool)
|
||
|
|
||
|
|
||
|
-class BlivetPool:
|
||
|
+class BlivetPool(object):
|
||
|
def __init__(self, blivet_obj, pool):
|
||
|
self._blivet = blivet_obj
|
||
|
self._pool = pool
|
||
|
@@ -424,8 +447,11 @@ class BlivetPool:
|
||
|
""" Schedule actions as needed to ensure pool member devices exist. """
|
||
|
members = list()
|
||
|
for disk in self._disks:
|
||
|
- if not disk.isleaf:
|
||
|
- self._blivet.devicetree.recursive_remove(disk)
|
||
|
+ if not disk.isleaf or disk.format.type is not None:
|
||
|
+ if not safe_mode:
|
||
|
+ self._blivet.devicetree.recursive_remove(disk)
|
||
|
+ else:
|
||
|
+ raise BlivetAnsibleError("cannot remove existing formatting and/or devices on disk '%s' (pool '%s') in safe mode" % (disk.name, self._pool['name']))
|
||
|
|
||
|
if use_partitions:
|
||
|
label = get_format("disklabel", device=disk.path)
|
||
|
@@ -486,7 +512,10 @@ class BlivetPartitionPool(BlivetPool):
|
||
|
def _create(self):
|
||
|
if self._device.format.type != "disklabel" or \
|
||
|
self._device.format.label_type != disklabel_type:
|
||
|
- self._blivet.devicetree.recursive_remove(self._device, remove_device=False)
|
||
|
+ if not safe_mode:
|
||
|
+ self._blivet.devicetree.recursive_remove(self._device, remove_device=False)
|
||
|
+ else:
|
||
|
+ raise BlivetAnsibleError("cannot remove existing formatting and/or devices on disk '%s' (pool '%s') in safe mode" % (self._device.name, self._pool['name']))
|
||
|
|
||
|
label = get_format("disklabel", device=self._device.path, label_type=disklabel_type)
|
||
|
self._blivet.format_device(self._device, label)
|
||
|
@@ -520,7 +549,7 @@ class BlivetLVMPool(BlivetPool):
|
||
|
|
||
|
|
||
|
_BLIVET_POOL_TYPES = {
|
||
|
- "disk": BlivetPartitionPool,
|
||
|
+ "partition": BlivetPartitionPool,
|
||
|
"lvm": BlivetLVMPool
|
||
|
}
|
||
|
|
||
|
@@ -550,7 +579,7 @@ def manage_pool(b, pool):
|
||
|
volume['_mount_id'] = bvolume._volume.get('_mount_id', '')
|
||
|
|
||
|
|
||
|
-class FSTab:
|
||
|
+class FSTab(object):
|
||
|
def __init__(self, blivet_obj):
|
||
|
self._blivet = blivet_obj
|
||
|
self._entries = list()
|
||
|
@@ -656,6 +685,7 @@ def run_module():
|
||
|
volumes=dict(type='list'),
|
||
|
packages_only=dict(type='bool', required=False, default=False),
|
||
|
disklabel_type=dict(type='str', required=False, default=None),
|
||
|
+ safe_mode=dict(type='bool', required=False, default=False),
|
||
|
use_partitions=dict(type='bool', required=False, default=True))
|
||
|
|
||
|
# seed the result dict in the object
|
||
|
@@ -684,6 +714,12 @@ def run_module():
|
||
|
global use_partitions
|
||
|
use_partitions = module.params['use_partitions']
|
||
|
|
||
|
+ global safe_mode
|
||
|
+ safe_mode = module.params['safe_mode']
|
||
|
+
|
||
|
+ global packages_only
|
||
|
+ packages_only = module.params['packages_only']
|
||
|
+
|
||
|
b = Blivet()
|
||
|
b.reset()
|
||
|
fstab = FSTab(b)
|
||
|
diff --git a/tasks/main-blivet.yml b/tasks/main-blivet.yml
|
||
|
index 061195c..65b8580 100644
|
||
|
--- a/tasks/main-blivet.yml
|
||
|
+++ b/tasks/main-blivet.yml
|
||
|
@@ -38,7 +38,7 @@
|
||
|
_storage_vols_no_defaults: "{{ _storage_vols_no_defaults|default([]) }} + [{{ item.1 }}]"
|
||
|
_storage_vol_defaults: "{{ _storage_vol_defaults|default([]) }} + [{{ storage_volume_defaults }}]"
|
||
|
_storage_vol_pools: "{{ _storage_vol_pools|default([]) }} + ['{{ item.0.name }}']"
|
||
|
- loop: "{{ _storage_pools|subelements('volumes') }}"
|
||
|
+ loop: "{{ _storage_pools|subelements('volumes', skip_missing=true) }}"
|
||
|
when: storage_pools is defined
|
||
|
|
||
|
- name: Apply defaults to pools and volumes [3/6]
|
||
|
@@ -85,6 +85,15 @@
|
||
|
- debug:
|
||
|
var: _storage_volumes
|
||
|
|
||
|
+- name: load mount facts
|
||
|
+ setup:
|
||
|
+ gather_subset: '!all,!min,mounts'
|
||
|
+ register: __storage_mounts_before_packages
|
||
|
+
|
||
|
+# - name: show mounts before get required packages
|
||
|
+# debug:
|
||
|
+# var: __storage_mounts_before_packages
|
||
|
+
|
||
|
- name: get required packages
|
||
|
blivet:
|
||
|
pools: "{{ _storage_pools }}"
|
||
|
@@ -94,6 +103,30 @@
|
||
|
packages_only: true
|
||
|
register: package_info
|
||
|
|
||
|
+- name: load mount facts
|
||
|
+ setup:
|
||
|
+ gather_subset: '!all,!min,mounts'
|
||
|
+ register: __storage_mounts_after_packages
|
||
|
+
|
||
|
+- name: detect mount alteration by 'get required packages'
|
||
|
+ block:
|
||
|
+ - name: show mounts before manage the pools and volumes
|
||
|
+ debug:
|
||
|
+ var: __storage_mounts_before_packages.ansible_facts.ansible_mounts
|
||
|
+
|
||
|
+ - name: show mounts after manage the pools and volumes
|
||
|
+ debug:
|
||
|
+ var: __storage_mounts_after_packages.ansible_facts.ansible_mounts
|
||
|
+
|
||
|
+ - name: fail if mounts changed
|
||
|
+ fail:
|
||
|
+ msg: "get required packages changed mounts. Changed status is
|
||
|
+ {{ package_info.changed }}"
|
||
|
+ when:
|
||
|
+ - __storage_mounts_before_packages.ansible_facts.ansible_mounts |
|
||
|
+ count !=
|
||
|
+ __storage_mounts_after_packages.ansible_facts.ansible_mounts | count
|
||
|
+
|
||
|
- name: make sure required packages are installed
|
||
|
package:
|
||
|
name: "{{ package_info.packages }}"
|
||
|
@@ -105,6 +138,7 @@
|
||
|
volumes: "{{ _storage_volumes }}"
|
||
|
use_partitions: "{{ storage_use_partitions }}"
|
||
|
disklabel_type: "{{ storage_disklabel_type }}"
|
||
|
+ safe_mode: "{{ storage_safe_mode }}"
|
||
|
register: blivet_output
|
||
|
|
||
|
- debug:
|
||
|
diff --git a/tests/get_unused_disk.yml b/tests/get_unused_disk.yml
|
||
|
index 9f4c5d2..79e952a 100644
|
||
|
--- a/tests/get_unused_disk.yml
|
||
|
+++ b/tests/get_unused_disk.yml
|
||
|
@@ -9,12 +9,10 @@
|
||
|
unused_disks: "{{ unused_disks_return.disks }}"
|
||
|
when: "'Unable to find unused disk' not in unused_disks_return.disks"
|
||
|
|
||
|
-- block:
|
||
|
- - name: Exit playbook when there's no unused disks in the system
|
||
|
- debug:
|
||
|
- msg: "Unable to find unused disks. Exiting playbook."
|
||
|
- - meta: end_play
|
||
|
- when: unused_disks is undefined
|
||
|
+- name: Exit playbook when there's not enough unused disks in the system
|
||
|
+ fail:
|
||
|
+ msg: "Unable to find enough unused disks. Exiting playbook."
|
||
|
+ when: unused_disks is undefined or unused_disks|length < disks_needed|default(1)
|
||
|
|
||
|
- name: Print unused disks
|
||
|
debug:
|
||
|
diff --git a/tests/tests_change_disk_fs.yml b/tests/tests_change_disk_fs.yml
|
||
|
index b6aa80b..f7962c6 100644
|
||
|
--- a/tests/tests_change_disk_fs.yml
|
||
|
+++ b/tests/tests_change_disk_fs.yml
|
||
|
@@ -2,6 +2,7 @@
|
||
|
- hosts: all
|
||
|
become: true
|
||
|
vars:
|
||
|
+ storage_safe_mode: false
|
||
|
mount_location: '/opt/test'
|
||
|
volume_size: '5g'
|
||
|
fs_type_after: "{{ 'ext3' if (ansible_distribution == 'RedHat' and ansible_distribution_major_version == '6') else 'ext4' }}"
|
||
|
diff --git a/tests/tests_change_fs.yml b/tests/tests_change_fs.yml
|
||
|
index cca23eb..b88e768 100644
|
||
|
--- a/tests/tests_change_fs.yml
|
||
|
+++ b/tests/tests_change_fs.yml
|
||
|
@@ -2,6 +2,7 @@
|
||
|
- hosts: all
|
||
|
become: true
|
||
|
vars:
|
||
|
+ storage_safe_mode: false
|
||
|
mount_location: '/opt/test1'
|
||
|
volume_size: '5g'
|
||
|
fs_after: "{{ (ansible_distribution == 'RedHat' and ansible_distribution_major_version == '6') | ternary('ext4', 'xfs') }}"
|
||
|
diff --git a/tests/tests_change_fs_use_partitions.yml b/tests/tests_change_fs_use_partitions.yml
|
||
|
index e4aa76c..eb93c11 100644
|
||
|
--- a/tests/tests_change_fs_use_partitions.yml
|
||
|
+++ b/tests/tests_change_fs_use_partitions.yml
|
||
|
@@ -2,6 +2,7 @@
|
||
|
- hosts: all
|
||
|
become: true
|
||
|
vars:
|
||
|
+ storage_safe_mode: false
|
||
|
storage_use_partitions: true
|
||
|
mount_location: '/opt/test1'
|
||
|
volume_size: '5g'
|
||
|
diff --git a/tests/tests_create_disk_then_remove.yml b/tests/tests_create_disk_then_remove.yml
|
||
|
index b19ae35..c5290eb 100644
|
||
|
--- a/tests/tests_create_disk_then_remove.yml
|
||
|
+++ b/tests/tests_create_disk_then_remove.yml
|
||
|
@@ -2,6 +2,7 @@
|
||
|
- hosts: all
|
||
|
become: true
|
||
|
vars:
|
||
|
+ storage_safe_mode: false
|
||
|
mount_location: '/opt/test1'
|
||
|
|
||
|
tasks:
|
||
|
diff --git a/tests/tests_create_lvm_pool_then_remove.yml b/tests/tests_create_lvm_pool_then_remove.yml
|
||
|
index 6b25939..f2c06fb 100644
|
||
|
--- a/tests/tests_create_lvm_pool_then_remove.yml
|
||
|
+++ b/tests/tests_create_lvm_pool_then_remove.yml
|
||
|
@@ -2,6 +2,7 @@
|
||
|
- hosts: all
|
||
|
become: true
|
||
|
vars:
|
||
|
+ storage_safe_mode: false
|
||
|
mount_location1: '/opt/test1'
|
||
|
mount_location2: '/opt/test2'
|
||
|
volume_group_size: '10g'
|
||
|
diff --git a/tests/tests_create_partition_volume_then_remove.yml b/tests/tests_create_partition_volume_then_remove.yml
|
||
|
index 40b3e62..ae589d3 100644
|
||
|
--- a/tests/tests_create_partition_volume_then_remove.yml
|
||
|
+++ b/tests/tests_create_partition_volume_then_remove.yml
|
||
|
@@ -2,6 +2,7 @@
|
||
|
- hosts: all
|
||
|
become: true
|
||
|
vars:
|
||
|
+ storage_safe_mode: false
|
||
|
mount_location: '/opt/test1'
|
||
|
|
||
|
tasks:
|
||
|
@@ -18,7 +19,7 @@
|
||
|
vars:
|
||
|
storage_pools:
|
||
|
- name: "{{ unused_disks[0] }}"
|
||
|
- type: disk
|
||
|
+ type: partition
|
||
|
disks: "{{ unused_disks }}"
|
||
|
volumes:
|
||
|
- name: test1
|
||
|
@@ -33,7 +34,7 @@
|
||
|
vars:
|
||
|
storage_pools:
|
||
|
- name: "{{ unused_disks[0] }}"
|
||
|
- type: disk
|
||
|
+ type: partition
|
||
|
disks: "{{ unused_disks }}"
|
||
|
volumes:
|
||
|
- name: test1
|
||
|
@@ -48,7 +49,7 @@
|
||
|
vars:
|
||
|
storage_pools:
|
||
|
- name: "{{ unused_disks[0] }}"
|
||
|
- type: disk
|
||
|
+ type: partition
|
||
|
disks: "{{ unused_disks }}"
|
||
|
state: absent
|
||
|
volumes:
|
||
|
@@ -65,7 +66,7 @@
|
||
|
vars:
|
||
|
storage_pools:
|
||
|
- name: "{{ unused_disks[0] }}"
|
||
|
- type: disk
|
||
|
+ type: partition
|
||
|
disks: "{{ unused_disks }}"
|
||
|
state: absent
|
||
|
volumes:
|
||
|
diff --git a/tests/tests_disk_errors.yml b/tests/tests_disk_errors.yml
|
||
|
index 36eec41..7112f6e 100644
|
||
|
--- a/tests/tests_disk_errors.yml
|
||
|
+++ b/tests/tests_disk_errors.yml
|
||
|
@@ -3,8 +3,17 @@
|
||
|
become: true
|
||
|
vars:
|
||
|
mount_location: '/opt/test1'
|
||
|
+ testfile: "{{ mount_location }}/quux"
|
||
|
|
||
|
tasks:
|
||
|
+ - include_role:
|
||
|
+ name: storage
|
||
|
+
|
||
|
+ - include_tasks: get_unused_disk.yml
|
||
|
+ vars:
|
||
|
+ min_size: "10g"
|
||
|
+ max_return: 1
|
||
|
+
|
||
|
- name: Verify that the play fails with the expected error message
|
||
|
block:
|
||
|
- name: Create a disk volume mounted at "{{ mount_location }}"
|
||
|
@@ -14,11 +23,246 @@
|
||
|
storage_volumes:
|
||
|
- name: test1
|
||
|
type: disk
|
||
|
- disks: "['/dev/surelyidonotexist']"
|
||
|
+ disks: ['/dev/surelyidonotexist']
|
||
|
mount_point: "{{ mount_location }}"
|
||
|
|
||
|
- - name: Check the error output
|
||
|
+ - name: UNREACH
|
||
|
+ fail:
|
||
|
+ msg: "this should be unreachable"
|
||
|
+
|
||
|
+ rescue:
|
||
|
+ - name: Check that we failed in the role
|
||
|
+ assert:
|
||
|
+ that:
|
||
|
+ - ansible_failed_task.name != 'UNREACH'
|
||
|
+ msg: "Role has not failed when it should have"
|
||
|
+ vars:
|
||
|
+ # Ugh! needed to expand ansible_failed_task
|
||
|
+ storage_provider: blivet
|
||
|
+
|
||
|
+ # the following does not work properly,
|
||
|
+ # blivet_output.failed is false.
|
||
|
+ # - name: Show the error output
|
||
|
+ # debug:
|
||
|
+ # msg: "{{ blivet_output.failed }}"
|
||
|
+
|
||
|
+ # - name: Check the error output
|
||
|
+ # assert:
|
||
|
+ # that: blivet_output.failed | bool
|
||
|
+ # msg: "Expected error message not found for missing disk"
|
||
|
+
|
||
|
+ - name: Create a file system on disk
|
||
|
+ include_role:
|
||
|
+ name: storage
|
||
|
+ vars:
|
||
|
+ storage_volumes:
|
||
|
+ - name: test1
|
||
|
+ type: disk
|
||
|
+ fs_type: 'ext4'
|
||
|
+ disks: "{{ unused_disks }}"
|
||
|
+ mount_point: "{{ mount_location }}"
|
||
|
+
|
||
|
+ - name: create a file
|
||
|
+ file:
|
||
|
+ path: "{{ testfile }}"
|
||
|
+ state: touch
|
||
|
+
|
||
|
+ - name: Test for correct handling of safe_mode
|
||
|
+ block:
|
||
|
+ - name: Try to replace the file system on disk in safe mode
|
||
|
+ include_role:
|
||
|
+ name: storage
|
||
|
+ vars:
|
||
|
+ storage_volumes:
|
||
|
+ - name: test1
|
||
|
+ type: disk
|
||
|
+ fs_type: 'ext3'
|
||
|
+ disks: "{{ unused_disks }}"
|
||
|
+
|
||
|
+ - name: UNREACH
|
||
|
+ fail:
|
||
|
+ msg: "this should be unreachable"
|
||
|
+
|
||
|
+ rescue:
|
||
|
+ - name: Check that we failed in the role
|
||
|
+ assert:
|
||
|
+ that:
|
||
|
+ - ansible_failed_task.name != 'UNREACH'
|
||
|
+ msg: "Role has not failed when it should have"
|
||
|
+ vars:
|
||
|
+ # Ugh! needed to expand ansible_failed_task
|
||
|
+ storage_provider: blivet
|
||
|
+
|
||
|
+ - name: Verify the output
|
||
|
+ assert:
|
||
|
+ that: "blivet_output.failed and
|
||
|
+ blivet_output.msg|regex_search('cannot remove existing formatting on volume.*in safe mode') and
|
||
|
+ not blivet_output.changed"
|
||
|
+ msg: "Unexpected behavior w/ existing data on specified disks"
|
||
|
+
|
||
|
+ - name: Unmount file system
|
||
|
+ include_role:
|
||
|
+ name: storage
|
||
|
+ vars:
|
||
|
+ storage_volumes:
|
||
|
+ - name: test1
|
||
|
+ type: disk
|
||
|
+ fs_type: 'ext4'
|
||
|
+ disks: "{{ unused_disks }}"
|
||
|
+ mount_point: none
|
||
|
+
|
||
|
+ - name: Test for correct handling of safe_mode with unmounted filesystem
|
||
|
+ block:
|
||
|
+ - name: Try to replace the file system on disk in safe mode
|
||
|
+ include_role:
|
||
|
+ name: storage
|
||
|
+ vars:
|
||
|
+ storage_volumes:
|
||
|
+ - name: test1
|
||
|
+ type: disk
|
||
|
+ fs_type: 'ext3'
|
||
|
+ disks: "{{ unused_disks }}"
|
||
|
+
|
||
|
+ - name: UNREACH
|
||
|
+ fail:
|
||
|
+ msg: "this should be unreachable"
|
||
|
+
|
||
|
+ rescue:
|
||
|
+ - name: Check that we failed in the role
|
||
|
assert:
|
||
|
- that: "{{ blivet_output.failed }}"
|
||
|
- msg: "Expected error message not found for missing disk"
|
||
|
- ignore_errors: yes
|
||
|
+ that:
|
||
|
+ - ansible_failed_task.name != 'UNREACH'
|
||
|
+ msg: "Role has not failed when it should have"
|
||
|
+ vars:
|
||
|
+ # Ugh! needed to expand ansible_failed_task
|
||
|
+ storage_provider: blivet
|
||
|
+
|
||
|
+ - name: Verify the output
|
||
|
+ assert:
|
||
|
+ that: "blivet_output.failed and
|
||
|
+ blivet_output.msg|regex_search('cannot remove existing formatting on volume.*in safe mode') and
|
||
|
+ not blivet_output.changed"
|
||
|
+ msg: "Unexpected behavior w/ existing data on specified disks"
|
||
|
+
|
||
|
+ - name: Remount file system
|
||
|
+ include_role:
|
||
|
+ name: storage
|
||
|
+ vars:
|
||
|
+ storage_volumes:
|
||
|
+ - name: test1
|
||
|
+ type: disk
|
||
|
+ fs_type: 'ext4'
|
||
|
+ disks: "{{ unused_disks }}"
|
||
|
+ mount_point: "{{ mount_location }}"
|
||
|
+
|
||
|
+ - name: stat the file
|
||
|
+ stat:
|
||
|
+ path: "{{ testfile }}"
|
||
|
+ register: stat_r
|
||
|
+
|
||
|
+ - name: assert file presence
|
||
|
+ assert:
|
||
|
+ that:
|
||
|
+ stat_r.stat.isreg is defined and stat_r.stat.isreg
|
||
|
+ msg: "data lost!"
|
||
|
+
|
||
|
+ - name: Test for correct handling of safe_mode
|
||
|
+ block:
|
||
|
+ - name: Try to create a partition pool on the disk already containing a file system in safe_mode
|
||
|
+ include_role:
|
||
|
+ name: storage
|
||
|
+ vars:
|
||
|
+ storage_pools:
|
||
|
+ - name: foo
|
||
|
+ disks: "{{ unused_disks }}"
|
||
|
+ type: partition
|
||
|
+
|
||
|
+ - name: UNREACH
|
||
|
+ fail:
|
||
|
+ msg: "this should be unreachable"
|
||
|
+
|
||
|
+ rescue:
|
||
|
+ - name: Check that we failed in the role
|
||
|
+ assert:
|
||
|
+ that:
|
||
|
+ - ansible_failed_task.name != 'UNREACH'
|
||
|
+ msg: "Role has not failed when it should have"
|
||
|
+ vars:
|
||
|
+ # Ugh! needed to expand ansible_failed_task
|
||
|
+ storage_provider: blivet
|
||
|
+
|
||
|
+ - name: Verify the output
|
||
|
+ assert:
|
||
|
+ that: "blivet_output.failed and
|
||
|
+ blivet_output.msg|regex_search('cannot remove existing formatting and/or devices on disk.*in safe mode') and
|
||
|
+ not blivet_output.changed"
|
||
|
+ msg: "Unexpected behavior w/ existing data on specified disks"
|
||
|
+
|
||
|
+ - name: Test for correct handling of safe_mode with existing filesystem
|
||
|
+ block:
|
||
|
+ - name: Try to create LVM pool on disk that already belongs to an existing filesystem
|
||
|
+ include_role:
|
||
|
+ name: storage
|
||
|
+ vars:
|
||
|
+ storage_pools:
|
||
|
+ - name: foo
|
||
|
+ disks: "{{ unused_disks }}"
|
||
|
+ type: lvm
|
||
|
+
|
||
|
+ - name: UNREACH
|
||
|
+ fail:
|
||
|
+ msg: "this should be unreachable"
|
||
|
+
|
||
|
+ rescue:
|
||
|
+ - name: Check that we failed in the role
|
||
|
+ assert:
|
||
|
+ that:
|
||
|
+ - ansible_failed_task.name != 'UNREACH'
|
||
|
+ msg: "Role has not failed when it should have"
|
||
|
+ vars:
|
||
|
+ # Ugh! needed to expand ansible_failed_task
|
||
|
+ storage_provider: blivet
|
||
|
+
|
||
|
+ - name: Verify the output
|
||
|
+ assert:
|
||
|
+ that: "{{ blivet_output.failed and
|
||
|
+ blivet_output.msg|regex_search('cannot remove existing formatting and/or devices on disk.*in safe mode') and
|
||
|
+ not blivet_output.changed }}"
|
||
|
+ msg: "Unexpected behavior w/ existing data on specified disks"
|
||
|
+
|
||
|
+ - name: stat the file
|
||
|
+ stat:
|
||
|
+ path: "{{ testfile }}"
|
||
|
+ register: stat_r
|
||
|
+
|
||
|
+ - name: assert file presence
|
||
|
+ assert:
|
||
|
+ that:
|
||
|
+ stat_r.stat.isreg is defined and stat_r.stat.isreg
|
||
|
+ msg: "data lost!"
|
||
|
+
|
||
|
+ - name: Create a partition pool on the disk already containing a file system w/o safe_mode
|
||
|
+ include_role:
|
||
|
+ name: storage
|
||
|
+ vars:
|
||
|
+ storage_safe_mode: false
|
||
|
+ storage_pools:
|
||
|
+ - name: foo
|
||
|
+ disks: "{{ unused_disks }}"
|
||
|
+ type: partition
|
||
|
+
|
||
|
+ - name: Verify the output
|
||
|
+ assert:
|
||
|
+ that: not blivet_output.failed
|
||
|
+ msg: "failed to create partition pool over existing file system w/o safe_mode"
|
||
|
+
|
||
|
+ - name: Clean up
|
||
|
+ include_role:
|
||
|
+ name: storage
|
||
|
+ vars:
|
||
|
+ storage_safe_mode: false
|
||
|
+ storage_pools:
|
||
|
+ - name: foo
|
||
|
+ type: partition
|
||
|
+ disks: "{{ unused_disks }}"
|
||
|
+ state: absent
|
||
|
diff --git a/tests/tests_lvm_errors.yml b/tests/tests_lvm_errors.yml
|
||
|
index ab23674..e8be153 100644
|
||
|
--- a/tests/tests_lvm_errors.yml
|
||
|
+++ b/tests/tests_lvm_errors.yml
|
||
|
@@ -33,13 +33,32 @@
|
||
|
size: "{{ volume1_size }}"
|
||
|
mount_point: "{{ mount_location1 }}"
|
||
|
|
||
|
- - name: Verify the output
|
||
|
+ - name: UNREACH
|
||
|
+ fail:
|
||
|
+ msg: "this should be unreachable"
|
||
|
+
|
||
|
+ rescue:
|
||
|
+ - name: Check that we failed in the role
|
||
|
assert:
|
||
|
- that: "{{ blivet_output.failed and
|
||
|
- blivet_output.msg|regex_search('unable to resolve.+disk')|length>0 and
|
||
|
- not blivet_output.changed }}"
|
||
|
- msg: "Unexpected behavior w/ non-existent pool disk"
|
||
|
- ignore_errors: yes
|
||
|
+ that:
|
||
|
+ - ansible_failed_task.name != 'UNREACH'
|
||
|
+ msg: "Role has not failed when it should have"
|
||
|
+ vars:
|
||
|
+ # Ugh! needed to expand ansible_failed_task
|
||
|
+ storage_provider: blivet
|
||
|
+
|
||
|
+ # the following does not work properly
|
||
|
+ # - debug:
|
||
|
+ # msg: "{{ 'failed: ' + blivet_output.failed | string +
|
||
|
+ # 'msg: ' + blivet_output.msg +
|
||
|
+ # 'changed: ' + blivet_output.changed | string }}"
|
||
|
+
|
||
|
+ # - name: Verify the output
|
||
|
+ # assert:
|
||
|
+ # that: "{{ blivet_output.failed and
|
||
|
+ # blivet_output.msg|regex_search('unable to resolve.+disk')|length>0 and
|
||
|
+ # not blivet_output.changed }}"
|
||
|
+ # msg: "Unexpected behavior w/ non-existent pool disk"
|
||
|
|
||
|
- name: Test for correct handling of invalid size specification.
|
||
|
block:
|
||
|
@@ -55,13 +74,27 @@
|
||
|
size: "{{ invalid_size }}"
|
||
|
mount_point: "{{ mount_location1 }}"
|
||
|
|
||
|
- - name: Verify the output
|
||
|
+ - name: UNREACH
|
||
|
+ fail:
|
||
|
+ msg: "this should be unreachable"
|
||
|
+
|
||
|
+ rescue:
|
||
|
+ - name: Check that we failed in the role
|
||
|
assert:
|
||
|
- that: "{{ blivet_output.failed and
|
||
|
- blivet_output.msg|regex_search('invalid size.+for volume') and
|
||
|
- not blivet_output.changed }}"
|
||
|
- msg: "Unexpected behavior w/ invalid volume size"
|
||
|
- ignore_errors: yes
|
||
|
+ that:
|
||
|
+ - ansible_failed_task.name != 'UNREACH'
|
||
|
+ msg: "Role has not failed when it should have"
|
||
|
+ vars:
|
||
|
+ # Ugh! needed to expand ansible_failed_task
|
||
|
+ storage_provider: blivet
|
||
|
+
|
||
|
+ # the following does not work properly
|
||
|
+ # - name: Verify the output
|
||
|
+ # assert:
|
||
|
+ # that: "{{ blivet_output.failed and
|
||
|
+ # blivet_output.msg|regex_search('invalid size.+for volume') and
|
||
|
+ # not blivet_output.changed }}"
|
||
|
+ # msg: "Unexpected behavior w/ invalid volume size"
|
||
|
|
||
|
- name: Test for correct handling of too-large volume size.
|
||
|
block:
|
||
|
@@ -77,13 +110,27 @@
|
||
|
size: "{{ too_large_size }}"
|
||
|
mount_point: "{{ mount_location1 }}"
|
||
|
|
||
|
- - name: Verify the output
|
||
|
+ - name: UNREACH
|
||
|
+ fail:
|
||
|
+ msg: "this should be unreachable"
|
||
|
+
|
||
|
+ rescue:
|
||
|
+ - name: Check that we failed in the role
|
||
|
assert:
|
||
|
- that: "{{ blivet_output.failed and
|
||
|
- blivet_output.msg|regex_search('size.+exceeds.+space in pool') and
|
||
|
- not blivet_output.changed }}"
|
||
|
- msg: "Unexpected behavior w/ too-large volume size"
|
||
|
- ignore_errors: yes
|
||
|
+ that:
|
||
|
+ - ansible_failed_task.name != 'UNREACH'
|
||
|
+ msg: "Role has not failed when it should have"
|
||
|
+ vars:
|
||
|
+ # Ugh! needed to expand ansible_failed_task
|
||
|
+ storage_provider: blivet
|
||
|
+
|
||
|
+ # the following does not work properly
|
||
|
+ # - name: Verify the output
|
||
|
+ # assert:
|
||
|
+ # that: "{{ blivet_output.failed and
|
||
|
+ # blivet_output.msg|regex_search('size.+exceeds.+space in pool') and
|
||
|
+ # not blivet_output.changed }}"
|
||
|
+ # msg: "Unexpected behavior w/ too-large volume size"
|
||
|
|
||
|
- name: Test for correct handling of non-list disk specification.
|
||
|
block:
|
||
|
@@ -99,13 +146,27 @@
|
||
|
size: "{{ too_large_size }}"
|
||
|
mount_point: "{{ mount_location1 }}"
|
||
|
|
||
|
- - name: Verify the output
|
||
|
+ - name: UNREACH
|
||
|
+ fail:
|
||
|
+ msg: "this should be unreachable"
|
||
|
+
|
||
|
+ rescue:
|
||
|
+ - name: Check that we failed in the role
|
||
|
assert:
|
||
|
- that: "{{ blivet_output.failed and
|
||
|
- blivet_output.msg|regex_search('disk.+list') and
|
||
|
- not blivet_output.changed }}"
|
||
|
- msg: "Unexpected behavior w/ disks not in list form"
|
||
|
- ignore_errors: yes
|
||
|
+ that:
|
||
|
+ - ansible_failed_task.name != 'UNREACH'
|
||
|
+ msg: "Role has not failed when it should have"
|
||
|
+ vars:
|
||
|
+ # Ugh! needed to expand ansible_failed_task
|
||
|
+ storage_provider: blivet
|
||
|
+
|
||
|
+ # the following does not work properly
|
||
|
+ # - name: Verify the output
|
||
|
+ # assert:
|
||
|
+ # that: "{{ blivet_output.failed and
|
||
|
+ # blivet_output.msg|regex_search('disk.+list') and
|
||
|
+ # not blivet_output.changed }}"
|
||
|
+ # msg: "Unexpected behavior w/ disks not in list form"
|
||
|
|
||
|
- name: Test for correct handling of missing disk specification.
|
||
|
block:
|
||
|
@@ -121,13 +182,27 @@
|
||
|
size: "{{ too_large_size }}"
|
||
|
mount_point: "{{ mount_location1 }}"
|
||
|
|
||
|
- - name: Verify the output
|
||
|
+ - name: UNREACH
|
||
|
+ fail:
|
||
|
+ msg: "this should be unreachable"
|
||
|
+
|
||
|
+ rescue:
|
||
|
+ - name: Check that we failed in the role
|
||
|
assert:
|
||
|
- that: "{{ blivet_output.failed and
|
||
|
- blivet_output.msg|regex_search('no disks.+pool') and
|
||
|
- not blivet_output.changed }}"
|
||
|
- msg: "Unexpected behavior w/ no disks specified"
|
||
|
- ignore_errors: yes
|
||
|
+ that:
|
||
|
+ - ansible_failed_task.name != 'UNREACH'
|
||
|
+ msg: "Role has not failed when it should have"
|
||
|
+ vars:
|
||
|
+ # Ugh! needed to expand ansible_failed_task
|
||
|
+ storage_provider: blivet
|
||
|
+
|
||
|
+ # the following does not work properly
|
||
|
+ # - name: Verify the output
|
||
|
+ # assert:
|
||
|
+ # that: "{{ blivet_output.failed and
|
||
|
+ # blivet_output.msg|regex_search('no disks.+pool') and
|
||
|
+ # not blivet_output.changed }}"
|
||
|
+ # msg: "Unexpected behavior w/ no disks specified"
|
||
|
|
||
|
- name: Test for correct handling of LVM volume not defined within a pool.
|
||
|
block:
|
||
|
@@ -142,10 +217,179 @@
|
||
|
size: "{{ volume1_size }}"
|
||
|
mount_point: "{{ mount_location1 }}"
|
||
|
|
||
|
+ - name: UNREACH
|
||
|
+ fail:
|
||
|
+ msg: "this should be unreachable"
|
||
|
+
|
||
|
+ rescue:
|
||
|
+ - name: Check that we failed in the role
|
||
|
+ assert:
|
||
|
+ that:
|
||
|
+ - ansible_failed_task.name != 'UNREACH'
|
||
|
+ msg: "Role has not failed when it should have"
|
||
|
+ vars:
|
||
|
+ # Ugh! needed to expand ansible_failed_task
|
||
|
+ storage_provider: blivet
|
||
|
+
|
||
|
+ # the following does not work properly
|
||
|
+ # - name: Verify the output
|
||
|
+ # assert:
|
||
|
+ # that: "{{ blivet_output.failed and
|
||
|
+ # blivet_output.msg|regex_search('failed to find pool .+ for volume') and
|
||
|
+ # not blivet_output.changed }}"
|
||
|
+ # msg: "Unexpected behavior w/ LVM volume defined outside of any pool"
|
||
|
+
|
||
|
+ - name: Create a pool
|
||
|
+ include_role:
|
||
|
+ name: storage
|
||
|
+ vars:
|
||
|
+ storage_pools:
|
||
|
+ - name: testpool1
|
||
|
+ type: lvm
|
||
|
+ disks: "{{ unused_disks }}"
|
||
|
+ volumes:
|
||
|
+ - name: testvol1
|
||
|
+ fs_type: 'ext4'
|
||
|
+ size: '1g'
|
||
|
+
|
||
|
+ - name: Test for correct handling of safe_mode
|
||
|
+ block:
|
||
|
+ - name: Try to replace file system in safe mode
|
||
|
+ include_role:
|
||
|
+ name: storage
|
||
|
+ vars:
|
||
|
+ storage_pools:
|
||
|
+ - name: testpool1
|
||
|
+ type: lvm
|
||
|
+ disks: "{{ unused_disks }}"
|
||
|
+ volumes:
|
||
|
+ - name: testvol1
|
||
|
+ fs_type: 'ext3'
|
||
|
+ size: '1g'
|
||
|
+
|
||
|
+ - name: UNREACH
|
||
|
+ fail:
|
||
|
+ msg: "this should be unreachable"
|
||
|
+
|
||
|
+ rescue:
|
||
|
+ - name: Check that we failed in the role
|
||
|
+ assert:
|
||
|
+ that:
|
||
|
+ - ansible_failed_task.name != 'UNREACH'
|
||
|
+ msg: "Role has not failed when it should have"
|
||
|
+ vars:
|
||
|
+ # Ugh! needed to expand ansible_failed_task
|
||
|
+ storage_provider: blivet
|
||
|
+
|
||
|
- name: Verify the output
|
||
|
assert:
|
||
|
that: "{{ blivet_output.failed and
|
||
|
- blivet_output.msg|regex_search('failed to find pool .+ for volume') and
|
||
|
+ blivet_output.msg|regex_search('cannot remove existing formatting on volume.*in safe mode') and
|
||
|
not blivet_output.changed }}"
|
||
|
- msg: "Unexpected behavior w/ LVM volume defined outside of any pool"
|
||
|
- ignore_errors: yes
|
||
|
+ msg: "Unexpected behavior w/ existing data on specified disks"
|
||
|
+
|
||
|
+ - name: Test for correct handling of safe_mode with resize
|
||
|
+ block:
|
||
|
+ - name: Try to resize in safe mode
|
||
|
+ include_role:
|
||
|
+ name: storage
|
||
|
+ vars:
|
||
|
+ storage_pools:
|
||
|
+ - name: testpool1
|
||
|
+ type: lvm
|
||
|
+ disks: "{{ unused_disks }}"
|
||
|
+ volumes:
|
||
|
+ - name: testvol1
|
||
|
+ fs_type: 'ext4'
|
||
|
+ size: '2g'
|
||
|
+
|
||
|
+ - name: Verify the output
|
||
|
+ assert:
|
||
|
+ that: "{{ not blivet_output.failed and blivet_output.changed }}"
|
||
|
+ msg: "Unexpected behavior w/ existing data on specified disks"
|
||
|
+
|
||
|
+ when: false
|
||
|
+
|
||
|
+ - name: Test for correct handling of safe_mode with existing pool
|
||
|
+ block:
|
||
|
+ - name: Try to create LVM pool on disks that already belong to an existing pool
|
||
|
+ include_role:
|
||
|
+ name: storage
|
||
|
+ vars:
|
||
|
+ storage_pools:
|
||
|
+ - name: foo
|
||
|
+ disks: "{{ unused_disks }}"
|
||
|
+ type: lvm
|
||
|
+
|
||
|
+ - name: UNREACH
|
||
|
+ fail:
|
||
|
+ msg: "this should be unreachable"
|
||
|
+
|
||
|
+ rescue:
|
||
|
+ - name: Check that we failed in the role
|
||
|
+ assert:
|
||
|
+ that:
|
||
|
+ - ansible_failed_task.name != 'UNREACH'
|
||
|
+ msg: "Role has not failed when it should have"
|
||
|
+ vars:
|
||
|
+ # Ugh! needed to expand ansible_failed_task
|
||
|
+ storage_provider: blivet
|
||
|
+
|
||
|
+ - name: Verify the output
|
||
|
+ assert:
|
||
|
+ that: "{{ blivet_output.failed and
|
||
|
+ blivet_output.msg|regex_search('cannot remove existing formatting and/or devices on disk.*in safe mode') and
|
||
|
+ not blivet_output.changed }}"
|
||
|
+ msg: "Unexpected behavior w/ existing data on specified disks"
|
||
|
+
|
||
|
+ - name: Test for correct handling of safe_mode
|
||
|
+ block:
|
||
|
+ - name: Try to replace a pool by a file system on disk in safe mode
|
||
|
+ include_role:
|
||
|
+ name: storage
|
||
|
+ vars:
|
||
|
+ storage_volumes:
|
||
|
+ - name: test1
|
||
|
+ type: disk
|
||
|
+ fs_type: 'ext3'
|
||
|
+ disks:
|
||
|
+ - "{{ unused_disks[0] }}"
|
||
|
+
|
||
|
+ - name: UNREACH
|
||
|
+ fail:
|
||
|
+ msg: "this should be unreachable"
|
||
|
+
|
||
|
+ rescue:
|
||
|
+ - name: Check that we failed in the role
|
||
|
+ assert:
|
||
|
+ that:
|
||
|
+ - ansible_failed_task.name != 'UNREACH'
|
||
|
+ msg: "Role has not failed when it should have"
|
||
|
+ vars:
|
||
|
+ # Ugh! needed to expand ansible_failed_task
|
||
|
+ storage_provider: blivet
|
||
|
+
|
||
|
+ - name: Verify the output
|
||
|
+ assert:
|
||
|
+ that: "blivet_output.failed and
|
||
|
+ blivet_output.msg|regex_search('cannot remove existing formatting on volume.*in safe mode') and
|
||
|
+ not blivet_output.changed"
|
||
|
+ msg: "Unexpected behavior w/ existing data on specified disks"
|
||
|
+
|
||
|
+ - name: Verify the output
|
||
|
+ assert:
|
||
|
+ that: "blivet_output.failed and
|
||
|
+ blivet_output.msg|regex_search('cannot remove existing formatting on volume.*in safe mode') and
|
||
|
+ not blivet_output.changed"
|
||
|
+ msg: "Unexpected behavior w/ existing data on specified disks"
|
||
|
+
|
||
|
+ - name: Clean up
|
||
|
+ include_role:
|
||
|
+ name: storage
|
||
|
+ vars:
|
||
|
+ storage_safe_mode: false
|
||
|
+ storage_pools:
|
||
|
+ - name: testpool1
|
||
|
+ type: lvm
|
||
|
+ disks: "{{ unused_disks }}"
|
||
|
+ state: absent
|
||
|
diff --git a/tests/tests_lvm_multiple_disks_multiple_volumes.yml b/tests/tests_lvm_multiple_disks_multiple_volumes.yml
|
||
|
index bbc7bb0..ca3968f 100644
|
||
|
--- a/tests/tests_lvm_multiple_disks_multiple_volumes.yml
|
||
|
+++ b/tests/tests_lvm_multiple_disks_multiple_volumes.yml
|
||
|
@@ -15,13 +15,7 @@
|
||
|
vars:
|
||
|
min_size: "{{ volume_group_size }}"
|
||
|
max_return: 2
|
||
|
-
|
||
|
- - block:
|
||
|
- - debug:
|
||
|
- msg: "There needs to be two unused disks in the system to run this playbook."
|
||
|
- - name: End playbook if there isn't two disks available
|
||
|
- meta: end_play
|
||
|
- when: unused_disks|length < 2
|
||
|
+ disks_needed: 2
|
||
|
|
||
|
- name: Create a logical volume spanning two physical volumes that changes its mount location
|
||
|
include_role:
|