Browse Source

Zap Journals

The is_osd_disk code assumes that the first partition
is the osd journal.  That might not always be the case.
This patch makes that function more general by searching
all partitions on a disk.

Change-Id: I4239ae498b9b6d2d97551d61d1a4f2981f72b88a
Chris Holcombe 2 years ago
parent
commit
573bad86dc
3 changed files with 93 additions and 15 deletions
  1. 79
    10
      ceph/__init__.py
  2. 2
    0
      unit_tests/partx_output
  3. 12
    5
      unit_tests/test_ceph.py

+ 79
- 10
ceph/__init__.py View File

@@ -117,6 +117,42 @@ NETWORK_ADAPTER_SYSCTLS = {
117 117
 }
118 118
 
119 119
 
120
+class Partition(object):
121
+    def __init__(self, name, number, size, start, end, sectors, uuid):
122
+        """
123
+        A block device partition
124
+        :param name: Name of block device
125
+        :param number:  Partition number
126
+        :param size:  Capacity of the device
127
+        :param start:  Starting block
128
+        :param end:  Ending block
129
+        :param sectors:  Number of blocks
130
+        :param uuid:  UUID of the partition
131
+        """
132
+        self.name = name,
133
+        self.number = number
134
+        self.size = size
135
+        self.start = start
136
+        self.end = end
137
+        self.sectors = sectors
138
+        self.uuid = uuid
139
+
140
+    def __str__(self):
141
+        return "number: {} start: {} end: {} sectors: {} size: {} " \
142
+               "name: {} uuid: {}".format(self.number, self.start,
143
+                                          self.end,
144
+                                          self.sectors, self.size,
145
+                                          self.name, self.uuid)
146
+
147
+    def __eq__(self, other):
148
+        if isinstance(other, self.__class__):
149
+            return self.__dict__ == other.__dict__
150
+        return False
151
+
152
+    def __ne__(self, other):
153
+        return not self.__eq__(other)
154
+
155
+
120 156
 def unmounted_disks():
121 157
     """List of unmounted block devices on the current host."""
122 158
     disks = []
@@ -759,9 +795,12 @@ DISK_FORMATS = [
759 795
 ]
760 796
 
761 797
 CEPH_PARTITIONS = [
798
+    '89C57F98-2FE5-4DC0-89C1-5EC00CEFF2BE',  # ceph encrypted disk in creation
799
+    '45B0969E-9B03-4F30-B4C6-5EC00CEFF106',  # ceph encrypted journal
762 800
     '4FBD7E29-9D25-41B8-AFD0-5EC00CEFF05D',  # ceph encrypted osd data
763 801
     '4FBD7E29-9D25-41B8-AFD0-062C0CEFF05D',  # ceph osd data
764 802
     '45B0969E-9B03-4F30-B4C6-B4B80CEFF106',  # ceph osd journal
803
+    '89C57F98-2FE5-4DC0-89C1-F3AD0CEFF2BE',  # ceph disk in creation
765 804
 ]
766 805
 
767 806
 
@@ -872,17 +911,48 @@ def replace_osd(dead_osd_number,
872 911
         log('replace_osd failed with error: ' + e.output)
873 912
 
874 913
 
875
-def is_osd_disk(dev):
914
+def get_partition_list(dev):
915
+    """
916
+    Lists the partitions of a block device
917
+    :param dev: Path to a block device. ex: /dev/sda
918
+    :return: :raise:  Returns a list of Partition objects.
919
+        Raises CalledProcessException if lsblk fails
920
+    """
921
+    partitions_list = []
876 922
     try:
877
-        info = check_output(['sgdisk', '-i', '1', dev])
878
-        info = info.split("\n")  # IGNORE:E1103
879
-        for line in info:
880
-            for ptype in CEPH_PARTITIONS:
881
-                sig = 'Partition GUID code: {}'.format(ptype)
882
-                if line.startswith(sig):
883
-                    return True
923
+        partitions = get_partitions(dev)
924
+        # For each line of output
925
+        for partition in partitions:
926
+            parts = partition.split()
927
+            partitions_list.append(
928
+                Partition(number=parts[0],
929
+                          start=parts[1],
930
+                          end=parts[2],
931
+                          sectors=parts[3],
932
+                          size=parts[4],
933
+                          name=parts[5],
934
+                          uuid=parts[6])
935
+            )
936
+        return partitions_list
884 937
     except subprocess.CalledProcessError:
885
-        pass
938
+        raise
939
+
940
+
941
+def is_osd_disk(dev):
942
+    partitions = get_partition_list(dev)
943
+    for partition in partitions:
944
+        try:
945
+            info = check_output(['sgdisk', '-i', partition.number, dev])
946
+            info = info.split("\n")  # IGNORE:E1103
947
+            for line in info:
948
+                for ptype in CEPH_PARTITIONS:
949
+                    sig = 'Partition GUID code: {}'.format(ptype)
950
+                    if line.startswith(sig):
951
+                        return True
952
+        except subprocess.CalledProcessError as e:
953
+            log("sgdisk inspection of partition {} on {} failed with "
954
+                "error: {}. Skipping".format(partition.minor, dev, e.message),
955
+                level=ERROR)
886 956
     return False
887 957
 
888 958
 
@@ -1923,7 +1993,6 @@ def dirs_need_ownership_update(service):
1923 1993
     # All child directories had the expected ownership
1924 1994
     return False
1925 1995
 
1926
-
1927 1996
 # A dict of valid ceph upgrade paths.  Mapping is old -> new
1928 1997
 UPGRADE_PATHS = {
1929 1998
     'firefly': 'hammer',

+ 2
- 0
unit_tests/partx_output View File

@@ -0,0 +1,2 @@
1
+1 2099200 8377310 6278111 3G ceph\x20data 6e99ac59-1aa3-4812-abd7-9c886a151dd4
2
+2 2048 2099199 2097152 1G ceph\x20journal 0333f202-256c-4867-a85c-3e3c92abd461

+ 12
- 5
unit_tests/test_ceph.py View File

@@ -153,17 +153,17 @@ class CephTestCase(unittest.TestCase):
153 153
 
154 154
     def test_parse_key_with_caps_existing_key(self):
155 155
         expected = "AQCm7aVYQFXXFhAAj0WIeqcag88DKOvY4UKR/g=="
156
-        with_caps = "[client.osd-upgrade]\n"\
157
-            "	key = AQCm7aVYQFXXFhAAj0WIeqcag88DKOvY4UKR/g==\n"\
158
-            "	caps mon = \"allow command \"config-key\";"
156
+        with_caps = "[client.osd-upgrade]\n" \
157
+                    "	key = AQCm7aVYQFXXFhAAj0WIeqcag88DKOvY4UKR/g==\n" \
158
+                    "	caps mon = \"allow command \"config-key\";"
159 159
         key = ceph.parse_key(with_caps)
160 160
         print("key: {}".format(key))
161 161
         self.assertEqual(key, expected)
162 162
 
163 163
     def test_parse_key_without_caps(self):
164 164
         expected = "AQCm7aVYQFXXFhAAj0WIeqcag88DKOvY4UKR/g=="
165
-        without_caps = "[client.osd-upgrade]\n"\
166
-            "	key = AQCm7aVYQFXXFhAAj0WIeqcag88DKOvY4UKR/g=="
165
+        without_caps = "[client.osd-upgrade]\n" \
166
+                       "	key = AQCm7aVYQFXXFhAAj0WIeqcag88DKOvY4UKR/g=="
167 167
         key = ceph.parse_key(without_caps)
168 168
         print("key: {}".format(key))
169 169
         self.assertEqual(key, expected)
@@ -193,6 +193,13 @@ class CephTestCase(unittest.TestCase):
193 193
                 devices = ceph.unmounted_disks()
194 194
                 self.assertEqual(devices, [])
195 195
 
196
+    @mock.patch.object(ceph, 'check_output')
197
+    def test_get_partition_list(self, output):
198
+        with open('unit_tests/partx_output', 'r') as partx_out:
199
+            output.return_value = partx_out.read()
200
+        partition_list = ceph.get_partition_list('/dev/xvdb')
201
+        self.assertEqual(len(partition_list), 2)
202
+
196 203
 
197 204
 class CephVersionTestCase(unittest.TestCase):
198 205
     @mock.patch.object(ceph, 'get_os_codename_install_source')

Loading…
Cancel
Save