From ac279adca57c729e9d65492c93665699a1eac5a5 Mon Sep 17 00:00:00 2001 From: Rishabh Dave Date: Thu, 19 Nov 2020 18:36:38 +0530 Subject: [PATCH] ceph-volume: allow listing devices by OSD ID Adds the ability to list devices by OSD IDs, i.e. "ceph-volume lvm list 3" would list all devices under OSD ID 3 (which can be up to 2 and 3 devices under filestore and bluestore OSDs respectively). Fixes: https://tracker.ceph.com/issues/41294 Signed-off-by: Rishabh Dave (cherry picked from commit 0792a396ce61b356ad004ac3dbd96fabed739eac) --- .../ceph_volume/devices/lvm/listing.py | 32 +++++-- .../tests/devices/lvm/test_listing.py | 87 +++++++++++++++++++ 2 files changed, 111 insertions(+), 8 deletions(-) diff --git a/src/ceph-volume/ceph_volume/devices/lvm/listing.py b/src/ceph-volume/ceph_volume/devices/lvm/listing.py index 1ae8489f6fcb6..de19790511bfe 100644 --- a/src/ceph-volume/ceph_volume/devices/lvm/listing.py +++ b/src/ceph-volume/ceph_volume/devices/lvm/listing.py @@ -140,12 +140,7 @@ class List(object): """ return self.create_report(api.get_lvs()) - def single_report(self, device): - """ - Generate a report for a single device. This can be either a logical - volume in the form of vg/lv or a device with an absolute path like - /dev/sda1 or /dev/sda. Returns '{}' to denote failure. - """ + def get_lvs_from_path(self, device): lvs = [] if os.path.isabs(device): # we have a block device @@ -159,13 +154,30 @@ class List(object): lvs = api.get_lvs(filters={'lv_name': lv_name, 'vg_name': vg_name}) - report = self.create_report(lvs) + return lvs + + def single_report(self, arg): + """ + Generate a report for a single device. This can be either a logical + volume in the form of vg/lv, a device with an absolute path like + /dev/sda1 or /dev/sda, or a list of devices under same OSD ID. + + Return value '{}' denotes failure. + """ + if isinstance(arg, int) or arg.isdigit(): + lv = api.get_lvs_from_osd_id(arg) + elif arg[0] == '/': + lv = self.get_lvs_from_path(arg) + else: + lv = [api.get_single_lv(filters={'lv_name': arg.split('/')[1]})] + + report = self.create_report(lv) if not report: # check if device is a non-lvm journals or wal/db for dev_type in ['journal', 'wal', 'db']: lvs = api.get_lvs(tags={ - 'ceph.{}_device'.format(dev_type): device}) + 'ceph.{}_device'.format(dev_type): arg}) if lvs: # just taking the first lv here should work lv = lvs[0] @@ -190,6 +202,10 @@ class List(object): ceph-volume lvm list + List devices under same OSD ID:: + + ceph-volume lvm list + List a particular device, reporting all metadata about it:: ceph-volume lvm list /dev/sda1 diff --git a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_listing.py b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_listing.py index c72b6155cc986..7e4d963c8b450 100644 --- a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_listing.py +++ b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_listing.py @@ -242,6 +242,93 @@ class TestSingleReport(object): assert result['0'][0]['path'] == '/dev/VolGroup/lv' assert result['0'][0]['devices'] == ['/dev/sda1', '/dev/sdb1'] + def test_report_by_osd_id_for_just_block_dev(self, monkeypatch): + tags = 'ceph.osd_id=0,ceph.journal_uuid=x,ceph.type=block' + lvs = [ api.Volume(lv_name='lv1', lv_tags=tags, lv_path='/dev/vg/lv1', + lv_uuid='aaaa', vg_name='vg') + ] + monkeypatch.setattr(lvm.listing.api, 'get_lvs', lambda **kwargs: lvs) + + listing = lvm.listing.List([]) + result = listing.single_report(0) + assert result['0'][0]['name'] == 'lv1' + assert result['0'][0]['lv_tags'] == tags + assert result['0'][0]['lv_path'] == '/dev/vg/lv1' + assert result['0'][0]['vg_name'] == 'vg' + + def test_report_by_osd_id_for_just_data_dev(self, monkeypatch): + tags = 'ceph.osd_id=0,ceph.journal_uuid=x,ceph.type=data' + lvs = [ api.Volume(lv_name='lv1', lv_tags=tags, lv_path='/dev/vg/lv1', + lv_uuid='bbbb', vg_name='vg'), + ] + monkeypatch.setattr(lvm.listing.api, 'get_lvs', lambda **kwargs: lvs) + + listing = lvm.listing.List([]) + result = listing.single_report(0) + assert result['0'][0]['name'] == 'lv1' + assert result['0'][0]['lv_tags'] == tags + assert result['0'][0]['lv_path'] == '/dev/vg/lv1' + assert result['0'][0]['vg_name'] == 'vg' + + def test_report_by_osd_id_for_just_block_wal_and_db_dev(self, monkeypatch): + tags1 = 'ceph.osd_id=0,ceph.journal_uuid=x,ceph.type=block' + tags2 = 'ceph.osd_id=0,ceph.journal_uuid=x,ceph.type=wal' + tags3 = 'ceph.osd_id=0,ceph.journal_uuid=x,ceph.type=db' + lvs = [ api.Volume(lv_name='lv1', lv_tags=tags1, lv_path='/dev/vg/lv1', + lv_uuid='aaaa', vg_name='vg'), + api.Volume(lv_name='lv2', lv_tags=tags2, lv_path='/dev/vg/lv2', + lv_uuid='bbbb', vg_name='vg'), + api.Volume(lv_name='lv3', lv_tags=tags3, lv_path='/dev/vg/lv3', + lv_uuid='cccc', vg_name='vg'), + ] + monkeypatch.setattr(lvm.listing.api, 'get_lvs', lambda **kwargs: lvs) + + listing = lvm.listing.List([]) + result = listing.single_report(0) + assert result['0'][0]['name'] == 'lv1' + assert result['0'][0]['lv_tags'] == tags1 + assert result['0'][0]['lv_path'] == '/dev/vg/lv1' + assert result['0'][0]['vg_name'] == 'vg' + assert result['0'][1]['name'] == 'lv2' + assert result['0'][1]['lv_tags'] == tags2 + assert result['0'][1]['lv_path'] == '/dev/vg/lv2' + assert result['0'][1]['vg_name'] == 'vg' + assert result['0'][2]['name'] == 'lv3' + assert result['0'][2]['lv_tags'] == tags3 + assert result['0'][2]['lv_path'] == '/dev/vg/lv3' + assert result['0'][2]['vg_name'] == 'vg' + + + def test_report_by_osd_id_for_data_and_journal_dev(self, monkeypatch): + tags1 = 'ceph.osd_id=0,ceph.journal_uuid=x,ceph.type=data' + tags2 = 'ceph.osd_id=0,ceph.journal_uuid=x,ceph.type=journal' + lvs = [ api.Volume(lv_name='lv1', lv_tags=tags1, lv_path='/dev/vg/lv1', + lv_uuid='aaaa', vg_name='vg'), + api.Volume(lv_name='lv2', lv_tags=tags2, lv_path='/dev/vg/lv2', + lv_uuid='bbbb', vg_name='vg'), + ] + monkeypatch.setattr(lvm.listing.api, 'get_lvs', lambda **kwargs: lvs) + + listing = lvm.listing.List([]) + result = listing.single_report(0) + assert result['0'][0]['name'] == 'lv1' + assert result['0'][0]['lv_tags'] == tags1 + assert result['0'][0]['lv_path'] == '/dev/vg/lv1' + assert result['0'][0]['vg_name'] == 'vg' + assert result['0'][1]['name'] == 'lv2' + assert result['0'][1]['lv_tags'] == tags2 + assert result['0'][1]['lv_path'] == '/dev/vg/lv2' + assert result['0'][1]['vg_name'] == 'vg' + + def test_report_by_nonexistent_osd_id(self, monkeypatch): + lv = api.Volume(lv_name='lv', lv_tags={}, lv_path='/dev/VolGroup/lv', + vg_name='VolGroup') + monkeypatch.setattr(lvm.listing.api, 'get_lvs', lambda **kwargs: + [lv]) + + result = lvm.listing.List([]).single_report('1') + assert result == {} + def test_report_a_ceph_lv_with_no_matching_devices(self, monkeypatch): tags = 'ceph.osd_id=0,ceph.type=data' lv = api.Volume(lv_name='lv', vg_name='VolGroup', lv_uuid='aaaa', -- 2.39.5