Blame SOURCES/storage-safemode-luks.diff

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