603 lines
19 KiB
Diff
603 lines
19 KiB
Diff
diff --git a/library/blivet.py b/library/blivet.py
|
|
index cb48e71..e1903f3 100644
|
|
--- a/library/blivet.py
|
|
+++ b/library/blivet.py
|
|
@@ -167,11 +167,16 @@ class BlivetBase(object):
|
|
raise NotImplementedError()
|
|
|
|
def _manage_one_encryption(self, device):
|
|
+ global safe_mode
|
|
ret = device
|
|
# Make sure to handle adjusting both existing stacks and future stacks.
|
|
if device == device.raw_device and self._spec_dict['encryption']:
|
|
# add luks
|
|
luks_name = "luks-%s" % device._name
|
|
+ if safe_mode and (device.original_format.type is not None or
|
|
+ device.original_format.name != get_format(None).name):
|
|
+ raise BlivetAnsibleError("cannot remove existing formatting on device '%s' in safe mode due to adding encryption" %
|
|
+ device._name)
|
|
if not device.format.exists:
|
|
fmt = device.format
|
|
else:
|
|
@@ -196,6 +201,10 @@ class BlivetBase(object):
|
|
ret = luks_device
|
|
elif device != device.raw_device and not self._spec_dict['encryption']:
|
|
# remove luks
|
|
+ if safe_mode and (device.original_format.type is not None or
|
|
+ device.original_format.name != get_format(None).name):
|
|
+ raise BlivetAnsibleError("cannot remove existing formatting on device '%s' in safe mode due to encryption removal" %
|
|
+ device._name)
|
|
if not device.format.exists:
|
|
fmt = device.format
|
|
else:
|
|
@@ -823,17 +832,21 @@ class BlivetPool(BlivetBase):
|
|
|
|
def manage(self):
|
|
""" Schedule actions to configure this pool according to the yaml input. """
|
|
+ global safe_mode
|
|
# look up the device
|
|
self._look_up_disks()
|
|
self._look_up_device()
|
|
|
|
# schedule destroy if appropriate, including member type change
|
|
- if not self.ultimately_present or self._member_management_is_destructive():
|
|
- if not self.ultimately_present:
|
|
- self._manage_volumes()
|
|
+ if not self.ultimately_present:
|
|
+ self._manage_volumes()
|
|
self._destroy()
|
|
- if not self.ultimately_present:
|
|
- return
|
|
+ return
|
|
+ elif self._member_management_is_destructive():
|
|
+ if safe_mode:
|
|
+ raise BlivetAnsibleError("cannot remove and recreate existing pool '%s' in safe mode" % self._pool['name'])
|
|
+ else:
|
|
+ self._destroy()
|
|
|
|
# schedule create if appropriate
|
|
self._create()
|
|
diff --git a/tests/create-test-file.yml b/tests/create-test-file.yml
|
|
new file mode 100644
|
|
index 0000000..d1091e2
|
|
--- /dev/null
|
|
+++ b/tests/create-test-file.yml
|
|
@@ -0,0 +1,13 @@
|
|
+# Create a file to be checked that it still exists and no data loss has occured.
|
|
+# To use:
|
|
+# - set testfile to a path under the mountpoint being tested
|
|
+# - include this file (create-test-file.yml) before executing the
|
|
+# operation to be tested
|
|
+# - execute the operation that could potentially result in a loss of
|
|
+# data in the filesystem where testfile is located
|
|
+# - include verify-data-preservation.yml
|
|
+
|
|
+- name: create a file
|
|
+ file:
|
|
+ path: "{{ testfile }}"
|
|
+ state: touch
|
|
diff --git a/tests/tests_luks.yml b/tests/tests_luks.yml
|
|
index f93efe5..f733714 100644
|
|
--- a/tests/tests_luks.yml
|
|
+++ b/tests/tests_luks.yml
|
|
@@ -2,8 +2,8 @@
|
|
- hosts: all
|
|
become: true
|
|
vars:
|
|
- storage_safe_mode: false
|
|
mount_location: '/opt/test1'
|
|
+ testfile: "{{ mount_location }}/quux"
|
|
volume_size: '5g'
|
|
|
|
tasks:
|
|
@@ -64,10 +64,47 @@
|
|
|
|
- include_tasks: verify-role-results.yml
|
|
|
|
+ - import_tasks: create-test-file.yml
|
|
+
|
|
+ - name: Test for correct handling of safe_mode
|
|
+ block:
|
|
+ - name: Remove the encryption layer
|
|
+ include_role:
|
|
+ name: storage
|
|
+ vars:
|
|
+ storage_volumes:
|
|
+ - name: foo
|
|
+ type: disk
|
|
+ disks: "{{ unused_disks }}"
|
|
+ mount_point: "{{ mount_location }}"
|
|
+ encryption: false
|
|
+ encryption_password: 'yabbadabbadoo'
|
|
+ - name: unreachable task
|
|
+ fail:
|
|
+ msg: UNREACH
|
|
+ rescue:
|
|
+ - name: Check that we failed in the role
|
|
+ assert:
|
|
+ that:
|
|
+ - ansible_failed_result.msg != 'UNREACH'
|
|
+ msg: "Role has not failed when it should have"
|
|
+
|
|
+ - name: Verify the output of the safe_mode test
|
|
+ assert:
|
|
+ that: "blivet_output.failed and
|
|
+ blivet_output.msg
|
|
+ |regex_search('cannot remove existing
|
|
+ formatting.*in safe mode due to encryption removal')
|
|
+ and not blivet_output.changed"
|
|
+ msg: "Unexpected behavior w/ existing filesystem in safe mode"
|
|
+
|
|
+ - import_tasks: verify-data-preservation.yml
|
|
+
|
|
- name: Remove the encryption layer
|
|
include_role:
|
|
name: storage
|
|
vars:
|
|
+ storage_safe_mode: false
|
|
storage_volumes:
|
|
- name: foo
|
|
type: disk
|
|
@@ -78,10 +115,47 @@
|
|
|
|
- include_tasks: verify-role-results.yml
|
|
|
|
+ - import_tasks: create-test-file.yml
|
|
+
|
|
+ - name: Test for correct handling of safe_mode
|
|
+ block:
|
|
+ - name: Add encryption to the volume
|
|
+ include_role:
|
|
+ name: storage
|
|
+ vars:
|
|
+ storage_volumes:
|
|
+ - name: foo
|
|
+ type: disk
|
|
+ disks: "{{ unused_disks }}"
|
|
+ mount_point: "{{ mount_location }}"
|
|
+ encryption: true
|
|
+ encryption_password: 'yabbadabbadoo'
|
|
+ - name: unreachable task
|
|
+ fail:
|
|
+ msg: UNREACH
|
|
+ rescue:
|
|
+ - name: Check that we failed in the role
|
|
+ assert:
|
|
+ that:
|
|
+ - ansible_failed_result.msg != 'UNREACH'
|
|
+ msg: "Role has not failed when it should have"
|
|
+
|
|
+ - name: Verify the output of the safe_mode test
|
|
+ assert:
|
|
+ that: "blivet_output.failed and
|
|
+ blivet_output.msg
|
|
+ |regex_search('cannot remove existing
|
|
+ formatting.*in safe mode due to adding encryption')
|
|
+ and not blivet_output.changed"
|
|
+ msg: "Unexpected behavior w/ existing filesystem in safe mode"
|
|
+
|
|
+ - import_tasks: verify-data-preservation.yml
|
|
+
|
|
- name: Add encryption to the volume
|
|
include_role:
|
|
name: storage
|
|
vars:
|
|
+ storage_safe_mode: false
|
|
storage_volumes:
|
|
- name: foo
|
|
type: disk
|
|
@@ -102,6 +176,7 @@
|
|
include_role:
|
|
name: storage
|
|
vars:
|
|
+ storage_safe_mode: false
|
|
storage_pools:
|
|
- name: foo
|
|
type: partition
|
|
@@ -135,6 +210,7 @@
|
|
include_role:
|
|
name: storage
|
|
vars:
|
|
+ storage_safe_mode: false
|
|
storage_pools:
|
|
- name: foo
|
|
type: partition
|
|
@@ -149,10 +225,51 @@
|
|
|
|
- include_tasks: verify-role-results.yml
|
|
|
|
+ - import_tasks: create-test-file.yml
|
|
+
|
|
+ - name: Test for correct handling of safe_mode
|
|
+ block:
|
|
+ - name: Remove the encryption layer
|
|
+ include_role:
|
|
+ name: storage
|
|
+ vars:
|
|
+ storage_pools:
|
|
+ - name: foo
|
|
+ type: partition
|
|
+ disks: "{{ unused_disks }}"
|
|
+ volumes:
|
|
+ - name: test1
|
|
+ type: partition
|
|
+ mount_point: "{{ mount_location }}"
|
|
+ size: 4g
|
|
+ encryption: false
|
|
+ encryption_password: 'yabbadabbadoo'
|
|
+ - name: unreachable task
|
|
+ fail:
|
|
+ msg: UNREACH
|
|
+ rescue:
|
|
+ - name: Check that we failed in the role
|
|
+ assert:
|
|
+ that:
|
|
+ - ansible_failed_result.msg != 'UNREACH'
|
|
+ msg: "Role has not failed when it should have"
|
|
+
|
|
+ - name: Verify the output of the safe_mode test
|
|
+ assert:
|
|
+ that: "blivet_output.failed and
|
|
+ blivet_output.msg
|
|
+ |regex_search('cannot remove existing
|
|
+ formatting.*in safe mode due to encryption removal')
|
|
+ and not blivet_output.changed"
|
|
+ msg: "Unexpected behavior w/ existing filesystem in safe mode"
|
|
+
|
|
+ - import_tasks: verify-data-preservation.yml
|
|
+
|
|
- name: Remove the encryption layer
|
|
include_role:
|
|
name: storage
|
|
vars:
|
|
+ storage_safe_mode: false
|
|
storage_pools:
|
|
- name: foo
|
|
type: partition
|
|
@@ -167,6 +284,48 @@
|
|
|
|
- include_tasks: verify-role-results.yml
|
|
|
|
+ - import_tasks: create-test-file.yml
|
|
+
|
|
+ - name: Test for correct handling of safe_mode
|
|
+ block:
|
|
+ - name: Add encryption to the volume
|
|
+ include_role:
|
|
+ name: storage
|
|
+ vars:
|
|
+ storage_pools:
|
|
+ - name: foo
|
|
+ type: partition
|
|
+ disks: "{{ unused_disks }}"
|
|
+ volumes:
|
|
+ - name: test1
|
|
+ type: partition
|
|
+ mount_point: "{{ mount_location }}"
|
|
+ size: 4g
|
|
+ encryption: true
|
|
+ encryption_password: 'yabbadabbadoo'
|
|
+
|
|
+ - name: unreachable task
|
|
+ fail:
|
|
+ msg: UNREACH
|
|
+
|
|
+ rescue:
|
|
+ - name: Check that we failed in the role
|
|
+ assert:
|
|
+ that:
|
|
+ - ansible_failed_result.msg != 'UNREACH'
|
|
+ msg: "Role has not failed when it should have"
|
|
+
|
|
+ - name: Verify the output of the safe_mode test
|
|
+ assert:
|
|
+ that: "blivet_output.failed and
|
|
+ blivet_output.msg
|
|
+ |regex_search('cannot remove existing
|
|
+ formatting.*in safe mode due to adding encryption')
|
|
+ and not blivet_output.changed"
|
|
+ msg: "Unexpected behavior w/ existing volume in safe mode"
|
|
+
|
|
+ - import_tasks: verify-data-preservation.yml
|
|
+
|
|
- name: Test key file handling
|
|
block:
|
|
- name: Create a key file
|
|
@@ -186,6 +345,7 @@
|
|
include_role:
|
|
name: storage
|
|
vars:
|
|
+ storage_safe_mode: false
|
|
storage_pools:
|
|
- name: foo
|
|
type: partition
|
|
@@ -216,6 +376,7 @@
|
|
include_role:
|
|
name: storage
|
|
vars:
|
|
+ storage_safe_mode: false
|
|
storage_pools:
|
|
- name: foo
|
|
type: lvm
|
|
@@ -248,6 +409,7 @@
|
|
include_role:
|
|
name: storage
|
|
vars:
|
|
+ storage_safe_mode: false
|
|
storage_pools:
|
|
- name: foo
|
|
type: lvm
|
|
@@ -264,10 +426,52 @@
|
|
|
|
- include_tasks: verify-role-results.yml
|
|
|
|
+ - import_tasks: create-test-file.yml
|
|
+
|
|
+ - name: Test for correct handling of safe_mode
|
|
+ block:
|
|
+ - name: Remove the encryption layer
|
|
+ include_role:
|
|
+ name: storage
|
|
+ vars:
|
|
+ storage_pools:
|
|
+ - name: foo
|
|
+ type: lvm
|
|
+ disks: "{{ unused_disks }}"
|
|
+ volumes:
|
|
+ - name: test1
|
|
+ mount_point: "{{ mount_location }}"
|
|
+ size: 4g
|
|
+ encryption: false
|
|
+ encryption_password: 'yabbadabbadoo'
|
|
+
|
|
+ - name: unreachable task
|
|
+ fail:
|
|
+ msg: UNREACH
|
|
+
|
|
+ rescue:
|
|
+ - name: Check that we failed in the role
|
|
+ assert:
|
|
+ that:
|
|
+ - ansible_failed_result.msg != 'UNREACH'
|
|
+ msg: "Role has not failed when it should have"
|
|
+
|
|
+ - name: Verify the output of the safe_mode test
|
|
+ assert:
|
|
+ that: "blivet_output.failed and
|
|
+ blivet_output.msg
|
|
+ |regex_search('cannot remove existing
|
|
+ formatting.*in safe mode due to encryption removal')
|
|
+ and not blivet_output.changed"
|
|
+ msg: "Unexpected behavior w/ existing volume in safe mode"
|
|
+
|
|
+ - import_tasks: verify-data-preservation.yml
|
|
+
|
|
- name: Remove the encryption layer
|
|
include_role:
|
|
name: storage
|
|
vars:
|
|
+ storage_safe_mode: false
|
|
storage_pools:
|
|
- name: foo
|
|
type: lvm
|
|
@@ -281,10 +485,52 @@
|
|
|
|
- include_tasks: verify-role-results.yml
|
|
|
|
+ - import_tasks: create-test-file.yml
|
|
+
|
|
+ - name: Test for correct handling of safe_mode
|
|
+ block:
|
|
+ - name: Add encryption to the volume
|
|
+ include_role:
|
|
+ name: storage
|
|
+ vars:
|
|
+ storage_pools:
|
|
+ - name: foo
|
|
+ type: lvm
|
|
+ disks: "{{ unused_disks }}"
|
|
+ volumes:
|
|
+ - name: test1
|
|
+ mount_point: "{{ mount_location }}"
|
|
+ size: 4g
|
|
+ encryption: true
|
|
+ encryption_password: 'yabbadabbadoo'
|
|
+
|
|
+ - name: unreachable task
|
|
+ fail:
|
|
+ msg: UNREACH
|
|
+
|
|
+ rescue:
|
|
+ - name: Check that we failed in the role
|
|
+ assert:
|
|
+ that:
|
|
+ - ansible_failed_result.msg != 'UNREACH'
|
|
+ msg: "Role has not failed when it should have"
|
|
+
|
|
+ - name: Verify the output of the safe_mode test
|
|
+ assert:
|
|
+ that: "blivet_output.failed and
|
|
+ blivet_output.msg
|
|
+ |regex_search('cannot remove existing
|
|
+ formatting.*in safe mode due to adding encryption')
|
|
+ and not blivet_output.changed"
|
|
+ msg: "Unexpected behavior w/ existing volume in safe mode"
|
|
+
|
|
+ - import_tasks: verify-data-preservation.yml
|
|
+
|
|
- name: Add encryption to the volume
|
|
include_role:
|
|
name: storage
|
|
vars:
|
|
+ storage_safe_mode: false
|
|
storage_pools:
|
|
- name: foo
|
|
type: lvm
|
|
diff --git a/tests/tests_luks_pool.yml b/tests/tests_luks_pool.yml
|
|
index b20b806..f44916f 100644
|
|
--- a/tests/tests_luks_pool.yml
|
|
+++ b/tests/tests_luks_pool.yml
|
|
@@ -2,9 +2,10 @@
|
|
- hosts: all
|
|
become: true
|
|
vars:
|
|
- storage_safe_mode: false
|
|
mount_location: '/opt/test1'
|
|
mount_location_2: '/opt/test2'
|
|
+ testfile: "{{ mount_location }}/quux"
|
|
+ testfile_location_2: "{{ mount_location_2 }}/quux"
|
|
volume_size: '5g'
|
|
|
|
tasks:
|
|
@@ -92,10 +93,50 @@
|
|
state: absent
|
|
changed_when: false
|
|
|
|
+ - import_tasks: create-test-file.yml
|
|
+
|
|
+ - name: Test for correct handling of safe_mode
|
|
+ block:
|
|
+ - name: Remove the encryption layer
|
|
+ include_role:
|
|
+ name: storage
|
|
+ vars:
|
|
+ storage_pools:
|
|
+ - name: foo
|
|
+ type: lvm
|
|
+ disks: "{{ unused_disks }}"
|
|
+ encryption: false
|
|
+ encryption_password: 'yabbadabbadoo'
|
|
+ volumes:
|
|
+ - name: test1
|
|
+ mount_point: "{{ mount_location }}"
|
|
+ size: 4g
|
|
+ - name: unreachable task
|
|
+ fail:
|
|
+ msg: UNREACH
|
|
+ rescue:
|
|
+ - name: Check that we failed in the role
|
|
+ assert:
|
|
+ that:
|
|
+ - ansible_failed_result.msg != 'UNREACH'
|
|
+ msg: "Role has not failed when it should have"
|
|
+
|
|
+ - name: Verify the output of the safe_mode test
|
|
+ assert:
|
|
+ that: "blivet_output.failed and
|
|
+ blivet_output.msg
|
|
+ |regex_search('cannot remove and recreate existing
|
|
+ pool.*in safe mode')
|
|
+ and not blivet_output.changed"
|
|
+ msg: "Unexpected behavior w/ existing pool in safe mode"
|
|
+
|
|
+ - import_tasks: verify-data-preservation.yml
|
|
+
|
|
- name: Remove the encryption layer
|
|
include_role:
|
|
name: storage
|
|
vars:
|
|
+ storage_safe_mode: false
|
|
storage_pools:
|
|
- name: foo
|
|
type: lvm
|
|
@@ -109,10 +150,53 @@
|
|
|
|
- include_tasks: verify-role-results.yml
|
|
|
|
- - name: Add encryption to the volume
|
|
+ - import_tasks: create-test-file.yml
|
|
+
|
|
+ - name: Test for correct handling of safe_mode
|
|
+ block:
|
|
+ - name: Add encryption to the pool
|
|
+ include_role:
|
|
+ name: storage
|
|
+ vars:
|
|
+ storage_pools:
|
|
+ - name: foo
|
|
+ type: lvm
|
|
+ disks: "{{ unused_disks }}"
|
|
+ encryption: true
|
|
+ encryption_password: 'yabbadabbadoo'
|
|
+ encryption_luks_version: luks1
|
|
+ encryption_key_size: 512
|
|
+ encryption_cipher: 'serpent-xts-plain64'
|
|
+ volumes:
|
|
+ - name: test1
|
|
+ mount_point: "{{ mount_location }}"
|
|
+ size: 4g
|
|
+ - name: unreachable task
|
|
+ fail:
|
|
+ msg: UNREACH
|
|
+ rescue:
|
|
+ - name: Check that we failed in the role
|
|
+ assert:
|
|
+ that:
|
|
+ - ansible_failed_result.msg != 'UNREACH'
|
|
+ msg: "Role has not failed when it should have"
|
|
+
|
|
+ - name: Verify the output of the safe_mode test
|
|
+ assert:
|
|
+ that: "blivet_output.failed and
|
|
+ blivet_output.msg
|
|
+ |regex_search('cannot remove and recreate existing
|
|
+ pool.*in safe mode')
|
|
+ and not blivet_output.changed"
|
|
+ msg: "Unexpected behavior w/ existing pool in safe mode"
|
|
+
|
|
+ - import_tasks: verify-data-preservation.yml
|
|
+
|
|
+ - name: Add encryption to the pool
|
|
include_role:
|
|
name: storage
|
|
vars:
|
|
+ storage_safe_mode: false
|
|
storage_pools:
|
|
- name: foo
|
|
type: lvm
|
|
@@ -129,6 +213,8 @@
|
|
|
|
- include_tasks: verify-role-results.yml
|
|
|
|
+ - import_tasks: create-test-file.yml
|
|
+
|
|
- name: Change the mountpoint, leaving encryption in place
|
|
include_role:
|
|
name: storage
|
|
@@ -144,6 +230,10 @@
|
|
mount_point: "{{ mount_location_2 }}"
|
|
size: 4g
|
|
|
|
+ - import_tasks: verify-data-preservation.yml
|
|
+ vars:
|
|
+ testfile: "{{ testfile_location_2 }}"
|
|
+
|
|
- include_tasks: verify-role-results.yml
|
|
|
|
- name: Clean up
|
|
diff --git a/tests/verify-data-preservation.yml b/tests/verify-data-preservation.yml
|
|
new file mode 100644
|
|
index 0000000..eed790f
|
|
--- /dev/null
|
|
+++ b/tests/verify-data-preservation.yml
|
|
@@ -0,0 +1,19 @@
|
|
+# Verify that a file still exists and no data loss has occured.
|
|
+# To use:
|
|
+# - set testfile to a path under the mountpoint being tested
|
|
+# - include create-test-file.yml before executing the operation to be
|
|
+# tested
|
|
+# - execute the operation that could potentially result in a loss of
|
|
+# data in the filesystem where testfile is located
|
|
+# - include this file (verify-data-preservation.yml)
|
|
+
|
|
+- 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!"
|