+ self.from_trigger = from_trigger
+ self.skip_systemd = False
+
+ def validate_devices(self, json_config):
+ """
+ ``json_config`` is the loaded dictionary coming from the JSON file. It is usually mixed with
+ other non-device items, but for sakes of comparison it doesn't really matter. This method is
+ just making sure that the keys needed exist
+ """
+ devices = json_config.keys()
+ try:
+ objectstore = json_config['type']
+ except KeyError:
+ if {'data', 'journal'}.issubset(set(devices)):
+ logger.warning(
+ '"type" key not found, assuming "filestore" since journal key is present'
+ )
+ objectstore = 'filestore'
+ else:
+ logger.warning(
+ '"type" key not found, assuming "bluestore" since journal key is not present'
+ )
+ objectstore = 'bluestore'
+
+ # Go through all the device combinations that are absolutely required,
+ # raise an error describing what was expected and what was found
+ # otherwise.
+ if objectstore == 'filestore':
+ if {'data', 'journal'}.issubset(set(devices)):
+ return True
+ else:
+ found = [i for i in devices if i in ['data', 'journal']]
+ mlogger.error("Required devices (data, and journal) not present for filestore")
+ mlogger.error('filestore devices found: %s', found)
+ raise RuntimeError('Unable to activate filestore OSD due to missing devices')
+ else:
+ # This is a bit tricky, with newer bluestore we don't need data, older implementations
+ # do (e.g. with ceph-disk). ceph-volume just uses a tmpfs that doesn't require data.
+ if {'block', 'data'}.issubset(set(devices)):
+ return True
+ else:
+ bluestore_devices = ['block.db', 'block.wal', 'block', 'data']
+ found = [i for i in devices if i in bluestore_devices]
+ mlogger.error("Required devices (block and data) not present for bluestore")
+ mlogger.error('bluestore devices found: %s', found)
+ raise RuntimeError('Unable to activate bluestore OSD due to missing devices')
+
+ def get_device(self, uuid):
+ """
+ If a device is encrypted, it will decrypt/open and return the mapper
+ path, if it isn't encrypted it will just return the device found that
+ is mapped to the uuid. This will make it easier for the caller to
+ avoid if/else to check if devices need decrypting
+
+ :param uuid: The partition uuid of the device (PARTUUID)
+ """
+ device = disk.get_device_from_partuuid(uuid)
+
+ # If device is not found, it is fine to return an empty string from the
+ # helper that finds `device`. If it finds anything and it is not
+ # encrypted, just return what was found
+ if not self.is_encrypted or not device:
+ return device
+
+ if self.encryption_type == 'luks':
+ encryption_utils.luks_open(self.dmcrypt_secret, device, uuid)
+ else:
+ encryption_utils.plain_open(self.dmcrypt_secret, device, uuid)
+
+ return '/dev/mapper/%s' % uuid
+
+ def enable_systemd_units(self, osd_id, osd_fsid):
+ """
+ * disables the ceph-disk systemd units to prevent them from running when
+ a UDEV event matches Ceph rules
+ * creates the ``simple`` systemd units to handle the activation and
+ startup of the OSD with ``osd_id`` and ``osd_fsid``
+ * enables the OSD systemd unit and finally starts the OSD.
+ """
+ if not self.from_trigger and not self.skip_systemd:
+ # means it was scanned and now activated directly, so ensure that
+ # ceph-disk units are disabled, and that the `simple` systemd unit
+ # is created and enabled
+
+ # enable the ceph-volume unit for this OSD
+ systemctl.enable_volume(osd_id, osd_fsid, 'simple')
+
+ # disable any/all ceph-disk units
+ systemctl.mask_ceph_disk()
+ terminal.warning(
+ ('All ceph-disk systemd units have been disabled to '
+ 'prevent OSDs getting triggered by UDEV events')
+ )
+ else:
+ terminal.info('Skipping enabling of `simple` systemd unit')
+ terminal.info('Skipping masking of ceph-disk systemd units')
+
+ if not self.skip_systemd:
+ # enable the OSD
+ systemctl.enable_osd(osd_id)
+
+ # start the OSD
+ systemctl.start_osd(osd_id)
+ else:
+ terminal.info(
+ 'Skipping enabling and starting OSD simple systemd unit because --no-systemd was used'
+ )