summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2018-07-17 14:20:12 +0000
committerGerrit Code Review <review@openstack.org>2018-07-17 14:20:12 +0000
commitfc4a4604ba87047e6c2a4b8ebf7cfed7a60a5eaa (patch)
treead46b425ae7b12758158783819a7de72a7ed3d29
parent43d868dc21d4a29127578e3b9f96d365a684ce43 (diff)
parente340cc851c0d409ae20c59bcf9e2199e1e0a277f (diff)
Merge "ignore devices that have already been processed"
-rwxr-xr-xactions/zap_disk.py5
-rwxr-xr-xhooks/ceph_hooks.py12
-rw-r--r--lib/ceph/broker.py7
-rw-r--r--lib/ceph/utils.py50
-rw-r--r--unit_tests/test_actions_zap_disk.py43
5 files changed, 111 insertions, 6 deletions
diff --git a/actions/zap_disk.py b/actions/zap_disk.py
index aae9896..550e70c 100755
--- a/actions/zap_disk.py
+++ b/actions/zap_disk.py
@@ -28,6 +28,7 @@ from charmhelpers.contrib.storage.linux.utils import (
28) 28)
29from charmhelpers.core.unitdata import kv 29from charmhelpers.core.unitdata import kv
30from ceph.utils import is_active_bluestore_device 30from ceph.utils import is_active_bluestore_device
31from ceph.utils import is_mapped_luks_device
31 32
32 33
33def get_devices(): 34def get_devices():
@@ -53,7 +54,9 @@ def zap():
53 for device in devices: 54 for device in devices:
54 if not is_block_device(device): 55 if not is_block_device(device):
55 not_block_devices.append(device) 56 not_block_devices.append(device)
56 if is_device_mounted(device) or is_active_bluestore_device(device): 57 if (is_device_mounted(device) or
58 is_active_bluestore_device(device) or
59 is_mapped_luks_device(device)):
57 failed_devices.append(device) 60 failed_devices.append(device)
58 61
59 if failed_devices or not_block_devices: 62 if failed_devices or not_block_devices:
diff --git a/hooks/ceph_hooks.py b/hooks/ceph_hooks.py
index 47379f0..0eca970 100755
--- a/hooks/ceph_hooks.py
+++ b/hooks/ceph_hooks.py
@@ -93,6 +93,8 @@ from charmhelpers.contrib.storage.linux.utils import (
93from charmhelpers.contrib.charmsupport import nrpe 93from charmhelpers.contrib.charmsupport import nrpe
94from charmhelpers.contrib.hardening.harden import harden 94from charmhelpers.contrib.hardening.harden import harden
95 95
96from charmhelpers.core.unitdata import kv
97
96import charmhelpers.contrib.openstack.vaultlocker as vaultlocker 98import charmhelpers.contrib.openstack.vaultlocker as vaultlocker
97 99
98hooks = Hooks() 100hooks = Hooks()
@@ -426,6 +428,15 @@ def prepare_disks_and_activate():
426 428
427 # pre-flight check of eligible device pristinity 429 # pre-flight check of eligible device pristinity
428 devices = get_devices() 430 devices = get_devices()
431
432 # if a device has been previously touched we need to consider it as
433 # non-pristine. If it needs to be re-processed it has to be zapped
434 # via the respective action which also clears the unitdata entry.
435 db = kv()
436 touched_devices = db.get('osd-devices', [])
437 devices = [dev for dev in devices if dev not in touched_devices]
438 log('Skipping osd devices previously processed by this unit: {}'
439 .format(touched_devices))
429 # filter osd-devices that are file system paths 440 # filter osd-devices that are file system paths
430 devices = [dev for dev in devices if dev.startswith('/dev')] 441 devices = [dev for dev in devices if dev.startswith('/dev')]
431 # filter osd-devices that does not exist on this unit 442 # filter osd-devices that does not exist on this unit
@@ -435,6 +446,7 @@ def prepare_disks_and_activate():
435 # filter osd-devices that are active bluestore devices 446 # filter osd-devices that are active bluestore devices
436 devices = [dev for dev in devices 447 devices = [dev for dev in devices
437 if not ceph.is_active_bluestore_device(dev)] 448 if not ceph.is_active_bluestore_device(dev)]
449
438 log('Checking for pristine devices: "{}"'.format(devices), level=DEBUG) 450 log('Checking for pristine devices: "{}"'.format(devices), level=DEBUG)
439 if not all(ceph.is_pristine_disk(dev) for dev in devices): 451 if not all(ceph.is_pristine_disk(dev) for dev in devices):
440 status_set('blocked', 452 status_set('blocked',
diff --git a/lib/ceph/broker.py b/lib/ceph/broker.py
index 0b6d3e2..3e857d2 100644
--- a/lib/ceph/broker.py
+++ b/lib/ceph/broker.py
@@ -81,6 +81,10 @@ POOL_KEYS = {
81 "cache_min_flush_age": [int], 81 "cache_min_flush_age": [int],
82 "cache_min_evict_age": [int], 82 "cache_min_evict_age": [int],
83 "fast_read": [bool], 83 "fast_read": [bool],
84 "allow_ec_overwrites": [bool],
85 "compression_mode": [str, ["none", "passive", "aggressive", "force"]],
86 "compression_algorithm": [str, ["lz4", "snappy", "zlib", "zstd"]],
87 "compression_required_ratio": [float, [0.0, 1.0]],
84} 88}
85 89
86CEPH_BUCKET_TYPES = [ 90CEPH_BUCKET_TYPES = [
@@ -251,7 +255,8 @@ def pool_permission_list_for_service(service):
251 for prefix in prefixes: 255 for prefix in prefixes:
252 permissions.append("allow {} object_prefix {}".format(permission, 256 permissions.append("allow {} object_prefix {}".format(permission,
253 prefix)) 257 prefix))
254 return ["mon", "allow r", "osd", ', '.join(permissions)] 258 return ['mon', 'allow r, allow command "osd blacklist"',
259 'osd', ', '.join(permissions)]
255 260
256 261
257def get_service_groups(service, namespace=None): 262def get_service_groups(service, namespace=None):
diff --git a/lib/ceph/utils.py b/lib/ceph/utils.py
index 5ff970b..6d039cd 100644
--- a/lib/ceph/utils.py
+++ b/lib/ceph/utils.py
@@ -1096,7 +1096,8 @@ def get_mds_bootstrap_key():
1096 1096
1097 1097
1098_default_caps = collections.OrderedDict([ 1098_default_caps = collections.OrderedDict([
1099 ('mon', ['allow r']), 1099 ('mon', ['allow r',
1100 'allow command "osd blacklist"']),
1100 ('osd', ['allow rwx']), 1101 ('osd', ['allow rwx']),
1101]) 1102])
1102 1103
@@ -1163,6 +1164,7 @@ def get_named_key(name, caps=None, pool_list=None):
1163 :param caps: dict of cephx capabilities 1164 :param caps: dict of cephx capabilities
1164 :returns: Returns a cephx key 1165 :returns: Returns a cephx key
1165 """ 1166 """
1167 key_name = 'client.{}'.format(name)
1166 try: 1168 try:
1167 # Does the key already exist? 1169 # Does the key already exist?
1168 output = str(subprocess.check_output( 1170 output = str(subprocess.check_output(
@@ -1177,8 +1179,14 @@ def get_named_key(name, caps=None, pool_list=None):
1177 ), 1179 ),
1178 'auth', 1180 'auth',
1179 'get', 1181 'get',
1180 'client.{}'.format(name), 1182 key_name,
1181 ]).decode('UTF-8')).strip() 1183 ]).decode('UTF-8')).strip()
1184 # NOTE(jamespage);
1185 # Apply any changes to key capabilities, dealing with
1186 # upgrades which requires new caps for operation.
1187 upgrade_key_caps(key_name,
1188 caps or _default_caps,
1189 pool_list)
1182 return parse_key(output) 1190 return parse_key(output)
1183 except subprocess.CalledProcessError: 1191 except subprocess.CalledProcessError:
1184 # Couldn't get the key, time to create it! 1192 # Couldn't get the key, time to create it!
@@ -1194,7 +1202,7 @@ def get_named_key(name, caps=None, pool_list=None):
1194 '/var/lib/ceph/mon/ceph-{}/keyring'.format( 1202 '/var/lib/ceph/mon/ceph-{}/keyring'.format(
1195 socket.gethostname() 1203 socket.gethostname()
1196 ), 1204 ),
1197 'auth', 'get-or-create', 'client.{}'.format(name), 1205 'auth', 'get-or-create', key_name,
1198 ] 1206 ]
1199 # Add capabilities 1207 # Add capabilities
1200 for subsystem, subcaps in caps.items(): 1208 for subsystem, subcaps in caps.items():
@@ -1213,7 +1221,7 @@ def get_named_key(name, caps=None, pool_list=None):
1213 .strip()) # IGNORE:E1103 1221 .strip()) # IGNORE:E1103
1214 1222
1215 1223
1216def upgrade_key_caps(key, caps): 1224def upgrade_key_caps(key, caps, pool_list=None):
1217 """ Upgrade key to have capabilities caps """ 1225 """ Upgrade key to have capabilities caps """
1218 if not is_leader(): 1226 if not is_leader():
1219 # Not the MON leader OR not clustered 1227 # Not the MON leader OR not clustered
@@ -1222,6 +1230,12 @@ def upgrade_key_caps(key, caps):
1222 "sudo", "-u", ceph_user(), 'ceph', 'auth', 'caps', key 1230 "sudo", "-u", ceph_user(), 'ceph', 'auth', 'caps', key
1223 ] 1231 ]
1224 for subsystem, subcaps in caps.items(): 1232 for subsystem, subcaps in caps.items():
1233 if subsystem == 'osd':
1234 if pool_list:
1235 # This will output a string similar to:
1236 # "pool=rgw pool=rbd pool=something"
1237 pools = " ".join(['pool={0}'.format(i) for i in pool_list])
1238 subcaps[0] = subcaps[0] + " " + pools
1225 cmd.extend([subsystem, '; '.join(subcaps)]) 1239 cmd.extend([subsystem, '; '.join(subcaps)])
1226 subprocess.check_call(cmd) 1240 subprocess.check_call(cmd)
1227 1241
@@ -1453,6 +1467,11 @@ def osdize_dev(dev, osd_format, osd_journal, ignore_errors=False,
1453 ' skipping.'.format(dev)) 1467 ' skipping.'.format(dev))
1454 return 1468 return
1455 1469
1470 if is_mapped_luks_device(dev):
1471 log('{} is a mapped LUKS device,'
1472 ' skipping.'.format(dev))
1473 return
1474
1456 if cmp_pkgrevno('ceph', '12.2.4') >= 0: 1475 if cmp_pkgrevno('ceph', '12.2.4') >= 0:
1457 cmd = _ceph_volume(dev, 1476 cmd = _ceph_volume(dev,
1458 osd_journal, 1477 osd_journal,
@@ -1664,6 +1683,29 @@ def is_active_bluestore_device(dev):
1664 return False 1683 return False
1665 1684
1666 1685
1686def is_luks_device(dev):
1687 """
1688 Determine if dev is a LUKS-formatted block device.
1689
1690 :param: dev: A full path to a block device to check for LUKS header
1691 presence
1692 :returns: boolean: indicates whether a device is used based on LUKS header.
1693 """
1694 return True if _luks_uuid(dev) else False
1695
1696
1697def is_mapped_luks_device(dev):
1698 """
1699 Determine if dev is a mapped LUKS device
1700 :param: dev: A full path to a block device to be checked
1701 :returns: boolean: indicates whether a device is mapped
1702 """
1703 _, dirs, _ = next(os.walk('/sys/class/block/{}/holders/'
1704 .format(os.path.basename(dev))))
1705 is_held = len(dirs) > 0
1706 return is_held and is_luks_device(dev)
1707
1708
1667def get_conf(variable): 1709def get_conf(variable):
1668 """ 1710 """
1669 Get the value of the given configuration variable from the 1711 Get the value of the given configuration variable from the
diff --git a/unit_tests/test_actions_zap_disk.py b/unit_tests/test_actions_zap_disk.py
index 47f71e7..61266e3 100644
--- a/unit_tests/test_actions_zap_disk.py
+++ b/unit_tests/test_actions_zap_disk.py
@@ -26,10 +26,12 @@ class ZapDiskActionTests(CharmTestCase):
26 'is_block_device', 26 'is_block_device',
27 'is_device_mounted', 27 'is_device_mounted',
28 'is_active_bluestore_device', 28 'is_active_bluestore_device',
29 'is_mapped_luks_device',
29 'kv']) 30 'kv'])
30 self.is_device_mounted.return_value = False 31 self.is_device_mounted.return_value = False
31 self.is_block_device.return_value = True 32 self.is_block_device.return_value = True
32 self.is_active_bluestore_device.return_value = False 33 self.is_active_bluestore_device.return_value = False
34 self.is_mapped_luks_device.return_value = False
33 self.kv.return_value = self.kv 35 self.kv.return_value = self.kv
34 self.hookenv.local_unit.return_value = "ceph-osd-test/0" 36 self.hookenv.local_unit.return_value = "ceph-osd-test/0"
35 37
@@ -127,3 +129,44 @@ class ZapDiskActionTests(CharmTestCase):
127 _zap_disk.assert_not_called() 129 _zap_disk.assert_not_called()
128 self.hookenv.action_fail.assert_called_with( 130 self.hookenv.action_fail.assert_called_with(
129 "1 devices are mounted: /dev/vdb") 131 "1 devices are mounted: /dev/vdb")
132
133 @mock.patch.object(zap_disk, 'zap_disk')
134 def test_wont_zap__mapped_luks_device(self, _zap_disk):
135 """Will not zap a disk that has a LUKS header"""
136 def side_effect(arg):
137 return {
138 'devices': '/dev/vdb',
139 'i-really-mean-it': True,
140 }.get(arg)
141 self.hookenv.action_get.side_effect = side_effect
142 self.is_active_bluestore_device.return_value = False
143 self.is_mapped_luks_device.return_value = True
144 zap_disk.zap()
145 _zap_disk.assert_not_called()
146 self.hookenv.action_fail.assert_called_with(
147 "1 devices are mounted: /dev/vdb")
148
149 @mock.patch.object(zap_disk, 'zap_disk')
150 def test_zap_luks_not_mapped(self, _zap_disk):
151 """Will zap disk with extra config set"""
152 def side_effect(arg):
153 return {
154 'devices': '/dev/vdb',
155 'i-really-mean-it': True,
156 }.get(arg)
157
158 self.is_active_bluestore_device.return_value = False
159 self.is_mapped_luks_device.return_value = False
160
161 self.hookenv.action_get.side_effect = side_effect
162 self.kv.get.return_value = ['/dev/vdb', '/dev/vdz']
163 zap_disk.zap()
164 _zap_disk.assert_called_with('/dev/vdb')
165 self.kv.get.assert_called_with('osd-devices', [])
166 self.kv.set.assert_called_with('osd-devices', ['/dev/vdz'])
167 self.hookenv.action_set.assert_called_with({
168 'message': "1 disk(s) have been zapped, to use "
169 "them as OSDs, run: \njuju "
170 "run-action ceph-osd-test/0 add-disk "
171 "osd-devices=\"/dev/vdb\""
172 })