From: Guillaume Abrioux Date: Tue, 4 Jul 2023 12:47:59 +0000 (+0000) Subject: ceph-volume: add objectstore unit tests X-Git-Tag: v19.1.1~207^2~2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=faffd26ed3685cabb0d2adb127b0abb074d1f00a;p=ceph.git ceph-volume: add objectstore unit tests This add unit tests in order to cover the code present in `./objectstore/` This also updates current unit tests with respect to the recent changes and fixes some tests that were already broken. Signed-off-by: Guillaume Abrioux (cherry picked from commit f06dad9bf93dd1671419932a1853b963c39d229d) --- diff --git a/src/ceph-volume/ceph_volume/objectstore/lvmbluestore.py b/src/ceph-volume/ceph_volume/objectstore/lvmbluestore.py index a76502e3bffc..5dc46361e92e 100644 --- a/src/ceph-volume/ceph_volume/objectstore/lvmbluestore.py +++ b/src/ceph-volume/ceph_volume/objectstore/lvmbluestore.py @@ -293,6 +293,7 @@ class LvmBlueStore(BlueStore): Return a path if possible, failing to do that a ``None``, since some of these devices are optional. """ + # TODO(guits): this should be moved in a new function get_device_uuid_from_lv() osd_block_lv = None for lv in osd_lvs: if lv.tags.get('ceph.type') == 'block': diff --git a/src/ceph-volume/ceph_volume/tests/api/test_lvm.py b/src/ceph-volume/ceph_volume/tests/api/test_lvm.py index 139328b4a0d5..9ad2f701f129 100644 --- a/src/ceph-volume/ceph_volume/tests/api/test_lvm.py +++ b/src/ceph-volume/ceph_volume/tests/api/test_lvm.py @@ -782,7 +782,7 @@ class TestGetLVs(object): class TestGetSinglePV(object): - @patch('ceph_volume.devices.lvm.prepare.api.get_pvs') + @patch('ceph_volume.api.lvm.get_pvs') def test_get_single_pv_multiple_matches_raises_runtimeerror(self, m_get_pvs): fake_pvs = [] fake_pvs.append(api.PVolume(pv_name='/dev/sda', pv_tags={})) @@ -794,14 +794,14 @@ class TestGetSinglePV(object): api.get_single_pv() assert "matched more than 1 PV present on this host." in str(e.value) - @patch('ceph_volume.devices.lvm.prepare.api.get_pvs') + @patch('ceph_volume.api.lvm.get_pvs') def test_get_single_pv_no_match_returns_none(self, m_get_pvs): m_get_pvs.return_value = [] pv = api.get_single_pv() assert pv == None - @patch('ceph_volume.devices.lvm.prepare.api.get_pvs') + @patch('ceph_volume.api.lvm.get_pvs') def test_get_single_pv_one_match(self, m_get_pvs): fake_pvs = [] fake_pvs.append(api.PVolume(pv_name='/dev/sda', pv_tags={})) @@ -815,7 +815,7 @@ class TestGetSinglePV(object): class TestGetSingleVG(object): - @patch('ceph_volume.devices.lvm.prepare.api.get_vgs') + @patch('ceph_volume.api.lvm.get_vgs') def test_get_single_vg_multiple_matches_raises_runtimeerror(self, m_get_vgs): fake_vgs = [] fake_vgs.append(api.VolumeGroup(vg_name='vg1')) @@ -827,14 +827,14 @@ class TestGetSingleVG(object): api.get_single_vg() assert "matched more than 1 VG present on this host." in str(e.value) - @patch('ceph_volume.devices.lvm.prepare.api.get_vgs') + @patch('ceph_volume.api.lvm.get_vgs') def test_get_single_vg_no_match_returns_none(self, m_get_vgs): m_get_vgs.return_value = [] vg = api.get_single_vg() assert vg == None - @patch('ceph_volume.devices.lvm.prepare.api.get_vgs') + @patch('ceph_volume.api.lvm.get_vgs') def test_get_single_vg_one_match(self, m_get_vgs): fake_vgs = [] fake_vgs.append(api.VolumeGroup(vg_name='vg1')) @@ -847,7 +847,7 @@ class TestGetSingleVG(object): class TestGetSingleLV(object): - @patch('ceph_volume.devices.lvm.prepare.api.get_lvs') + @patch('ceph_volume.api.lvm.get_lvs') def test_get_single_lv_multiple_matches_raises_runtimeerror(self, m_get_lvs): fake_lvs = [] fake_lvs.append(api.Volume(lv_name='lv1', @@ -866,14 +866,14 @@ class TestGetSingleLV(object): api.get_single_lv() assert "matched more than 1 LV present on this host" in str(e.value) - @patch('ceph_volume.devices.lvm.prepare.api.get_lvs') + @patch('ceph_volume.api.lvm.get_lvs') def test_get_single_lv_no_match_returns_none(self, m_get_lvs): m_get_lvs.return_value = [] lv = api.get_single_lv() assert lv == None - @patch('ceph_volume.devices.lvm.prepare.api.get_lvs') + @patch('ceph_volume.api.lvm.get_lvs') def test_get_single_lv_one_match(self, m_get_lvs): fake_lvs = [] fake_lvs.append(api.Volume(lv_name='lv1', lv_path='/dev/vg1/lv1', vg_name='vg1', lv_tags='', lv_uuid='fake-uuid')) diff --git a/src/ceph-volume/ceph_volume/tests/conftest.py b/src/ceph-volume/ceph_volume/tests/conftest.py index 7a7c57d9721d..4a6820852efb 100644 --- a/src/ceph-volume/ceph_volume/tests/conftest.py +++ b/src/ceph-volume/ceph_volume/tests/conftest.py @@ -5,7 +5,7 @@ from ceph_volume.api import lvm from ceph_volume.util import disk from ceph_volume.util import device from ceph_volume.util.constants import ceph_disk_guids -from ceph_volume import conf, configuration +from ceph_volume import conf, configuration, objectstore class Capture(object): @@ -36,6 +36,16 @@ class Factory(object): def factory(): return Factory +def objectstore_bluestore_factory(**kw): + o = objectstore.bluestore.BlueStore([]) + for k, v in kw.items(): + setattr(o, k, v) + return o + +@pytest.fixture +def objectstore_bluestore(): + return objectstore_bluestore_factory + @pytest.fixture def capture(): @@ -58,30 +68,78 @@ def mock_lv_device_generator(): return dev return mock_lv -def mock_device(): +def mock_device(name='foo', + vg_name='vg_foo', + vg_size=None, + lv_name='lv_foo', + lv_size=None, + path='foo', + lv_path='', + number_lvs=0): dev = create_autospec(device.Device) - dev.path = '/dev/foo' - dev.vg_name = 'vg_foo' - dev.lv_name = 'lv_foo' + if vg_size is None: + dev.vg_size = [21474836480] + if lv_size is None: + lv_size = dev.vg_size + dev.lv_size = lv_size + dev.path = f'/dev/{path}' + dev.vg_name = f'{vg_name}' + dev.lv_name = f'{lv_name}' + dev.lv_path = lv_path if lv_path else f'/dev/{dev.vg_name}/{dev.lv_name}' dev.symlink = None dev.vgs = [lvm.VolumeGroup(vg_name=dev.vg_name, lv_name=dev.lv_name)] dev.available_lvm = True - dev.vg_size = [21474836480] dev.vg_free = dev.vg_size dev.lvs = [] + for n in range(0, number_lvs): + dev.lvs.append(lvm.Volume(vg_name=f'{dev.vg_name}{n}', + lv_name=f'{dev.lv_name}-{n}', + lv_path=f'{dev.lv_path}-{n}', + lv_size=dev.lv_size, + lv_tags='')) + dev.is_device = True return dev @pytest.fixture(params=range(1,4)) def mock_devices_available(request): ret = [] - for n in range(request.param): - dev = mock_device() - # after v15.2.8, a single VG is created for each PV - dev.vg_name = f'vg_foo_{n}' + for n in range(1, request.param+1): + # dev = mock_device(suffix=str(n), vg_name=f'vg_foo_{n}', lv_name='') + dev = mock_device(vg_name=f'vg_foo_{n}', lv_name='') dev.vgs = [lvm.VolumeGroup(vg_name=dev.vg_name, lv_name=dev.lv_name)] ret.append(dev) return ret +@pytest.fixture(params=range(2,5)) +def mock_devices_available_multi_pvs_per_vg(request): + ret = [] + number_lvs = 1 + # for n in range(0, 2): + for n in range(0, request.param): + if n == request.param - 1: + number_lvs = 2 + dev = mock_device(path=f'foo{str(n)}', + vg_name='vg_foo', + lv_name=f'lv_foo{str(n)}', + lv_size=[21474836480], + number_lvs=number_lvs) + # after v15.2.8, a single VG is created for each PV + dev.vgs = [lvm.VolumeGroup(vg_name=dev.vg_name, + pv_name=dev.path, + pv_count=request.param)] + ret.append(dev) + return ret + +# @pytest.fixture(params=range(1,4)) +# def mock_devices_available_multi_pvs_per_vg(request): +# ret = [] +# for n in range(1, request.param+1): +# dev = mock_device(suffix=str(n), vg_name=f'vg_foo', lv_name='') +# # after v15.2.8, a single VG is created for each PV +# dev.vgs = [lvm.VolumeGroup(vg_name=dev.vg_name, lv_name=dev.lv_name)] +# ret.append(dev) +# return ret + @pytest.fixture def mock_device_generator(): return mock_device @@ -323,3 +381,117 @@ def fake_filesystem(fs): fs.create_dir('/sys/block/sda/queue') fs.create_dir('/sys/block/rbd0') yield fs + +@pytest.fixture +def key_size(monkeypatch): + monkeypatch.setattr("ceph_volume.util.encryption.get_key_size_from_conf", lambda: 512) + +lvm_direct_report_data = { + '1': [{ + 'lv_tags': 'ceph.block_device=/dev/ceph-40bc7bd7-4aee-483e-ba95-89a64bc8a4fd/osd-block-824f7edf-371f-4b75-9231-4ab62a32d5c0,ceph.block_uuid=kS7zXI-bpmu-3ciB-0rVY-d08b-gWDf-Y9oums,ceph.cephx_lockbox_secret=,ceph.cluster_fsid=7dccab18-14cf-11ee-837b-5254008f8ca5,ceph.cluster_name=ceph,ceph.crush_device_class=,ceph.db_device=/dev/ceph-73d6d4db-6528-48f2-a4e2-1c82bc87a9ac/osd-db-b82d920d-be3c-4e4d-ba64-18f7e8445892,ceph.db_uuid=Kuvi0U-05vW-sETB-QiNW-lpaK-XBfD-82eQWw,ceph.encrypted=0,ceph.osd_fsid=824f7edf-371f-4b75-9231-4ab62a32d5c0,ceph.osd_id=1,ceph.osdspec_affinity=,ceph.type=block,ceph.vdo=0', + 'lv_path': '/dev/ceph-40bc7bd7-4aee-483e-ba95-89a64bc8a4fd/osd-block-824f7edf-371f-4b75-9231-4ab62a32d5c0', + 'lv_name': 'osd-block-824f7edf-371f-4b75-9231-4ab62a32d5c0', + 'vg_name': 'ceph-40bc7bd7-4aee-483e-ba95-89a64bc8a4fd', + 'lv_uuid': 'kS7zXI-bpmu-3ciB-0rVY-d08b-gWDf-Y9oums', + 'lv_size': '214744170496', + 'tags': { + 'ceph.block_device': '/dev/ceph-40bc7bd7-4aee-483e-ba95-89a64bc8a4fd/osd-block-824f7edf-371f-4b75-9231-4ab62a32d5c0', + 'ceph.block_uuid': 'kS7zXI-bpmu-3ciB-0rVY-d08b-gWDf-Y9oums', + 'ceph.cephx_lockbox_secret': '', + 'ceph.cluster_fsid': '7dccab18-14cf-11ee-837b-5254008f8ca5', + 'ceph.cluster_name': 'ceph', + 'ceph.crush_device_class': '', + 'ceph.db_device': '/dev/ceph-73d6d4db-6528-48f2-a4e2-1c82bc87a9ac/osd-db-b82d920d-be3c-4e4d-ba64-18f7e8445892', + 'ceph.db_uuid': 'Kuvi0U-05vW-sETB-QiNW-lpaK-XBfD-82eQWw', + 'ceph.encrypted': '0', + 'ceph.osd_fsid': '824f7edf-371f-4b75-9231-4ab62a32d5c0', + 'ceph.osd_id': '1', + 'ceph.osdspec_affinity': '', + 'ceph.type': 'block', + 'ceph.vdo': '0' + }, + 'name': 'osd-block-824f7edf-371f-4b75-9231-4ab62a32d5c0', + 'type': 'block', + 'path': '/dev/ceph-40bc7bd7-4aee-483e-ba95-89a64bc8a4fd/osd-block-824f7edf-371f-4b75-9231-4ab62a32d5c0', + 'devices': ['/dev/vdc'] + }, { + 'lv_tags': 'ceph.block_device=/dev/ceph-40bc7bd7-4aee-483e-ba95-89a64bc8a4fd/osd-block-824f7edf-371f-4b75-9231-4ab62a32d5c0,ceph.block_uuid=kS7zXI-bpmu-3ciB-0rVY-d08b-gWDf-Y9oums,ceph.cephx_lockbox_secret=,ceph.cluster_fsid=7dccab18-14cf-11ee-837b-5254008f8ca5,ceph.cluster_name=ceph,ceph.crush_device_class=,ceph.db_device=/dev/ceph-73d6d4db-6528-48f2-a4e2-1c82bc87a9ac/osd-db-b82d920d-be3c-4e4d-ba64-18f7e8445892,ceph.db_uuid=Kuvi0U-05vW-sETB-QiNW-lpaK-XBfD-82eQWw,ceph.encrypted=0,ceph.osd_fsid=824f7edf-371f-4b75-9231-4ab62a32d5c0,ceph.osd_id=1,ceph.osdspec_affinity=,ceph.type=db,ceph.vdo=0', + 'lv_path': '/dev/ceph-73d6d4db-6528-48f2-a4e2-1c82bc87a9ac/osd-db-b82d920d-be3c-4e4d-ba64-18f7e8445892', + 'lv_name': 'osd-db-b82d920d-be3c-4e4d-ba64-18f7e8445892', + 'vg_name': 'ceph-73d6d4db-6528-48f2-a4e2-1c82bc87a9ac', + 'lv_uuid': 'Kuvi0U-05vW-sETB-QiNW-lpaK-XBfD-82eQWw', + 'lv_size': '214744170496', + 'tags': { + 'ceph.block_device': '/dev/ceph-40bc7bd7-4aee-483e-ba95-89a64bc8a4fd/osd-block-824f7edf-371f-4b75-9231-4ab62a32d5c0', + 'ceph.block_uuid': 'kS7zXI-bpmu-3ciB-0rVY-d08b-gWDf-Y9oums', + 'ceph.cephx_lockbox_secret': '', + 'ceph.cluster_fsid': '7dccab18-14cf-11ee-837b-5254008f8ca5', + 'ceph.cluster_name': 'ceph', + 'ceph.crush_device_class': '', + 'ceph.db_device': '/dev/ceph-73d6d4db-6528-48f2-a4e2-1c82bc87a9ac/osd-db-b82d920d-be3c-4e4d-ba64-18f7e8445892', + 'ceph.db_uuid': 'Kuvi0U-05vW-sETB-QiNW-lpaK-XBfD-82eQWw', + 'ceph.encrypted': '0', + 'ceph.osd_fsid': '824f7edf-371f-4b75-9231-4ab62a32d5c0', + 'ceph.osd_id': '1', + 'ceph.osdspec_affinity': '', + 'ceph.type': 'db', + 'ceph.vdo': '0' + }, + 'name': 'osd-db-b82d920d-be3c-4e4d-ba64-18f7e8445892', + 'type': 'db', + 'path': '/dev/ceph-73d6d4db-6528-48f2-a4e2-1c82bc87a9ac/osd-db-b82d920d-be3c-4e4d-ba64-18f7e8445892', + 'devices': ['/dev/vdd'] + }], + '0': [{ + 'lv_tags': 'ceph.block_device=/dev/ceph-e34cc3f5-a70d-49df-82b3-46bcbd63d4b0/osd-block-a0e07c5b-bee1-4ea2-ae07-cb89deda9b27,ceph.block_uuid=cYBGv9-s2cn-FfEy-dGQh-VHci-5jj9-9l5kvH,ceph.cephx_lockbox_secret=,ceph.cluster_fsid=7dccab18-14cf-11ee-837b-5254008f8ca5,ceph.cluster_name=ceph,ceph.crush_device_class=,ceph.encrypted=0,ceph.osd_fsid=a0e07c5b-bee1-4ea2-ae07-cb89deda9b27,ceph.osd_id=0,ceph.osdspec_affinity=,ceph.type=block,ceph.vdo=0', + 'lv_path': '/dev/ceph-e34cc3f5-a70d-49df-82b3-46bcbd63d4b0/osd-block-a0e07c5b-bee1-4ea2-ae07-cb89deda9b27', + 'lv_name': 'osd-block-a0e07c5b-bee1-4ea2-ae07-cb89deda9b27', + 'vg_name': 'ceph-e34cc3f5-a70d-49df-82b3-46bcbd63d4b0', + 'lv_uuid': 'cYBGv9-s2cn-FfEy-dGQh-VHci-5jj9-9l5kvH', + 'lv_size': '214744170496', + 'tags': { + 'ceph.block_device': '/dev/ceph-e34cc3f5-a70d-49df-82b3-46bcbd63d4b0/osd-block-a0e07c5b-bee1-4ea2-ae07-cb89deda9b27', + 'ceph.block_uuid': 'cYBGv9-s2cn-FfEy-dGQh-VHci-5jj9-9l5kvH', + 'ceph.cephx_lockbox_secret': '', + 'ceph.cluster_fsid': '7dccab18-14cf-11ee-837b-5254008f8ca5', + 'ceph.cluster_name': 'ceph', + 'ceph.crush_device_class': '', + 'ceph.encrypted': '0', + 'ceph.osd_fsid': 'a0e07c5b-bee1-4ea2-ae07-cb89deda9b27', + 'ceph.osd_id': '0', + 'ceph.osdspec_affinity': '', + 'ceph.type': 'block', + 'ceph.vdo': '0' + }, + 'name': 'osd-block-a0e07c5b-bee1-4ea2-ae07-cb89deda9b27', + 'type': 'block', + 'path': '/dev/ceph-e34cc3f5-a70d-49df-82b3-46bcbd63d4b0/osd-block-a0e07c5b-bee1-4ea2-ae07-cb89deda9b27', + 'devices': ['/dev/vdb1'] + }] + } + +raw_direct_report_data = { + "824f7edf-371f-4b75-9231-4ab62a32d5c0": { + "ceph_fsid": "7dccab18-14cf-11ee-837b-5254008f8ca5", + "device": "/dev/mapper/ceph--40bc7bd7--4aee--483e--ba95--89a64bc8a4fd-osd--block--824f7edf--371f--4b75--9231--4ab62a32d5c0", + "device_db": "/dev/mapper/ceph--73d6d4db--6528--48f2--a4e2--1c82bc87a9ac-osd--db--b82d920d--be3c--4e4d--ba64--18f7e8445892", + "osd_id": 8, + "osd_uuid": "824f7edf-371f-4b75-9231-4ab62a32d5c0", + "type": "bluestore" + }, + "a0e07c5b-bee1-4ea2-ae07-cb89deda9b27": { + "ceph_fsid": "7dccab18-14cf-11ee-837b-5254008f8ca5", + "device": "/dev/mapper/ceph--e34cc3f5--a70d--49df--82b3--46bcbd63d4b0-osd--block--a0e07c5b--bee1--4ea2--ae07--cb89deda9b27", + "osd_id": 9, + "osd_uuid": "a0e07c5b-bee1-4ea2-ae07-cb89deda9b27", + "type": "bluestore" + } +} + +@pytest.fixture +def mock_lvm_direct_report(monkeypatch): + monkeypatch.setattr('ceph_volume.objectstore.lvmbluestore.direct_report', lambda: lvm_direct_report_data) + +@pytest.fixture +def mock_raw_direct_report(monkeypatch): + monkeypatch.setattr('ceph_volume.objectstore.rawbluestore.direct_report', lambda x: raw_direct_report_data) \ No newline at end of file diff --git a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_activate.py b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_activate.py index 5d48a0ef4044..6f38097a1ab9 100644 --- a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_activate.py +++ b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_activate.py @@ -3,7 +3,10 @@ from copy import deepcopy from ceph_volume.devices.lvm import activate from ceph_volume.api import lvm as api from ceph_volume.tests.conftest import Capture - +from ceph_volume import objectstore +#from ceph_volume.util.prepare import create_key +from mock import patch, call +from argparse import Namespace class Args(object): @@ -16,33 +19,48 @@ class Args(object): setattr(self, k, v) +@patch('ceph_volume.util.prepare.create_key', return_value='fake-secret') class TestActivate(object): # these tests are very functional, hence the heavy patching, it is hard to # test the negative side effect with an actual functional run, so we must # setup a perfect scenario for this test to check it can really work # with/without osd_id - def test_no_osd_id_matches_fsid_bluestore(self, is_root, monkeypatch, capture): - FooVolume = api.Volume(lv_name='foo', lv_path='/dev/vg/foo', - lv_tags="ceph.osd_fsid=1234") + def test_no_osd_id_matches_fsid_bluestore(self, + m_create_key, + is_root, + monkeypatch, + capture): + FooVolume = api.Volume(lv_name='foo', + lv_path='/dev/vg/foo', + lv_tags="ceph.osd_fsid=1234") volumes = [] volumes.append(FooVolume) monkeypatch.setattr(api, 'get_lvs', lambda **kwargs: volumes) - monkeypatch.setattr(activate, 'activate_bluestore', capture) + monkeypatch.setattr(objectstore.lvmbluestore.LvmBlueStore, + '_activate', + capture) + args = Args(osd_id=None, osd_fsid='1234', bluestore=True) - activate.Activate([]).activate(args) + a = activate.Activate([]) + a.objectstore = objectstore.lvmbluestore.LvmBlueStore(args=args) + a.objectstore.activate() assert capture.calls[0]['args'][0] == [FooVolume] - def test_osd_id_no_osd_fsid(self, is_root): + def test_osd_id_no_osd_fsid(self, m_create_key, is_root): args = Args(osd_id=42, osd_fsid=None) + a = activate.Activate([]) + a.objectstore = objectstore.lvmbluestore.LvmBlueStore(args=args) with pytest.raises(RuntimeError) as result: - activate.Activate([]).activate(args) + a.objectstore.activate() assert result.value.args[0] == 'could not activate osd.42, please provide the osd_fsid too' - def test_no_osd_id_no_osd_fsid(self, is_root): + def test_no_osd_id_no_osd_fsid(self, m_create_key, is_root): args = Args(osd_id=None, osd_fsid=None) + a = activate.Activate([]) + a.objectstore = objectstore.lvmbluestore.LvmBlueStore(args=args) with pytest.raises(RuntimeError) as result: - activate.Activate([]).activate(args) + a.objectstore.activate() assert result.value.args[0] == 'Please provide both osd_id and osd_fsid' def test_bluestore_no_systemd(self, is_root, monkeypatch, capture): @@ -52,8 +70,8 @@ class TestActivate(object): monkeypatch.setattr('ceph_volume.util.system.path_is_mounted', lambda *a, **kw: True) monkeypatch.setattr('ceph_volume.util.system.chown', lambda *a, **kw: True) monkeypatch.setattr('ceph_volume.process.run', lambda *a, **kw: True) - monkeypatch.setattr(activate.systemctl, 'enable_volume', fake_enable) - monkeypatch.setattr(activate.systemctl, 'start_osd', fake_start_osd) + monkeypatch.setattr(objectstore.lvmbluestore.systemctl, 'enable_volume', fake_enable) + monkeypatch.setattr(objectstore.lvmbluestore.systemctl, 'start_osd', fake_start_osd) DataVolume = api.Volume( lv_name='data', lv_path='/dev/vg/data', @@ -64,7 +82,9 @@ class TestActivate(object): monkeypatch.setattr(api, 'get_lvs', lambda **kwargs: deepcopy(volumes)) args = Args(osd_id=None, osd_fsid='1234', no_systemd=True, bluestore=True) - activate.Activate([]).activate(args) + a = activate.Activate([]) + a.objectstore = objectstore.lvmbluestore.LvmBlueStore(args=args) + a.objectstore.activate() assert fake_enable.calls == [] assert fake_start_osd.calls == [] @@ -75,8 +95,8 @@ class TestActivate(object): monkeypatch.setattr('ceph_volume.util.system.path_is_mounted', lambda *a, **kw: True) monkeypatch.setattr('ceph_volume.util.system.chown', lambda *a, **kw: True) monkeypatch.setattr('ceph_volume.process.run', lambda *a, **kw: True) - monkeypatch.setattr(activate.systemctl, 'enable_volume', fake_enable) - monkeypatch.setattr(activate.systemctl, 'start_osd', fake_start_osd) + monkeypatch.setattr(objectstore.lvmbluestore.systemctl, 'enable_volume', fake_enable) + monkeypatch.setattr(objectstore.lvmbluestore.systemctl, 'start_osd', fake_start_osd) DataVolume = api.Volume( lv_name='data', lv_path='/dev/vg/data', @@ -88,7 +108,9 @@ class TestActivate(object): args = Args(osd_id=None, osd_fsid='1234', no_systemd=False, bluestore=True) - activate.Activate([]).activate(args) + a = activate.Activate([]) + a.objectstore = objectstore.lvmbluestore.LvmBlueStore(args=args) + a.objectstore.activate() assert fake_enable.calls != [] assert fake_start_osd.calls != [] @@ -99,8 +121,8 @@ class TestActivate(object): monkeypatch.setattr('ceph_volume.util.system.path_is_mounted', lambda *a, **kw: True) monkeypatch.setattr('ceph_volume.util.system.chown', lambda *a, **kw: True) monkeypatch.setattr('ceph_volume.process.run', lambda *a, **kw: True) - monkeypatch.setattr(activate.systemctl, 'enable_volume', fake_enable) - monkeypatch.setattr(activate.systemctl, 'start_osd', fake_start_osd) + monkeypatch.setattr(objectstore.lvmbluestore.systemctl, 'enable_volume', fake_enable) + monkeypatch.setattr(objectstore.lvmbluestore.systemctl, 'start_osd', fake_start_osd) DataVolume = api.Volume( lv_name='data', lv_path='/dev/vg/data', @@ -112,7 +134,9 @@ class TestActivate(object): args = Args(osd_id=None, osd_fsid='1234', no_systemd=True, bluestore=True, auto_detect_objectstore=True) - activate.Activate([]).activate(args) + a = activate.Activate([]) + a.objectstore = objectstore.lvmbluestore.LvmBlueStore(args=args) + a.objectstore.activate() assert fake_enable.calls == [] assert fake_start_osd.calls == [] @@ -125,8 +149,8 @@ class TestActivate(object): monkeypatch.setattr('ceph_volume.util.system.chown', lambda *a, **kw: True) monkeypatch.setattr('ceph_volume.process.run', lambda *a, **kw: True) - monkeypatch.setattr(activate.systemctl, 'enable_volume', fake_enable) - monkeypatch.setattr(activate.systemctl, 'start_osd', fake_start_osd) + monkeypatch.setattr(objectstore.lvmbluestore.systemctl, 'enable_volume', fake_enable) + monkeypatch.setattr(objectstore.lvmbluestore.systemctl, 'start_osd', fake_start_osd) DataVolume = api.Volume( lv_name='data', lv_path='/dev/vg/data', @@ -138,33 +162,37 @@ class TestActivate(object): args = Args(osd_id=None, osd_fsid='1234', no_systemd=False, bluestore=True, auto_detect_objectstore=False) - activate.Activate([]).activate(args) + a = activate.Activate([]) + a.objectstore = objectstore.lvmbluestore.LvmBlueStore(args=args) + a.objectstore.activate() assert fake_enable.calls != [] assert fake_start_osd.calls != [] + +@patch('ceph_volume.util.prepare.create_key', return_value='fake-secret') +@patch('ceph_volume.objectstore.lvmbluestore.LvmBlueStore.activate_all') +@patch('ceph_volume.objectstore.lvmbluestore.LvmBlueStore.activate') class TestActivateFlags(object): - def test_default_objectstore(self, capture): + def test_default_objectstore(self, m_activate, m_activate_all, m_create_key, capture): args = ['0', 'asdf-ljh-asdf'] - activation = activate.Activate(args) - activation.activate = capture - activation.main() - parsed_args = capture.calls[0]['args'][0] - assert parsed_args.bluestore is False - def test_uses_bluestore(self, capture): + a = activate.Activate(args) + a.main() + assert a.args.objectstore == 'bluestore' + + def test_bluestore_backward_compatibility(self, m_activate, m_activate_all, m_create_key, capture): args = ['--bluestore', '0', 'asdf-ljh-asdf'] - activation = activate.Activate(args) - activation.activate = capture - activation.main() - parsed_args = capture.calls[0]['args'][0] - assert parsed_args.bluestore is True + a = activate.Activate(args) + a.main() + assert a.args.objectstore == 'bluestore' +@patch('ceph_volume.util.prepare.create_key', return_value='fake-secret') class TestActivateAll(object): - def test_does_not_detect_osds(self, capsys, is_root, capture, monkeypatch): - monkeypatch.setattr('ceph_volume.devices.lvm.activate.direct_report', lambda: {}) + def test_does_not_detect_osds(self, m_create_key, capsys, is_root, monkeypatch): + monkeypatch.setattr('ceph_volume.objectstore.lvmbluestore.direct_report', lambda: {}) args = ['--all'] activation = activate.Activate(args) activation.main() @@ -172,9 +200,9 @@ class TestActivateAll(object): assert 'Was unable to find any OSDs to activate' in err assert 'Verify OSDs are present with ' in err - def test_detects_running_osds(self, capsys, is_root, capture, monkeypatch): - monkeypatch.setattr('ceph_volume.devices.lvm.activate.direct_report', lambda: direct_report) - monkeypatch.setattr('ceph_volume.devices.lvm.activate.systemctl.osd_is_active', lambda x: True) + def test_detects_running_osds(self, m_create_key, capsys, is_root, capture, monkeypatch): + monkeypatch.setattr('ceph_volume.objectstore.lvmbluestore.direct_report', lambda: direct_report) + monkeypatch.setattr('ceph_volume.objectstore.lvmbluestore.systemctl.osd_is_active', lambda x: True) args = ['--all'] activation = activate.Activate(args) activation.main() @@ -182,30 +210,66 @@ class TestActivateAll(object): assert 'a8789a96ce8b process is active. Skipping activation' in err assert 'b8218eaa1634 process is active. Skipping activation' in err - def test_detects_osds_to_activate_systemd(self, is_root, capture, monkeypatch): - monkeypatch.setattr('ceph_volume.devices.lvm.activate.direct_report', lambda: direct_report) - monkeypatch.setattr('ceph_volume.devices.lvm.activate.systemctl.osd_is_active', lambda x: False) - args = ['--all'] - activation = activate.Activate(args) - activation.activate = capture - activation.main() - calls = sorted(capture.calls, key=lambda x: x['kwargs']['osd_id']) - assert calls[0]['kwargs']['osd_id'] == '0' - assert calls[0]['kwargs']['osd_fsid'] == '957d22b7-24ce-466a-9883-b8218eaa1634' - assert calls[1]['kwargs']['osd_id'] == '1' - assert calls[1]['kwargs']['osd_fsid'] == 'd0f3e4ad-e52a-4520-afc0-a8789a96ce8b' + @patch('ceph_volume.objectstore.lvmbluestore.LvmBlueStore.activate') + def test_detects_osds_to_activate_systemd(self, m_activate, m_create_key, is_root, monkeypatch): + monkeypatch.setattr('ceph_volume.objectstore.lvmbluestore.direct_report', lambda: direct_report) + monkeypatch.setattr('ceph_volume.objectstore.lvmbluestore.systemctl.osd_is_active', lambda x: False) + args = ['--all', '--bluestore'] + a = activate.Activate(args) + a.main() + calls = [ + call(Namespace(activate_all=True, + auto_detect_objectstore=False, + bluestore=True, + no_systemd=False, + no_tmpfs=False, + objectstore='bluestore', + osd_fsid=None, + osd_id=None), + osd_id='0', + osd_fsid='957d22b7-24ce-466a-9883-b8218eaa1634'), + call(Namespace(activate_all=True, + auto_detect_objectstore=False, + bluestore=True, + no_systemd=False, + no_tmpfs=False, + objectstore='bluestore', + osd_fsid=None, + osd_id=None), + osd_id='1', + osd_fsid='d0f3e4ad-e52a-4520-afc0-a8789a96ce8b') + ] + m_activate.assert_has_calls(calls) - def test_detects_osds_to_activate_no_systemd(self, is_root, capture, monkeypatch): - monkeypatch.setattr('ceph_volume.devices.lvm.activate.direct_report', lambda: direct_report) - args = ['--all', '--no-systemd'] - activation = activate.Activate(args) - activation.activate = capture - activation.main() - calls = sorted(capture.calls, key=lambda x: x['kwargs']['osd_id']) - assert calls[0]['kwargs']['osd_id'] == '0' - assert calls[0]['kwargs']['osd_fsid'] == '957d22b7-24ce-466a-9883-b8218eaa1634' - assert calls[1]['kwargs']['osd_id'] == '1' - assert calls[1]['kwargs']['osd_fsid'] == 'd0f3e4ad-e52a-4520-afc0-a8789a96ce8b' + @patch('ceph_volume.objectstore.lvmbluestore.LvmBlueStore.activate') + def test_detects_osds_to_activate_no_systemd(self, m_activate, is_root, monkeypatch): + monkeypatch.setattr('ceph_volume.objectstore.lvmbluestore.direct_report', lambda: direct_report) + args = ['--all', '--no-systemd', '--bluestore'] + a = activate.Activate(args) + a.main() + calls = [ + call(Namespace(activate_all=True, + auto_detect_objectstore=False, + bluestore=True, + no_systemd=True, + no_tmpfs=False, + objectstore='bluestore', + osd_fsid=None, + osd_id=None), + osd_id='0', + osd_fsid='957d22b7-24ce-466a-9883-b8218eaa1634'), + call(Namespace(activate_all=True, + auto_detect_objectstore=False, + bluestore=True, + no_systemd=True, + no_tmpfs=False, + objectstore='bluestore', + osd_fsid=None, + osd_id=None), + osd_id='1', + osd_fsid='d0f3e4ad-e52a-4520-afc0-a8789a96ce8b') + ] + m_activate.assert_has_calls(calls) # # Activate All fixture diff --git a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_batch.py b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_batch.py index 51072da120a9..e26a733b09cd 100644 --- a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_batch.py +++ b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_batch.py @@ -5,7 +5,6 @@ import random from argparse import ArgumentError from mock import MagicMock, patch -from ceph_volume.api import lvm from ceph_volume.devices.lvm import batch from ceph_volume.util import arg_validators @@ -77,14 +76,14 @@ class TestBatch(object): devices=devs, db_devices=[], wal_devices=[], - bluestore=True, + objectstore='bluestore', block_db_size="1G", dmcrypt=True, data_allocate_fraction=1.0, ) b = batch.Batch([]) - plan = b.get_plan(args) b.args = args + plan = b.get_deployment_layout() report = b._create_report(plan) json.loads(report) @@ -103,14 +102,15 @@ class TestBatch(object): devices=devs, db_devices=fast_devs, wal_devices=[], - bluestore=True, + objectstore='bluestore', block_db_size="1G", + block_db_slots=1.0, dmcrypt=True, data_allocate_fraction=1.0, ) b = batch.Batch([]) - plan = b.get_plan(args) b.args = args + plan = b.get_deployment_layout() report = b._create_report(plan) json.loads(report) @@ -121,6 +121,7 @@ class TestBatch(object): conf_ceph_stub('[global]\nfsid=asdf-lkjh') devs = [mock_device_generator() for _ in range(5)] fast_devs = [mock_device_generator()] + fast_devs[0].available_lvm = False very_fast_devs = [mock_device_generator()] very_fast_devs[0].available_lvm = False args = factory(data_slots=1, @@ -131,14 +132,15 @@ class TestBatch(object): devices=devs, db_devices=fast_devs, wal_devices=very_fast_devs, - bluestore=True, + objectstore='bluestore', block_db_size="1G", + block_db_slots=5, dmcrypt=True, data_allocate_fraction=1.0, ) b = batch.Batch([]) - plan = b.get_plan(args) b.args = args + plan = b.get_deployment_layout() report = b._create_report(plan) json.loads(report) @@ -250,35 +252,50 @@ class TestBatch(object): for (_, _, slot_size, _) in fasts: assert slot_size == expected_slot_size - def test_get_physical_fast_allocs_abs_size_multi_pvs_per_vg(self, factory, - conf_ceph_stub, - mock_devices_available): + def test_get_physical_fast_allocs_abs_size_multi_pvs_per_vg(self, + factory, + conf_ceph_stub, + mock_device_generator, + mock_devices_available_multi_pvs_per_vg): conf_ceph_stub('[global]\nfsid=asdf-lkjh') - args = factory(block_db_slots=None, get_block_db_size=None) - dev_size = 21474836480 - num_devices = len(mock_devices_available) + data_devices = [] + # existing_osds = sum([len(dev.lvs) for dev in mock_devices_available_multi_pvs_per_vg]) + for i in range(len(mock_devices_available_multi_pvs_per_vg)+2): + data_devices.append(mock_device_generator(name='data', + vg_name=f'vg_foo_data{str(i)}', + lv_name=f'lv_foo_data{str(i)}')) + args = factory(block_db_slots=None, + block_db_size=None, + devices=[dev.lv_path for dev in data_devices]) + dev_size = 53687091200 + num_devices = len(mock_devices_available_multi_pvs_per_vg) vg_size = dev_size * num_devices - vg_name = 'vg_foo' - for dev in mock_devices_available: - dev.vg_name = vg_name - dev.vg_size = [vg_size] - dev.vg_free = dev.vg_size - dev.vgs = [lvm.VolumeGroup(vg_name=dev.vg_name, lv_name=dev.lv_name)] - slots_per_device = 2 - slots_per_vg = slots_per_device * num_devices - fasts = batch.get_physical_fast_allocs(mock_devices_available, - 'block_db', slots_per_device, 2, args) - expected_slot_size = int(vg_size / slots_per_vg) + vg_free = vg_size + for dev in mock_devices_available_multi_pvs_per_vg: + for lv in dev.lvs: + vg_free -= lv.lv_size[0] + dev.vg_size = [vg_size] # override the `vg_size` set in mock_device() since it's 1VG that has multiple PVs + for dev in mock_devices_available_multi_pvs_per_vg: + dev.vg_free = [vg_free] # override the `vg_free` set in mock_device() since it's 1VG that has multiple PVs + b = batch.Batch([]) + b.args = args + new_osds = len(data_devices) - len(mock_devices_available_multi_pvs_per_vg) + fasts = b.fast_allocations(mock_devices_available_multi_pvs_per_vg, + len(data_devices), + new_osds, + 'block_db') + expected_slot_size = int(vg_size / len(data_devices)) for (_, _, slot_size, _) in fasts: assert slot_size == expected_slot_size - def test_batch_fast_allocations_one_block_db_length(self, factory, conf_ceph_stub, - mock_lv_device_generator): + def test_batch_fast_allocations_one_block_db_length(self, + factory, conf_ceph_stub, + mock_device_generator): conf_ceph_stub('[global]\nfsid=asdf-lkjh') b = batch.Batch([]) - db_lv_devices = [mock_lv_device_generator()] - fast = b.fast_allocations(db_lv_devices, 1, 0, 'block_db') + db_device = [mock_device_generator()] + fast = b.fast_allocations(db_device, 1, 1, 'block_db') assert len(fast) == 1 @pytest.mark.parametrize('occupied_prior', range(7)) @@ -293,22 +310,24 @@ class TestBatch(object): mock_device_generator): conf_ceph_stub('[global]\nfsid=asdf-lkjh') occupied_prior = min(occupied_prior, slots) - devs = [mock_device_generator() for _ in range(num_devs)] + devs = [mock_device_generator(lv_name=f'foo{n}') for n in range(slots)] + dev_paths = [dev.path for dev in devs] + fast_devs = [mock_device_generator(lv_name=f'ssd{n}') for n in range(num_devs)] already_assigned = 0 while already_assigned < occupied_prior: dev_i = random.randint(0, num_devs - 1) - dev = devs[dev_i] + dev = fast_devs[dev_i] if len(dev.lvs) < occupied_prior: dev.lvs.append('foo') dev.path = '/dev/bar' - already_assigned = sum([len(d.lvs) for d in devs]) - args = factory(block_db_slots=None, get_block_db_size=None) - expected_num_osds = max(len(devs) * slots - occupied_prior, 0) - fast = batch.get_physical_fast_allocs(devs, + already_assigned = sum([len(dev.lvs) for dev in fast_devs]) + args = factory(block_db_slots=None, get_block_db_size=None, devices=dev_paths) + expected_num_osds = max(len(fast_devs) * slots - occupied_prior, 0) + fast = batch.get_physical_fast_allocs(fast_devs, 'block_db', slots, expected_num_osds, args) assert len(fast) == expected_num_osds - expected_assignment_on_used_devices = sum([slots - len(d.lvs) for d in devs if len(d.lvs) > 0]) + expected_assignment_on_used_devices = sum([slots - len(d.lvs) for d in fast_devs if len(d.lvs) > 0]) assert len([f for f in fast if f[0] == '/dev/bar']) == expected_assignment_on_used_devices assert len([f for f in fast if f[0] != '/dev/bar']) == expected_num_osds - expected_assignment_on_used_devices diff --git a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_migrate.py b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_migrate.py index 91e6155f38cd..13f4acb075c1 100644 --- a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_migrate.py +++ b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_migrate.py @@ -524,7 +524,8 @@ class TestNew(object): def mock_prepare_dmcrypt(self, *args, **kwargs): return '/dev/mapper/' + kwargs['mapping'] - def test_newdb_non_root(self): + @patch('os.getuid', return_value=1) + def test_newdb_non_root(self, m_getuid): with pytest.raises(Exception) as error: migrate.NewDB(argv=[ '--osd-id', '1', diff --git a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_prepare.py b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_prepare.py index 0a356988eebc..7f51896ea8f6 100644 --- a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_prepare.py +++ b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_prepare.py @@ -2,6 +2,7 @@ import pytest from ceph_volume.devices import lvm from ceph_volume.api import lvm as api from mock.mock import patch, Mock +from ceph_volume import objectstore class TestLVM(object): @@ -24,102 +25,116 @@ class TestLVM(object): assert 'Format an LVM device' in stdout +@patch('ceph_volume.util.prepare.create_key', return_value='fake-secret') class TestPrepareDevice(object): - def test_cannot_use_device(self, factory): + def test_cannot_use_device(self, m_create_key, factory): args = factory(data='/dev/var/foo') with pytest.raises(RuntimeError) as error: p = lvm.prepare.Prepare([]) - p.args = args - p.prepare_data_device( 'data', '0') + p.objectstore = objectstore.lvmbluestore.LvmBlueStore(args=args) + p.objectstore.prepare_data_device( 'data', '0') assert 'Cannot use device (/dev/var/foo)' in str(error.value) assert 'A vg/lv path or an existing device is needed' in str(error.value) - +@patch('ceph_volume.util.prepare.create_key', return_value='fake-secret') class TestGetClusterFsid(object): + def setup(self): + self.p = lvm.prepare.Prepare([]) - def test_fsid_is_passed_in(self, factory): + def test_fsid_is_passed_in(self, m_create_key, factory): args = factory(cluster_fsid='aaaa-1111') - prepare_obj = lvm.prepare.Prepare([]) - prepare_obj.args = args - assert prepare_obj.get_cluster_fsid() == 'aaaa-1111' + self.p.objectstore = objectstore.lvmbluestore.LvmBlueStore(args) + assert self.p.objectstore.get_cluster_fsid() == 'aaaa-1111' - def test_fsid_is_read_from_ceph_conf(self, factory, conf_ceph_stub): + def test_fsid_is_read_from_ceph_conf(self, m_create_key, factory, conf_ceph_stub): conf_ceph_stub('[global]\nfsid = bbbb-2222') - prepare_obj = lvm.prepare.Prepare([]) - prepare_obj.args = factory(cluster_fsid=None) - assert prepare_obj.get_cluster_fsid() == 'bbbb-2222' + args = factory(cluster_fsid='') + self.p.objectstore = objectstore.lvmbluestore.LvmBlueStore(args) + assert self.p.objectstore.get_cluster_fsid() == 'bbbb-2222' +@patch('ceph_volume.util.prepare.create_key', return_value='fake-secret') class TestPrepare(object): - def test_main_spits_help_with_no_arguments(self, capsys): + def setup(self): + self.p = lvm.prepare.Prepare([]) + + def test_main_spits_help_with_no_arguments(self, m_create_key, capsys): lvm.prepare.Prepare([]).main() stdout, stderr = capsys.readouterr() assert 'Prepare an OSD by assigning an ID and FSID' in stdout - def test_main_shows_full_help(self, capsys): + def test_main_shows_full_help(self, m_create_key, capsys): with pytest.raises(SystemExit): lvm.prepare.Prepare(argv=['--help']).main() stdout, stderr = capsys.readouterr() assert 'Use the bluestore objectstore' in stdout assert 'A physical device or logical' in stdout - @patch('ceph_volume.devices.lvm.prepare.api.is_ceph_device') - def test_safe_prepare_osd_already_created(self, m_is_ceph_device): + @patch('ceph_volume.api.lvm.is_ceph_device') + def test_safe_prepare_osd_already_created(self, m_create_key, m_is_ceph_device): m_is_ceph_device.return_value = True with pytest.raises(RuntimeError) as error: - prepare = lvm.prepare.Prepare(argv=[]) - prepare.args = Mock() - prepare.args.data = '/dev/sdfoo' - prepare.get_lv = Mock() - prepare.safe_prepare() + self.p.args = Mock() + self.p.args.data = '/dev/sdfoo' + self.p.get_lv = Mock() + self.p.objectstore = objectstore.lvmbluestore.LvmBlueStore(args=self.p.args) + self.p.objectstore.safe_prepare() expected = 'skipping {}, it is already prepared'.format('/dev/sdfoo') assert expected in str(error.value) - def test_setup_device_device_name_is_none(self): - result = lvm.prepare.Prepare([]).setup_device(device_type='data', device_name=None, tags={'ceph.type': 'data'}, size=0, slots=None) + def test_setup_device_device_name_is_none(self, m_create_key): + self.p.objectstore = objectstore.lvmbluestore.LvmBlueStore(args=[]) + result = self.p.objectstore.setup_device(device_type='data', + device_name=None, + tags={'ceph.type': 'data'}, + size=0, + slots=None) assert result == ('', '', {'ceph.type': 'data'}) @patch('ceph_volume.api.lvm.Volume.set_tags') - @patch('ceph_volume.devices.lvm.prepare.api.get_single_lv') - def test_setup_device_lv_passed(self, m_get_single_lv, m_set_tags): + @patch('ceph_volume.api.lvm.get_single_lv') + def test_setup_device_lv_passed(self, m_get_single_lv, m_set_tags, m_create_key): fake_volume = api.Volume(lv_name='lv_foo', lv_path='/fake-path', vg_name='vg_foo', lv_tags='', lv_uuid='fake-uuid') m_get_single_lv.return_value = fake_volume - result = lvm.prepare.Prepare([]).setup_device(device_type='data', device_name='vg_foo/lv_foo', tags={'ceph.type': 'data'}, size=0, slots=None) + self.p.objectstore = objectstore.lvmbluestore.LvmBlueStore(args=[]) + result = self.p.objectstore.setup_device(device_type='data', device_name='vg_foo/lv_foo', tags={'ceph.type': 'data'}, size=0, slots=None) assert result == ('/fake-path', 'fake-uuid', {'ceph.type': 'data', 'ceph.vdo': '0', 'ceph.data_uuid': 'fake-uuid', 'ceph.data_device': '/fake-path'}) - @patch('ceph_volume.devices.lvm.prepare.api.create_lv') + @patch('ceph_volume.api.lvm.create_lv') @patch('ceph_volume.api.lvm.Volume.set_tags') @patch('ceph_volume.util.disk.is_device') - def test_setup_device_device_passed(self, m_is_device, m_set_tags, m_create_lv): + def test_setup_device_device_passed(self, m_is_device, m_set_tags, m_create_lv, m_create_key): fake_volume = api.Volume(lv_name='lv_foo', lv_path='/fake-path', vg_name='vg_foo', lv_tags='', lv_uuid='fake-uuid') m_is_device.return_value = True m_create_lv.return_value = fake_volume - result = lvm.prepare.Prepare([]).setup_device(device_type='data', device_name='/dev/sdx', tags={'ceph.type': 'data'}, size=0, slots=None) + self.p.objectstore = objectstore.lvmbluestore.LvmBlueStore(args=[]) + result = self.p.objectstore.setup_device(device_type='data', device_name='/dev/sdx', tags={'ceph.type': 'data'}, size=0, slots=None) assert result == ('/fake-path', 'fake-uuid', {'ceph.type': 'data', 'ceph.vdo': '0', 'ceph.data_uuid': 'fake-uuid', 'ceph.data_device': '/fake-path'}) - @patch('ceph_volume.devices.lvm.prepare.Prepare.get_ptuuid') - @patch('ceph_volume.devices.lvm.prepare.api.get_single_lv') - def test_setup_device_partition_passed(self, m_get_single_lv, m_get_ptuuid): + @patch('ceph_volume.objectstore.baseobjectstore.BaseObjectStore.get_ptuuid') + @patch('ceph_volume.api.lvm.get_single_lv') + def test_setup_device_partition_passed(self, m_get_single_lv, m_get_ptuuid, m_create_key): m_get_single_lv.side_effect = ValueError() m_get_ptuuid.return_value = 'fake-uuid' - result = lvm.prepare.Prepare([]).setup_device(device_type='data', device_name='/dev/sdx', tags={'ceph.type': 'data'}, size=0, slots=None) + self.p.objectstore = objectstore.lvmbluestore.LvmBlueStore(args=[]) + result = self.p.objectstore.setup_device(device_type='data', device_name='/dev/sdx', tags={'ceph.type': 'data'}, size=0, slots=None) assert result == ('/dev/sdx', 'fake-uuid', {'ceph.type': 'data', 'ceph.vdo': '0', 'ceph.data_uuid': 'fake-uuid', 'ceph.data_device': '/dev/sdx'}) - def test_invalid_osd_id_passed(self): + def test_invalid_osd_id_passed(self, m_create_key): with pytest.raises(SystemExit): lvm.prepare.Prepare(argv=['--osd-id', 'foo']).main() diff --git a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_zap.py b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_zap.py index 2446c5ed6651..51f66abfc780 100644 --- a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_zap.py +++ b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_zap.py @@ -139,17 +139,6 @@ class TestEnsureAssociatedLVs(object): out, err = capsys.readouterr() assert "Zapping successful for OSD: 1" in err - def test_block_and_partition_are_found(self, monkeypatch): - monkeypatch.setattr(zap.disk, 'get_device_from_partuuid', lambda x: '/dev/sdb1') - tags = 'ceph.osd_id=0,ceph.osd_fsid=asdf-lkjh,ceph.journal_uuid=x,ceph.type=block' - osd = api.Volume( - lv_name='volume1', lv_uuid='y', vg_name='', lv_path='/dev/VolGroup/block', lv_tags=tags) - volumes = [] - volumes.append(osd) - result = zap.ensure_associated_lvs(volumes) - assert '/dev/sdb1' in result - assert '/dev/VolGroup/block' in result - def test_journal_is_found(self, fake_call): tags = 'ceph.osd_id=0,ceph.osd_fsid=asdf-lkjh,ceph.journal_uuid=x,ceph.type=journal' osd = api.Volume( @@ -211,7 +200,6 @@ class TestEnsureAssociatedLVs(object): def test_ensure_associated_lvs(self, m_get_lvs): zap.ensure_associated_lvs([], lv_tags={'ceph.osd_id': '1'}) calls = [ - call(tags={'ceph.type': 'journal', 'ceph.osd_id': '1'}), call(tags={'ceph.type': 'db', 'ceph.osd_id': '1'}), call(tags={'ceph.type': 'wal', 'ceph.osd_id': '1'}) ] diff --git a/src/ceph-volume/ceph_volume/tests/devices/raw/test_prepare.py b/src/ceph-volume/ceph_volume/tests/devices/raw/test_prepare.py index f814bbf136b7..0802f9232498 100644 --- a/src/ceph-volume/ceph_volume/tests/devices/raw/test_prepare.py +++ b/src/ceph-volume/ceph_volume/tests/devices/raw/test_prepare.py @@ -1,7 +1,7 @@ import pytest from ceph_volume.devices import raw from mock.mock import patch - +from ceph_volume import objectstore class TestRaw(object): @@ -22,15 +22,21 @@ class TestRaw(object): assert 'prepare ' in stdout assert 'Format a raw device' in stdout - +@patch('ceph_volume.util.prepare.create_key', return_value='fake-secret') class TestPrepare(object): + def _setup(self, **kw): + args = kw.get('args', []) + self.p = raw.prepare.Prepare([]) + self.p.objectstore = objectstore.rawbluestore.RawBlueStore(args=args) + for k, v in kw.items(): + setattr(self.p.objectstore, k, v) - def test_main_spits_help_with_no_arguments(self, capsys): + def test_main_spits_help_with_no_arguments(self, m_create_key, capsys): raw.prepare.Prepare([]).main() stdout, stderr = capsys.readouterr() assert 'Prepare an OSD by assigning an ID and FSID' in stdout - def test_main_shows_full_help(self, capsys): + def test_main_shows_full_help(self, m_create_key, capsys): with pytest.raises(SystemExit): raw.prepare.Prepare(argv=['--help']).main() stdout, stderr = capsys.readouterr() @@ -42,7 +48,7 @@ class TestPrepare(object): assert 'Enable device encryption via dm-crypt' in stdout @patch('ceph_volume.util.arg_validators.ValidRawDevice.__call__') - def test_prepare_dmcrypt_no_secret_passed(self, m_valid_device, capsys): + def test_prepare_dmcrypt_no_secret_passed(self, m_valid_device, m_create_key, capsys): m_valid_device.return_value = '/dev/foo' with pytest.raises(SystemExit): raw.prepare.Prepare(argv=['--bluestore', '--data', '/dev/foo', '--dmcrypt']).main() @@ -52,43 +58,52 @@ class TestPrepare(object): @patch('ceph_volume.util.encryption.luks_open') @patch('ceph_volume.util.encryption.luks_format') @patch('ceph_volume.util.disk.lsblk') - def test_prepare_dmcrypt_block(self, m_lsblk, m_luks_format, m_luks_open): + def test_prepare_dmcrypt_block(self, m_lsblk, m_luks_format, m_luks_open, m_create_key, factory): m_lsblk.return_value = {'KNAME': 'foo'} m_luks_format.return_value = True m_luks_open.return_value = True - result = raw.prepare.prepare_dmcrypt('foo', '/dev/foo', 'block', '123') + self._setup(block_device_path='/dev/foo', + osd_fsid='123', + secrets=dict(dmcrypt_key='foo')) + self.p.objectstore.prepare_dmcrypt() m_luks_open.assert_called_with('foo', '/dev/foo', 'ceph-123-foo-block-dmcrypt') m_luks_format.assert_called_with('foo', '/dev/foo') - assert result == '/dev/mapper/ceph-123-foo-block-dmcrypt' + assert self.p.objectstore.__dict__['block_device_path'] == '/dev/mapper/ceph-123-foo-block-dmcrypt' @patch('ceph_volume.util.encryption.luks_open') @patch('ceph_volume.util.encryption.luks_format') @patch('ceph_volume.util.disk.lsblk') - def test_prepare_dmcrypt_db(self, m_lsblk, m_luks_format, m_luks_open): + def test_prepare_dmcrypt_db(self, m_lsblk, m_luks_format, m_luks_open, m_create_key): m_lsblk.return_value = {'KNAME': 'foo'} m_luks_format.return_value = True m_luks_open.return_value = True - result = raw.prepare.prepare_dmcrypt('foo', '/dev/foo', 'db', '123') - m_luks_open.assert_called_with('foo', '/dev/foo', 'ceph-123-foo-db-dmcrypt') - m_luks_format.assert_called_with('foo', '/dev/foo') - assert result == '/dev/mapper/ceph-123-foo-db-dmcrypt' + self._setup(db_device_path='/dev/db-foo', + osd_fsid='456', + secrets=dict(dmcrypt_key='foo')) + self.p.objectstore.prepare_dmcrypt() + m_luks_open.assert_called_with('foo', '/dev/db-foo', 'ceph-456-foo-db-dmcrypt') + m_luks_format.assert_called_with('foo', '/dev/db-foo') + assert self.p.objectstore.__dict__['db_device_path'] == '/dev/mapper/ceph-456-foo-db-dmcrypt' @patch('ceph_volume.util.encryption.luks_open') @patch('ceph_volume.util.encryption.luks_format') @patch('ceph_volume.util.disk.lsblk') - def test_prepare_dmcrypt_wal(self, m_lsblk, m_luks_format, m_luks_open): + def test_prepare_dmcrypt_wal(self, m_lsblk, m_luks_format, m_luks_open, m_create_key): m_lsblk.return_value = {'KNAME': 'foo'} m_luks_format.return_value = True m_luks_open.return_value = True - result = raw.prepare.prepare_dmcrypt('foo', '/dev/foo', 'wal', '123') - m_luks_open.assert_called_with('foo', '/dev/foo', 'ceph-123-foo-wal-dmcrypt') - m_luks_format.assert_called_with('foo', '/dev/foo') - assert result == '/dev/mapper/ceph-123-foo-wal-dmcrypt' + self._setup(wal_device_path='/dev/wal-foo', + osd_fsid='789', + secrets=dict(dmcrypt_key='foo')) + self.p.objectstore.prepare_dmcrypt() + m_luks_open.assert_called_with('foo', '/dev/wal-foo', 'ceph-789-foo-wal-dmcrypt') + m_luks_format.assert_called_with('foo', '/dev/wal-foo') + assert self.p.objectstore.__dict__['wal_device_path'] == '/dev/mapper/ceph-789-foo-wal-dmcrypt' - @patch('ceph_volume.devices.raw.prepare.rollback_osd') - @patch('ceph_volume.devices.raw.prepare.Prepare.prepare') + @patch('ceph_volume.objectstore.rawbluestore.rollback_osd') + @patch('ceph_volume.objectstore.rawbluestore.RawBlueStore.prepare') @patch('ceph_volume.util.arg_validators.ValidRawDevice.__call__') - def test_safe_prepare_exception_raised(self, m_valid_device, m_prepare, m_rollback_osd): + def test_safe_prepare_exception_raised(self, m_valid_device, m_prepare, m_rollback_osd, m_create_key): m_valid_device.return_value = '/dev/foo' m_prepare.side_effect=Exception('foo') m_rollback_osd.return_value = 'foobar' diff --git a/src/ceph-volume/ceph_volume/tests/objectstore/test_baseobjectstore.py b/src/ceph-volume/ceph_volume/tests/objectstore/test_baseobjectstore.py new file mode 100644 index 000000000000..248adf66e9e4 --- /dev/null +++ b/src/ceph-volume/ceph_volume/tests/objectstore/test_baseobjectstore.py @@ -0,0 +1,162 @@ +import pytest +from mock.mock import patch, Mock, call +from ceph_volume.objectstore.baseobjectstore import BaseObjectStore +from ceph_volume.util import system + + +@patch('ceph_volume.objectstore.baseobjectstore.prepare_utils.create_key', Mock(return_value=['AQCee6ZkzhOrJRAAZWSvNC3KdXOpC2w8ly4AZQ=='])) +class TestBaseObjectStore: + def test_init_dmcrypt(self, factory): + args = factory(dmcrypt=True) + bo = BaseObjectStore(args) + assert bo.encrypted == 1 + assert bo.cephx_lockbox_secret == ['AQCee6ZkzhOrJRAAZWSvNC3KdXOpC2w8ly4AZQ=='] + assert bo.secrets['cephx_lockbox_secret'] == ['AQCee6ZkzhOrJRAAZWSvNC3KdXOpC2w8ly4AZQ=='] + + @patch('ceph_volume.process.call', Mock(return_value=(['c6798f59-01'], '', 0))) + def test_get_ptuuid_ok(self): + """ + Test that the ptuuid is returned + """ + assert BaseObjectStore([]).get_ptuuid('/dev/sda') == 'c6798f59-01' + + @patch('ceph_volume.process.call', Mock(return_value=('', '', 0))) + def test_get_ptuuid_raises_runtime_error(self, capsys): + """ + Test that the ptuuid is returned + """ + with pytest.raises(RuntimeError) as error: + bo = BaseObjectStore([]) + bo.get_ptuuid('/dev/sda') + stdout, stderr = capsys.readouterr() + assert 'blkid could not detect a PARTUUID for device: /dev/sda' in stderr + assert str(error.value) == 'unable to use device' + + @patch.dict('os.environ', {'CEPH_VOLUME_OSDSPEC_AFFINITY': 'foo'}) + def test_get_osdspec_affinity(self): + assert BaseObjectStore([]).get_osdspec_affinity() == 'foo' + + def test_pre_prepare(self): + with pytest.raises(NotImplementedError): + BaseObjectStore([]).pre_prepare() + + def test_prepare_data_device(self): + with pytest.raises(NotImplementedError): + BaseObjectStore([]).prepare_data_device('foo', 'bar') + + def test_safe_prepare(self): + with pytest.raises(NotImplementedError): + BaseObjectStore([]).safe_prepare(args=None) + + def test_add_objectstore_opts(self): + with pytest.raises(NotImplementedError): + BaseObjectStore([]).add_objectstore_opts() + + @patch('ceph_volume.util.prepare.create_osd_path') + @patch('ceph_volume.util.prepare.link_block') + @patch('ceph_volume.util.prepare.get_monmap') + @patch('ceph_volume.util.prepare.write_keyring') + def test_prepare_osd_req(self, m_write_keyring, m_get_monmap, m_link_block, m_create_osd_path): + bo = BaseObjectStore([]) + bo.osd_id = '123' + bo.block_device_path = '/dev/foo' + bo.prepare_osd_req() + assert m_create_osd_path.mock_calls == [call('123', tmpfs=True)] + assert m_link_block.mock_calls == [call('/dev/foo', '123')] + assert m_get_monmap.mock_calls == [call('123')] + assert m_write_keyring.mock_calls == [call('123', ['AQCee6ZkzhOrJRAAZWSvNC3KdXOpC2w8ly4AZQ=='])] + + def test_prepare(self): + with pytest.raises(NotImplementedError): + BaseObjectStore([]).prepare() + + def test_prepare_dmcrypt(self): + with pytest.raises(NotImplementedError): + BaseObjectStore([]).prepare_dmcrypt() + + def test_cluster_fsid_from_args(self, factory): + args = factory(cluster_fsid='abcd') + bo = BaseObjectStore(args) + assert bo.get_cluster_fsid() == 'abcd' + + def test_cluster_fsid_from_conf(self, conf_ceph_stub, factory): + args = factory(cluster_fsid=None) + conf_ceph_stub('[global]\nfsid = abcd-123') + bo = BaseObjectStore([]) + bo.args = args + assert bo.get_cluster_fsid() == 'abcd-123' + + @patch('ceph_volume.conf.cluster', 'ceph') + def test_get_osd_path(self): + bo = BaseObjectStore([]) + bo.osd_id = '123' + assert bo.get_osd_path() == '/var/lib/ceph/osd/ceph-123/' + + @patch('ceph_volume.conf.cluster', 'ceph') + def test_build_osd_mkfs_cmd_base(self): + bo = BaseObjectStore([]) + bo.osd_path = '/var/lib/ceph/osd/ceph-123/' + bo.osd_fsid = 'abcd-1234' + bo.objectstore = 'my-fake-objectstore' + bo.osd_id = '123' + bo.monmap = '/etc/ceph/ceph.monmap' + result = bo.build_osd_mkfs_cmd() + + assert result == ['ceph-osd', + '--cluster', + 'ceph', + '--osd-objectstore', + 'my-fake-objectstore', + '--mkfs', '-i', '123', + '--monmap', + '/etc/ceph/ceph.monmap', + '--keyfile', '-', + '--osd-data', + '/var/lib/ceph/osd/ceph-123/', + '--osd-uuid', 'abcd-1234', + '--setuser', 'ceph', + '--setgroup', 'ceph'] + + def test_osd_mkfs_ok(self, monkeypatch, fake_call): + bo = BaseObjectStore([]) + bo.get_osd_path = lambda: '/var/lib/ceph/osd/ceph-123/' + bo.build_osd_mkfs_cmd = lambda: ['ceph-osd', '--mkfs', 'some', 'fake', 'args'] + monkeypatch.setattr(system, 'chown', lambda path: 0) + bo.osd_mkfs() + assert fake_call.calls == [ + { + 'args': (['ceph-osd', + '--mkfs', + 'some', + 'fake', + 'args'],), + 'kwargs': { + 'stdin': ['AQCee6ZkzhOrJRAAZWSvNC3KdXOpC2w8ly4AZQ=='], + 'terminal_verbose': True, + 'show_command': True} + } + ] + + @patch('ceph_volume.process.call', Mock(return_value=([], [], 999))) + def test_osd_mkfs_fails(self, monkeypatch): + bo = BaseObjectStore([]) + bo.get_osd_path = lambda: '/var/lib/ceph/osd/ceph-123/' + bo.build_osd_mkfs_cmd = lambda: ['ceph-osd', '--mkfs', 'some', 'fake', 'args'] + monkeypatch.setattr(system, 'chown', lambda path: 0) + with pytest.raises(RuntimeError) as error: + bo.osd_mkfs() + assert str(error.value) == 'Command failed with exit code 999: ceph-osd --mkfs some fake args' + + @patch('time.sleep', Mock()) + @patch('ceph_volume.process.call', return_value=([], [], 11)) + def test_osd_mkfs_fails_EWOULDBLOCK(self, m_call, monkeypatch): + bo = BaseObjectStore([]) + bo.get_osd_path = lambda: '/var/lib/ceph/osd/ceph-123/' + bo.build_osd_mkfs_cmd = lambda: ['ceph-osd', '--mkfs', 'some', 'fake', 'args'] + monkeypatch.setattr(system, 'chown', lambda path: 0) + bo.osd_mkfs() + assert m_call.call_count == 5 + + def test_activate(self): + with pytest.raises(NotImplementedError): + BaseObjectStore([]).activate() diff --git a/src/ceph-volume/ceph_volume/tests/objectstore/test_bluestore.py b/src/ceph-volume/ceph_volume/tests/objectstore/test_bluestore.py new file mode 100644 index 000000000000..77bb383284ee --- /dev/null +++ b/src/ceph-volume/ceph_volume/tests/objectstore/test_bluestore.py @@ -0,0 +1,27 @@ +from mock import patch, Mock +from ceph_volume.objectstore.bluestore import BlueStore + + +class TestBlueStore: + @patch('ceph_volume.objectstore.baseobjectstore.prepare_utils.create_key', Mock(return_value=['AQCee6ZkzhOrJRAAZWSvNC3KdXOpC2w8ly4AZQ=='])) + def setup_method(self, m_create_key): + self.b = BlueStore([]) + self.b.osd_mkfs_cmd = ['binary', 'arg1'] + + def test_add_objectstore_opts_wal_device_path(self, monkeypatch): + monkeypatch.setattr('ceph_volume.util.system.chown', lambda path: 0) + self.b.wal_device_path = '/dev/nvme0n1' + self.b.add_objectstore_opts() + assert self.b.osd_mkfs_cmd == ['binary', 'arg1', '--bluestore-block-wal-path', '/dev/nvme0n1'] + + def test_add_objectstore_opts_db_device_path(self, monkeypatch): + monkeypatch.setattr('ceph_volume.util.system.chown', lambda path: 0) + self.b.db_device_path = '/dev/ssd1' + self.b.add_objectstore_opts() + assert self.b.osd_mkfs_cmd == ['binary', 'arg1', '--bluestore-block-db-path', '/dev/ssd1'] + + def test_add_objectstore_opts_osdspec_affinity(self, monkeypatch): + monkeypatch.setattr('ceph_volume.util.system.chown', lambda path: 0) + self.b.get_osdspec_affinity = lambda: 'foo' + self.b.add_objectstore_opts() + assert self.b.osd_mkfs_cmd == ['binary', 'arg1', '--osdspec-affinity', 'foo'] \ No newline at end of file diff --git a/src/ceph-volume/ceph_volume/tests/objectstore/test_lvmbluestore.py b/src/ceph-volume/ceph_volume/tests/objectstore/test_lvmbluestore.py new file mode 100644 index 000000000000..49872bb6a80d --- /dev/null +++ b/src/ceph-volume/ceph_volume/tests/objectstore/test_lvmbluestore.py @@ -0,0 +1,561 @@ +import pytest +from mock import patch, Mock, MagicMock, call +from ceph_volume.objectstore.lvmbluestore import LvmBlueStore +from ceph_volume.api.lvm import Volume +from ceph_volume.util import system + + +class TestLvmBlueStore: + @patch('ceph_volume.objectstore.lvmbluestore.prepare_utils.create_key', Mock(return_value=['AQCee6ZkzhOrJRAAZWSvNC3KdXOpC2w8ly4AZQ=='])) + def setup_method(self, m_create_key): + self.lvm_bs = LvmBlueStore([]) + + @patch('ceph_volume.conf.cluster', 'ceph') + @patch('ceph_volume.api.lvm.get_single_lv') + @patch('ceph_volume.objectstore.lvmbluestore.prepare_utils.create_id', Mock(return_value='111')) + @patch('ceph_volume.objectstore.lvmbluestore.encryption_utils.create_dmcrypt_key', Mock(return_value='fake-dmcrypt-key')) + def test_pre_prepare_lv(self, m_get_single_lv, factory): + args = factory(cluster_fsid='abcd', + osd_fsid='abc123', + crush_device_class='ssd', + osd_id='111', + data='vg_foo/lv_foo') + m_get_single_lv.return_value = Volume(lv_name='lv_foo', + lv_path='/fake-path', + vg_name='vg_foo', + lv_tags='', + lv_uuid='fake-uuid') + self.lvm_bs.encrypted = True + self.lvm_bs.args = args + self.lvm_bs.pre_prepare() + assert self.lvm_bs.secrets['dmcrypt_key'] == 'fake-dmcrypt-key' + assert self.lvm_bs.secrets['crush_device_class'] == 'ssd' + assert self.lvm_bs.osd_id == '111' + assert self.lvm_bs.block_device_path == '/fake-path' + assert self.lvm_bs.tags == {'ceph.osd_fsid': 'abc123', + 'ceph.osd_id': '111', + 'ceph.cluster_fsid': 'abcd', + 'ceph.cluster_name': 'ceph', + 'ceph.crush_device_class': 'ssd', + 'ceph.osdspec_affinity': '', + 'ceph.block_device': '/fake-path', + 'ceph.block_uuid': 'fake-uuid', + 'ceph.cephx_lockbox_secret': '', + 'ceph.encrypted': True, + 'ceph.vdo': '0'} + + @patch('ceph_volume.objectstore.lvmbluestore.prepare_utils.create_id', Mock(return_value='111')) + @patch('ceph_volume.objectstore.lvmbluestore.encryption_utils.create_dmcrypt_key', Mock(return_value='fake-dmcrypt-key')) + def test_pre_prepare_no_lv(self, factory): + args = factory(cluster_fsid='abcd', + osd_fsid='abc123', + crush_device_class='ssd', + osd_id='111', + data='/dev/foo') + self.lvm_bs.prepare_data_device = lambda x, y: Volume(lv_name='lv_foo', + lv_path='/fake-path', + vg_name='vg_foo', + lv_tags='', + lv_uuid='fake-uuid') + self.lvm_bs.encrypted = True + self.lvm_bs.args = args + self.lvm_bs.pre_prepare() + assert self.lvm_bs.secrets['dmcrypt_key'] == 'fake-dmcrypt-key' + assert self.lvm_bs.secrets['crush_device_class'] == 'ssd' + assert self.lvm_bs.osd_id == '111' + assert self.lvm_bs.block_device_path == '/fake-path' + assert self.lvm_bs.tags == {'ceph.osd_fsid': 'abc123', + 'ceph.osd_id': '111', + 'ceph.cluster_fsid': 'abcd', + 'ceph.cluster_name': None, + 'ceph.crush_device_class': 'ssd', + 'ceph.osdspec_affinity': '', + 'ceph.block_device': '/fake-path', + 'ceph.block_uuid': 'fake-uuid', + 'ceph.cephx_lockbox_secret': '', + 'ceph.encrypted': True, + 'ceph.vdo': '0'} + + @patch('ceph_volume.util.disk.is_partition', Mock(return_value=True)) + @patch('ceph_volume.api.lvm.create_lv') + def test_prepare_data_device(self, m_create_lv, factory): + args = factory(data='/dev/foo', + data_slots=1, + data_size=102400) + self.lvm_bs.args = args + m_create_lv.return_value = Volume(lv_name='lv_foo', + lv_path='/fake-path', + vg_name='vg_foo', + lv_tags='', + lv_uuid='abcd') + assert self.lvm_bs.prepare_data_device('block', 'abcd') == m_create_lv.return_value + assert self.lvm_bs.args.data_size == 102400 + + @patch('ceph_volume.util.disk.is_device', Mock(return_value=False)) + @patch('ceph_volume.util.disk.is_partition', Mock(return_value=False)) + def test_prepare_data_device_fails(self, factory): + args = factory(data='/dev/foo') + self.lvm_bs.args = args + with pytest.raises(RuntimeError) as error: + self.lvm_bs.prepare_data_device('block', 'abcd') + assert ('Cannot use device (/dev/foo). ' + 'A vg/lv path or an existing device is needed') == str(error.value) + + @patch('ceph_volume.api.lvm.is_ceph_device', Mock(return_value=True)) + @patch('ceph_volume.api.lvm.get_single_lv') + def test_safe_prepare_is_ceph_device(self, m_get_single_lv, factory): + args = factory(data='/dev/foo') + self.lvm_bs.args = args + m_get_single_lv.return_value = Volume(lv_name='lv_foo', + lv_path='/fake-path', + vg_name='vg_foo', + lv_tags='', + lv_uuid='fake-uuid') + self.lvm_bs.prepare = MagicMock() + with pytest.raises(RuntimeError) as error: + self.lvm_bs.safe_prepare(args) + assert str(error.value) == 'skipping /dev/foo, it is already prepared' + + @patch('ceph_volume.api.lvm.is_ceph_device', Mock(return_value=False)) + @patch('ceph_volume.api.lvm.get_single_lv') + def test_safe_prepare(self, m_get_single_lv, factory): + args = factory(data='vg_foo/lv_foo') + self.lvm_bs.args = args + m_get_single_lv.return_value = Volume(lv_name='lv_foo', + lv_path='/fake-path', + vg_name='vg_foo', + lv_tags='', + lv_uuid='fake-uuid') + self.lvm_bs.prepare = MagicMock() + self.lvm_bs.safe_prepare() + assert self.lvm_bs.prepare.called + + @patch('ceph_volume.objectstore.lvmbluestore.LvmBlueStore.prepare', Mock(side_effect=Exception)) + @patch('ceph_volume.api.lvm.is_ceph_device', Mock(return_value=False)) + # @patch('ceph_volume.devices.lvm.common.rollback_osd') + @patch('ceph_volume.objectstore.lvmbluestore.rollback_osd') + @patch('ceph_volume.api.lvm.get_single_lv') + def test_safe_prepare_raises_exception(self, m_get_single_lv, m_rollback_osd, factory): + args = factory(data='/dev/foo') + self.lvm_bs.args = args + self.lvm_bs.osd_id = '111' + m_get_single_lv.return_value = Volume(lv_name='lv_foo', + lv_path='/fake-path', + vg_name='vg_foo', + lv_tags='', + lv_uuid='fake-uuid') + m_rollback_osd.return_value = MagicMock() + with pytest.raises(Exception): + self.lvm_bs.safe_prepare() + assert m_rollback_osd.mock_calls == [call(self.lvm_bs.args, '111')] + + @patch('ceph_volume.objectstore.baseobjectstore.BaseObjectStore.get_ptuuid', Mock(return_value='c6798f59-01')) + @patch('ceph_volume.api.lvm.Volume.set_tags', MagicMock()) + @patch('ceph_volume.api.lvm.get_single_lv') + def test_prepare(self, m_get_single_lv, factory): + m_get_single_lv.return_value = Volume(lv_name='lv_foo', + lv_path='/fake-path', + vg_name='vg_foo', + lv_tags='', + lv_uuid='fake-uuid') + args = factory(data='vg_foo/lv_foo', + block_wal='/dev/foo1', + block_db='/dev/foo2', + block_wal_size=123, + block_db_size=123, + block_wal_slots=1, + block_db_slots=1, + ) + self.lvm_bs.args = args + self.lvm_bs.pre_prepare = lambda: None + self.lvm_bs.block_lv = MagicMock() + self.lvm_bs.prepare_osd_req = MagicMock() + self.lvm_bs.osd_mkfs = MagicMock() + self.lvm_bs.prepare_dmcrypt = MagicMock() + self.lvm_bs.secrets['dmcrypt_key'] = 'fake-secret' + self.lvm_bs.prepare() + assert self.lvm_bs.wal_device_path == '/dev/foo1' + assert self.lvm_bs.db_device_path == '/dev/foo2' + assert self.lvm_bs.block_lv.set_tags.mock_calls == [call({'ceph.type': 'block', 'ceph.vdo': '0', 'ceph.wal_uuid': 'c6798f59-01', 'ceph.wal_device': '/dev/foo1', 'ceph.db_uuid': 'c6798f59-01', 'ceph.db_device': '/dev/foo2'})] + assert self.lvm_bs.prepare_dmcrypt.called + assert self.lvm_bs.osd_mkfs.called + assert self.lvm_bs.prepare_osd_req.called + + def test_prepare_dmcrypt(self): + self.lvm_bs.secrets = {'dmcrypt_key': 'fake-secret'} + self.lvm_bs.tags = {'ceph.block_uuid': 'block-uuid1', + 'ceph.db_uuid': 'db-uuid2', + 'ceph.wal_uuid': 'wal-uuid3'} + self.lvm_bs.luks_format_and_open = lambda *a: f'/dev/mapper/{a[3]["ceph."+a[2]+"_uuid"]}' + self.lvm_bs.prepare_dmcrypt() + assert self.lvm_bs.block_device_path == '/dev/mapper/block-uuid1' + assert self.lvm_bs.db_device_path == '/dev/mapper/db-uuid2' + assert self.lvm_bs.wal_device_path == '/dev/mapper/wal-uuid3' + + @patch('ceph_volume.objectstore.lvmbluestore.encryption_utils.luks_open') + @patch('ceph_volume.objectstore.lvmbluestore.encryption_utils.luks_format') + def test_luks_format_and_open(self, m_luks_format, m_luks_open): + result = self.lvm_bs.luks_format_and_open('key', + '/dev/foo', + 'block', + {'ceph.block_uuid': 'block-uuid1'}) + assert result == '/dev/mapper/block-uuid1' + + def test_luks_format_and_open_not_device(self): + result = self.lvm_bs.luks_format_and_open('key', + '', + 'block', + {}) + assert result == '' + + def test_setup_device_is_none(self): + result = self.lvm_bs.setup_device('block', + None, + {}, + 1, + 1) + assert result == ('', '', {}) + + @patch('ceph_volume.api.lvm.Volume.set_tags', return_value=MagicMock()) + @patch('ceph_volume.util.system.generate_uuid', + Mock(return_value='d83fa1ca-bd68-4c75-bdc2-464da58e8abd')) + @patch('ceph_volume.api.lvm.create_lv') + @patch('ceph_volume.util.disk.is_device', Mock(return_value=True)) + def test_setup_device_is_device(self, m_create_lv, m_set_tags): + m_create_lv.return_value = Volume(lv_name='lv_foo', + lv_path='/fake-path', + vg_name='vg_foo', + lv_tags='', + lv_uuid='fake-uuid') + result = self.lvm_bs.setup_device('block', + '/dev/foo', + {}, + 1, + 1) + assert m_create_lv.mock_calls == [call('osd-block', + 'd83fa1ca-bd68-4c75-bdc2-464da58e8abd', + device='/dev/foo', + tags={'ceph.type': 'block', + 'ceph.vdo': '0', + 'ceph.block_device': '/fake-path', + 'ceph.block_uuid': 'fake-uuid'}, + slots=1, + size=1)] + assert result == ('/fake-path', + 'fake-uuid', + {'ceph.type': 'block', + 'ceph.vdo': '0', + 'ceph.block_device': '/fake-path', + 'ceph.block_uuid': 'fake-uuid' + }) + + @patch('ceph_volume.api.lvm.get_single_lv') + @patch('ceph_volume.api.lvm.Volume.set_tags', return_value=MagicMock()) + def test_setup_device_is_lv(self, m_set_tags, m_get_single_lv): + m_get_single_lv.return_value = Volume(lv_name='lv_foo', + lv_path='/fake-path', + vg_name='vg_foo', + lv_tags='', + lv_uuid='fake-uuid') + result = self.lvm_bs.setup_device('block', + 'vg_foo/lv_foo', + {}, + 1, + 1) + assert result == ('/fake-path', + 'fake-uuid', + {'ceph.type': 'block', + 'ceph.vdo': '0', + 'ceph.block_device': '/fake-path', + 'ceph.block_uuid': 'fake-uuid' + }) + + @patch('ceph_volume.api.lvm.Volume.set_tags', return_value=MagicMock()) + def test_setup_device_partition(self, m_set_tags): + self.lvm_bs.get_ptuuid = lambda x: 'c6798f59-01' + result = self.lvm_bs.setup_device('block', + '/dev/foo1', + {}, + 1, + 1) + assert result == ('/dev/foo1', + 'c6798f59-01', + {'ceph.type': 'block', + 'ceph.vdo': '0', + 'ceph.block_uuid': 'c6798f59-01', + 'ceph.block_device': '/dev/foo1'}) + + def test_get_osd_device_path_lv_block(self): + lvs = [Volume(lv_name='lv_foo', + lv_path='/fake-path', + vg_name='vg_foo', + lv_tags='ceph.type=block,ceph.block_uuid=fake-block-uuid', + lv_uuid='fake-block-uuid')] + assert self.lvm_bs.get_osd_device_path(lvs, 'block') == '/fake-path' + + @patch('ceph_volume.objectstore.lvmbluestore.encryption_utils.luks_open', MagicMock()) + def test_get_osd_device_path_lv_block_encrypted(self): + lvs = [Volume(lv_name='lv_foo', + lv_path='/fake-path', + vg_name='vg_foo', + lv_tags='ceph.type=block,ceph.block_uuid=fake-block-uuid,ceph.encrypted=1', + lv_uuid='fake-block-uuid')] + assert self.lvm_bs.get_osd_device_path(lvs, 'block') == '/dev/mapper/fake-block-uuid' + + def test_get_osd_device_path_lv_db(self): + lvs = [Volume(lv_name='lv_foo-block', + lv_path='/fake-block-path', + vg_name='vg_foo', + lv_tags='ceph.type=block,ceph.block_uuid=fake-block-uuid,ceph.db_uuid=fake-db-uuid', + lv_uuid='fake-block-uuid'), + Volume(lv_name='lv_foo-db', + lv_path='/fake-db-path', + vg_name='vg_foo_db', + lv_tags='ceph.type=db,ceph.block_uuid=fake-block-uuid,ceph.db_uuid=fake-db-uuid', + lv_uuid='fake-db-uuid')] + assert self.lvm_bs.get_osd_device_path(lvs, 'db') == '/fake-db-path' + + def test_get_osd_device_path_no_device_uuid(self): + lvs = [Volume(lv_name='lv_foo-block', + lv_path='/fake-block-path', + vg_name='vg_foo', + lv_tags='ceph.type=block,ceph.block_uuid=fake-block-uuid', + lv_uuid='fake-block-uuid'), + Volume(lv_name='lv_foo-db', + lv_path='/fake-db-path', + vg_name='vg_foo_db', + lv_tags='ceph.type=db,ceph.block_uuid=fake-block-uuid', + lv_uuid='fake-db-uuid')] + assert not self.lvm_bs.get_osd_device_path(lvs, 'db') + + @patch('ceph_volume.util.disk.get_device_from_partuuid') + @patch('ceph_volume.objectstore.lvmbluestore.encryption_utils.luks_open', MagicMock()) + def test_get_osd_device_path_phys_encrypted(self, m_get_device_from_partuuid): + m_get_device_from_partuuid.return_value = '/dev/sda1' + lvs = [Volume(lv_name='lv_foo-block', + lv_path='/fake-block-path', + vg_name='vg_foo', + lv_tags='ceph.type=block,ceph.block_uuid=fake-block-uuid,ceph.db_uuid=fake-db-uuid,ceph.osd_id=0,ceph.osd_fsid=abcd,ceph.cluster_name=ceph,ceph.encrypted=1', + lv_uuid='fake-block-uuid')] + assert self.lvm_bs.get_osd_device_path(lvs, 'db') == '/dev/mapper/fake-db-uuid' + + @patch('ceph_volume.util.disk.get_device_from_partuuid') + def test_get_osd_device_path_phys(self, m_get_device_from_partuuid): + m_get_device_from_partuuid.return_value = '/dev/sda1' + lvs = [Volume(lv_name='lv_foo-block', + lv_path='/fake-block-path', + vg_name='vg_foo', + lv_tags='ceph.type=block,ceph.block_uuid=fake-block-uuid,ceph.db_uuid=fake-db-uuid,ceph.osd_id=0,ceph.osd_fsid=abcd,ceph.cluster_name=ceph', + lv_uuid='fake-block-uuid')] + self.lvm_bs.get_osd_device_path(lvs, 'db') + + @patch('ceph_volume.util.disk.get_device_from_partuuid') + def test_get_osd_device_path_phys_raises_exception(self, m_get_device_from_partuuid): + m_get_device_from_partuuid.return_value = '' + lvs = [Volume(lv_name='lv_foo-block', + lv_path='/fake-block-path', + vg_name='vg_foo', + lv_tags='ceph.type=block,ceph.block_uuid=fake-block-uuid,ceph.db_uuid=fake-db-uuid,ceph.osd_id=0,ceph.osd_fsid=abcd,ceph.cluster_name=ceph', + lv_uuid='fake-block-uuid')] + with pytest.raises(RuntimeError): + self.lvm_bs.get_osd_device_path(lvs, 'db') + + def test__activate_raises_exception(self): + lvs = [Volume(lv_name='lv_foo-db', + lv_path='/fake-path', + vg_name='vg_foo', + lv_tags='ceph.type=db,ceph.db_uuid=fake-db-uuid', + lv_uuid='fake-db-uuid')] + with pytest.raises(RuntimeError) as error: + self.lvm_bs._activate(lvs) + assert str(error.value) == 'could not find a bluestore OSD to activate' + + @patch('ceph_volume.objectstore.lvmbluestore.encryption_utils.write_lockbox_keyring', MagicMock()) + @patch('ceph_volume.objectstore.lvmbluestore.encryption_utils.get_dmcrypt_key', MagicMock()) + @patch('ceph_volume.objectstore.lvmbluestore.prepare_utils.create_osd_path') + @patch('ceph_volume.terminal.success') + @pytest.mark.parametrize("encrypted", ["ceph.encrypted=0", "ceph.encrypted=1"]) + def test__activate(self, + m_success, m_create_osd_path, + monkeypatch, fake_run, fake_call, encrypted, conf_ceph_stub): + conf_ceph_stub('[global]\nfsid=asdf-lkjh') + monkeypatch.setattr(system, 'chown', lambda path: 0) + monkeypatch.setattr('ceph_volume.configuration.load', lambda: None) + monkeypatch.setattr('ceph_volume.util.system.path_is_mounted', lambda path: False) + m_create_osd_path.return_value = MagicMock() + m_success.return_value = MagicMock() + lvs = [Volume(lv_name='lv_foo-block', + lv_path='/fake-block-path', + vg_name='vg_foo', + lv_tags=f'ceph.type=block,ceph.db_uuid=fake-db-uuid,ceph.block_uuid=fake-block-uuid,ceph.wal_uuid=fake-wal-uuid,ceph.osd_id=0,ceph.osd_fsid=abcd,ceph.cluster_name=ceph,{encrypted},ceph.cephx_lockbox_secret=abcd', + lv_uuid='fake-block-uuid'), + Volume(lv_name='lv_foo-db', + lv_path='/fake-db-path', + vg_name='vg_foo_db', + lv_tags=f'ceph.type=db,ceph.db_uuid=fake-db-uuid,ceph.block_uuid=fake-block-uuid,ceph.wal_uuid=fake-wal-uuid,ceph.osd_id=0,ceph.osd_fsid=abcd,ceph.cluster_name=ceph,{encrypted},ceph.cephx_lockbox_secret=abcd', + lv_uuid='fake-db-uuid'), + Volume(lv_name='lv_foo-db', + lv_path='/fake-db-path', + vg_name='vg_foo_db', + lv_tags=f'ceph.type=wal,ceph.block_uuid=fake-block-uuid,ceph.wal_uuid=fake-wal-uuid,ceph.db_uuid=fake-db-uuid,ceph.osd_id=0,ceph.osd_fsid=abcd,ceph.cluster_name=ceph,{encrypted},ceph.cephx_lockbox_secret=abcd', + lv_uuid='fake-wal-uuid')] + self.lvm_bs._activate(lvs) + if encrypted == "ceph.encrypted=0": + assert fake_run.calls == [{'args': (['ceph-bluestore-tool', '--cluster=ceph', + 'prime-osd-dir', '--dev', '/fake-block-path', + '--path', '/var/lib/ceph/osd/ceph-0', '--no-mon-config'],), + 'kwargs': {}}, + {'args': (['ln', '-snf', '/fake-block-path', + '/var/lib/ceph/osd/ceph-0/block'],), + 'kwargs': {}}, + {'args': (['ln', '-snf', '/fake-db-path', + '/var/lib/ceph/osd/ceph-0/block.db'],), + 'kwargs': {}}, + {'args': (['ln', '-snf', '/fake-db-path', + '/var/lib/ceph/osd/ceph-0/block.wal'],), + 'kwargs': {}}, + {'args': (['systemctl', 'enable', + 'ceph-volume@lvm-0-abcd'],), + 'kwargs': {}}, + {'args': (['systemctl', 'enable', '--runtime', 'ceph-osd@0'],), + 'kwargs': {}}, + {'args': (['systemctl', 'start', 'ceph-osd@0'],), + 'kwargs': {}}] + else: + assert fake_run.calls == [{'args': (['ceph-bluestore-tool', '--cluster=ceph', + 'prime-osd-dir', '--dev', '/dev/mapper/fake-block-uuid', + '--path', '/var/lib/ceph/osd/ceph-0', '--no-mon-config'],), + 'kwargs': {}}, + {'args': (['ln', '-snf', '/dev/mapper/fake-block-uuid', + '/var/lib/ceph/osd/ceph-0/block'],), + 'kwargs': {}}, + {'args': (['ln', '-snf', '/dev/mapper/fake-db-uuid', + '/var/lib/ceph/osd/ceph-0/block.db'],), + 'kwargs': {}}, + {'args': (['ln', '-snf', '/dev/mapper/fake-wal-uuid', + '/var/lib/ceph/osd/ceph-0/block.wal'],), + 'kwargs': {}}, + {'args': (['systemctl', 'enable', 'ceph-volume@lvm-0-abcd'],), + 'kwargs': {}}, + {'args': (['systemctl', 'enable', '--runtime', 'ceph-osd@0'],), + 'kwargs': {}}, + {'args': (['systemctl', 'start', 'ceph-osd@0'],), + 'kwargs': {}}] + assert m_success.mock_calls == [call('ceph-volume lvm activate successful for osd ID: 0')] + + @patch('ceph_volume.systemd.systemctl.osd_is_active', return_value=False) + def test_activate_all(self, + mock_lvm_direct_report, + factory, + fake_run): + args = factory(no_systemd=True) + self.lvm_bs.args = args + self.lvm_bs.activate = MagicMock() + self.lvm_bs.activate_all() + assert self.lvm_bs.activate.mock_calls == [call(args, + osd_id='1', + osd_fsid='824f7edf-371f-4b75-9231-4ab62a32d5c0'), + call(args, + osd_id='0', + osd_fsid='a0e07c5b-bee1-4ea2-ae07-cb89deda9b27')] + + @patch('ceph_volume.systemd.systemctl.osd_is_active', return_value=False) + def test_activate_all_no_osd_found(self, + factory, + fake_run, + monkeypatch, + capsys): + monkeypatch.setattr('ceph_volume.objectstore.lvmbluestore.direct_report', lambda: {}) + args = factory(no_systemd=True) + self.lvm_bs.args = args + self.lvm_bs.activate_all() + stdout, stderr = capsys.readouterr() + assert "Was unable to find any OSDs to activate" in stderr + assert "Verify OSDs are present with" in stderr + + @patch('ceph_volume.systemd.systemctl.osd_is_active', return_value=True) + def test_activate_all_osd_is_active(self, + mock_lvm_direct_report, + factory, + fake_run): + args = factory(no_systemd=False) + self.lvm_bs.args = args + self.lvm_bs.activate = MagicMock() + self.lvm_bs.activate_all() + assert self.lvm_bs.activate.mock_calls == [] + + @patch('ceph_volume.api.lvm.get_lvs') + def test_activate_osd_id_and_fsid(self, + m_get_lvs, + factory): + args = factory(osd_id='1', + osd_fsid='824f7edf', + no_systemd=True) + lvs = [Volume(lv_name='lv_foo', + lv_path='/fake-path', + vg_name='vg_foo', + lv_tags=f'ceph.osd_id={args.osd_id},ceph.osd_fsid={args.osd_fsid}', + lv_uuid='fake-uuid')] + m_get_lvs.return_value = lvs + self.lvm_bs.args = args + self.lvm_bs._activate = MagicMock() + self.lvm_bs.activate() + assert self.lvm_bs._activate.mock_calls == [call(lvs, True, False)] + assert m_get_lvs.mock_calls == [call(tags={'ceph.osd_id': '1', + 'ceph.osd_fsid': '824f7edf'})] + + @patch('ceph_volume.api.lvm.get_lvs') + def test_activate_not_osd_id_and_fsid(self, + m_get_lvs, + factory): + args = factory(no_systemd=True, + osd_id=None, + osd_fsid='824f7edf') + lvs = [Volume(lv_name='lv_foo', + lv_path='/fake-path', + vg_name='vg_foo', + lv_tags='', + lv_uuid='fake-uuid')] + m_get_lvs.return_value = lvs + self.lvm_bs.args = args + self.lvm_bs._activate = MagicMock() + self.lvm_bs.activate() + assert self.lvm_bs._activate.mock_calls == [call(lvs, True, False)] + assert m_get_lvs.mock_calls == [call(tags={'ceph.osd_fsid': '824f7edf'})] + + def test_activate_osd_id_and_not_fsid(self, + factory): + args = factory(no_systemd=True, + osd_id='1', + osd_fsid=None) + self.lvm_bs.args = args + self.lvm_bs._activate = MagicMock() + with pytest.raises(RuntimeError) as error: + self.lvm_bs.activate() + assert str(error.value) == 'could not activate osd.1, please provide the osd_fsid too' + + def test_activate_not_osd_id_and_not_fsid(self, + factory): + args = factory(no_systemd=True, + osd_id=None, + osd_fsid=None) + self.lvm_bs.args = args + self.lvm_bs._activate = MagicMock() + with pytest.raises(RuntimeError) as error: + self.lvm_bs.activate() + assert str(error.value) == 'Please provide both osd_id and osd_fsid' + + @patch('ceph_volume.api.lvm.get_lvs') + def test_activate_couldnt_find_osd(self, + m_get_lvs, + factory): + args = factory(osd_id='1', + osd_fsid='824f7edf', + no_systemd=True) + lvs = [] + m_get_lvs.return_value = lvs + self.lvm_bs.args = args + self.lvm_bs._activate = MagicMock() + with pytest.raises(RuntimeError) as error: + self.lvm_bs.activate() + assert str(error.value) == 'could not find osd.1 with osd_fsid 824f7edf' \ No newline at end of file diff --git a/src/ceph-volume/ceph_volume/tests/objectstore/test_rawbluestore.py b/src/ceph-volume/ceph_volume/tests/objectstore/test_rawbluestore.py new file mode 100644 index 000000000000..4e9861b8b34c --- /dev/null +++ b/src/ceph-volume/ceph_volume/tests/objectstore/test_rawbluestore.py @@ -0,0 +1,156 @@ +import pytest +from mock import patch, Mock, MagicMock, call +from ceph_volume.objectstore.rawbluestore import RawBlueStore +from ceph_volume.util import system + + +class TestRawBlueStore: + @patch('ceph_volume.objectstore.rawbluestore.prepare_utils.create_key', Mock(return_value=['AQCee6ZkzhOrJRAAZWSvNC3KdXOpC2w8ly4AZQ=='])) + def setup_method(self, m_create_key): + self.raw_bs = RawBlueStore([]) + + def test_prepare_dmcrypt(self, + device_info, + fake_call, + key_size): + self.raw_bs.secrets = {'dmcrypt_key': 'foo'} + self.raw_bs.block_device_path = '/dev/foo0' + self.raw_bs.db_device_path = '/dev/foo1' + self.raw_bs.wal_device_path = '/dev/foo2' + lsblk = {"TYPE": "disk", + "NAME": "foo0", + 'KNAME': 'foo0'} + device_info(lsblk=lsblk) + self.raw_bs.prepare_dmcrypt() + assert self.raw_bs.block_device_path == "/dev/mapper/ceph--foo0-block-dmcrypt" + assert self.raw_bs.db_device_path == "/dev/mapper/ceph--foo0-db-dmcrypt" + assert self.raw_bs.wal_device_path == "/dev/mapper/ceph--foo0-wal-dmcrypt" + + @patch('ceph_volume.objectstore.rawbluestore.rollback_osd') + @patch('ceph_volume.objectstore.rawbluestore.RawBlueStore.prepare') + def test_safe_prepare_raises_exception(self, + m_prepare, + m_rollback_osd, + factory, + capsys): + m_prepare.side_effect = Exception + m_rollback_osd.return_value = MagicMock() + args = factory(osd_id='1') + self.raw_bs.args = args + self.raw_bs.osd_id = self.raw_bs.args.osd_id + with pytest.raises(Exception): + self.raw_bs.safe_prepare() + assert m_rollback_osd.mock_calls == [call(self.raw_bs.args, '1')] + + @patch('ceph_volume.objectstore.rawbluestore.RawBlueStore.prepare', MagicMock()) + def test_safe_prepare(self, + factory, + capsys): + args = factory(dmcrypt=True, + data='/dev/foo') + # self.raw_bs.args = args + self.raw_bs.safe_prepare(args) + stdout, stderr = capsys.readouterr() + assert "prepare successful for: /dev/foo" in stderr + + # @patch('ceph_volume.objectstore.rawbluestore.prepare_utils.create_id') + # @patch('ceph_volume.objectstore.rawbluestore.system.generate_uuid', return_value='fake-uuid') + @patch.dict('os.environ', {'CEPH_VOLUME_DMCRYPT_SECRET': 'dmcrypt-key'}) + @patch('ceph_volume.objectstore.rawbluestore.prepare_utils.create_id') + @patch('ceph_volume.objectstore.rawbluestore.system.generate_uuid') + def test_prepare(self, m_generate_uuid, m_create_id, factory): + m_generate_uuid.return_value = 'fake-uuid' + m_create_id.return_value = MagicMock() + self.raw_bs.prepare_dmcrypt = MagicMock() + self.raw_bs.prepare_osd_req = MagicMock() + self.raw_bs.osd_mkfs = MagicMock() + args = factory(crush_device_class='foo', + no_tmpfs=False, + block_wal='/dev/foo1', + block_db='/dev/foo2',) + self.raw_bs.args = args + self.raw_bs.secrets = dict() + self.raw_bs.encrypted = True + self.raw_bs.prepare() + assert self.raw_bs.prepare_osd_req.mock_calls == [call(tmpfs=True)] + assert self.raw_bs.osd_mkfs.called + assert self.raw_bs.prepare_dmcrypt.called + + @patch('ceph_volume.conf.cluster', 'ceph') + @patch('ceph_volume.objectstore.rawbluestore.prepare_utils.link_wal') + @patch('ceph_volume.objectstore.rawbluestore.prepare_utils.link_db') + @patch('ceph_volume.objectstore.rawbluestore.prepare_utils.link_block') + @patch('os.path.exists') + @patch('os.unlink') + @patch('ceph_volume.objectstore.rawbluestore.prepare_utils.create_osd_path') + @patch('ceph_volume.objectstore.rawbluestore.process.run') + def test__activate(self, + m_run, + m_create_osd_path, + m_unlink, + m_exists, + m_link_block, + m_link_db, + m_link_wal, + monkeypatch): + meta = dict(osd_id='1', + osd_uuid='fake-uuid', + device='/dev/foo', + device_db='/dev/foo1', + device_wal='/dev/foo2') + m_run.return_value = MagicMock() + m_exists.side_effect = lambda path: True + m_create_osd_path.return_value = MagicMock() + m_unlink.return_value = MagicMock() + monkeypatch.setattr(system, 'chown', lambda path: 0) + monkeypatch.setattr(system, 'path_is_mounted', lambda path: 0) + self.raw_bs._activate(meta, True) + calls = [call('/var/lib/ceph/osd/ceph-1/block'), + call('/var/lib/ceph/osd/ceph-1/block.db'), + call('/var/lib/ceph/osd/ceph-1/block.wal')] + assert m_run.mock_calls == [call(['ceph-bluestore-tool', + 'prime-osd-dir', + '--path', '/var/lib/ceph/osd/ceph-1', + '--no-mon-config', '--dev', '/dev/foo'])] + assert m_unlink.mock_calls == calls + assert m_exists.mock_calls == calls + assert m_create_osd_path.mock_calls == [call('1', tmpfs=True)] + + def test_activate_raises_exception(self, + mock_raw_direct_report): + with pytest.raises(RuntimeError) as error: + self.raw_bs.activate([], + '123', + 'fake-uuid', + True) + assert str(error.value) == 'did not find any matching OSD to activate' + + def test_activate_osd_id(self, + mock_raw_direct_report): + self.raw_bs._activate = MagicMock() + self.raw_bs.activate([], + '8', + '824f7edf-371f-4b75-9231-4ab62a32d5c0', + True) + self.raw_bs._activate.mock_calls == [call({'ceph_fsid': '7dccab18-14cf-11ee-837b-5254008f8ca5', + 'device': '/dev/mapper/ceph--40bc7bd7--4aee--483e--ba95--89a64bc8a4fd-osd--block--824f7edf--371f--4b75--9231--4ab62a32d5c0', + 'device_db': '/dev/mapper/ceph--73d6d4db--6528--48f2--a4e2--1c82bc87a9ac-osd--db--b82d920d--be3c--4e4d--ba64--18f7e8445892', + 'osd_id': 8, + 'osd_uuid': '824f7edf-371f-4b75-9231-4ab62a32d5c0', + 'type': 'bluestore'}, + tmpfs=True)] + + def test_activate_osd_fsid(self, + mock_raw_direct_report): + self.raw_bs._activate = MagicMock() + with pytest.raises(RuntimeError): + self.raw_bs.activate([], + '8', + 'a0e07c5b-bee1-4ea2-ae07-cb89deda9b27', + True) + self.raw_bs._activate.mock_calls == [call({'ceph_fsid': '7dccab18-14cf-11ee-837b-5254008f8ca5', + 'device': '/dev/mapper/ceph--e34cc3f5--a70d--49df--82b3--46bcbd63d4b0-osd--block--a0e07c5b--bee1--4ea2--ae07--cb89deda9b27', + 'osd_id': 9, + 'osd_uuid': 'a0e07c5b-bee1-4ea2-ae07-cb89deda9b27', + 'type': 'bluestore'}, + tmpfs=True)] \ No newline at end of file diff --git a/src/ceph-volume/ceph_volume/tests/util/test_disk.py b/src/ceph-volume/ceph_volume/tests/util/test_disk.py index b287530dc17f..da2cedae1be2 100644 --- a/src/ceph-volume/ceph_volume/tests/util/test_disk.py +++ b/src/ceph-volume/ceph_volume/tests/util/test_disk.py @@ -544,7 +544,14 @@ class TestSizeSpecificFormatting(object): class TestAllowLoopDevsWarning(object): + def setup(self): + disk.AllowLoopDevices.allow = False + disk.AllowLoopDevices.warned = False + if os.environ.get('CEPH_VOLUME_ALLOW_LOOP_DEVICES'): + os.environ.pop('CEPH_VOLUME_ALLOW_LOOP_DEVICES') + def test_loop_dev_warning(self, fake_call, caplog): + disk.AllowLoopDevices.warned = False assert disk.allow_loop_devices() is False assert not caplog.records os.environ['CEPH_VOLUME_ALLOW_LOOP_DEVICES'] = "y" diff --git a/src/ceph-volume/ceph_volume/tests/util/test_prepare.py b/src/ceph-volume/ceph_volume/tests/util/test_prepare.py index ee9774ecc833..c45beb45c7a1 100644 --- a/src/ceph-volume/ceph_volume/tests/util/test_prepare.py +++ b/src/ceph-volume/ceph_volume/tests/util/test_prepare.py @@ -5,6 +5,8 @@ from ceph_volume.util import prepare from ceph_volume.util.prepare import system from ceph_volume import conf from ceph_volume.tests.conftest import Factory +from ceph_volume import objectstore +from mock.mock import patch class TestOSDIDAvailable(object): @@ -117,28 +119,43 @@ class TestFormatDevice(object): class TestOsdMkfsBluestore(object): + def setup(self): + conf.cluster = 'ceph' def test_keyring_is_added(self, fake_call, monkeypatch): monkeypatch.setattr(system, 'chown', lambda path: True) - prepare.osd_mkfs_bluestore(1, 'asdf', keyring='secret') - assert '--keyfile' in fake_call.calls[0]['args'][0] + o = objectstore.baseobjectstore.BaseObjectStore([]) + o.osd_id = '1' + o.osd_fsid = 'asdf' + o.osd_mkfs() + assert '--keyfile' in fake_call.calls[2]['args'][0] def test_keyring_is_not_added(self, fake_call, monkeypatch): monkeypatch.setattr(system, 'chown', lambda path: True) - prepare.osd_mkfs_bluestore(1, 'asdf') + o = objectstore.bluestore.BlueStore([]) + o.osd_id = '1' + o.osd_fsid = 'asdf' + o.osd_mkfs() assert '--keyfile' not in fake_call.calls[0]['args'][0] - def test_wal_is_added(self, fake_call, monkeypatch): + def test_wal_is_added(self, fake_call, monkeypatch, objectstore_bluestore): monkeypatch.setattr(system, 'chown', lambda path: True) - prepare.osd_mkfs_bluestore(1, 'asdf', wal='/dev/smm1') - assert '--bluestore-block-wal-path' in fake_call.calls[0]['args'][0] - assert '/dev/smm1' in fake_call.calls[0]['args'][0] + bs = objectstore_bluestore(objecstore='bluestore', + osd_id='1', + osd_fid='asdf', + wal_device_path='/dev/smm1', + cephx_secret='foo',) + bs.osd_mkfs() + assert '--bluestore-block-wal-path' in fake_call.calls[2]['args'][0] + assert '/dev/smm1' in fake_call.calls[2]['args'][0] def test_db_is_added(self, fake_call, monkeypatch): monkeypatch.setattr(system, 'chown', lambda path: True) - prepare.osd_mkfs_bluestore(1, 'asdf', db='/dev/smm2') - assert '--bluestore-block-db-path' in fake_call.calls[0]['args'][0] - assert '/dev/smm2' in fake_call.calls[0]['args'][0] + bs = objectstore.bluestore.BlueStore([]) + bs.db_device_path = '/dev/smm2' + bs.osd_mkfs() + assert '--bluestore-block-db-path' in fake_call.calls[2]['args'][0] + assert '/dev/smm2' in fake_call.calls[2]['args'][0] class TestMountOSD(object): @@ -263,23 +280,29 @@ class TestNormalizeFlags(object): result = sorted(prepare._normalize_mount_flags(flags, extras=['discard','rw']).split(',')) assert ','.join(result) == 'auto,discard,exec,rw' - +@patch('ceph_volume.util.prepare.create_key', return_value='fake-secret') class TestMkfsBluestore(object): - def test_non_zero_exit_status(self, stub_call, monkeypatch): + def test_non_zero_exit_status(self, m_create_key, stub_call, monkeypatch, objectstore_bluestore): conf.cluster = 'ceph' monkeypatch.setattr('ceph_volume.util.prepare.system.chown', lambda x: True) stub_call(([], [], 1)) + bs = objectstore_bluestore(osd_id='1', + osd_fsid='asdf-1234', + cephx_secret='keyring') with pytest.raises(RuntimeError) as error: - prepare.osd_mkfs_bluestore('1', 'asdf-1234', keyring='keyring') + bs.osd_mkfs() assert "Command failed with exit code 1" in str(error.value) - def test_non_zero_exit_formats_command_correctly(self, stub_call, monkeypatch): + def test_non_zero_exit_formats_command_correctly(self, m_create_key, stub_call, monkeypatch, objectstore_bluestore): conf.cluster = 'ceph' monkeypatch.setattr('ceph_volume.util.prepare.system.chown', lambda x: True) stub_call(([], [], 1)) + bs = objectstore_bluestore(osd_id='1', + osd_fsid='asdf-1234', + cephx_secret='keyring') with pytest.raises(RuntimeError) as error: - prepare.osd_mkfs_bluestore('1', 'asdf-1234', keyring='keyring') + bs.osd_mkfs() expected = ' '.join([ 'ceph-osd', '--cluster',