]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
ceph-volume: add objectstore unit tests
authorGuillaume Abrioux <gabrioux@ibm.com>
Tue, 4 Jul 2023 12:47:59 +0000 (12:47 +0000)
committerGuillaume Abrioux <gabrioux@redhat.com>
Wed, 15 May 2024 09:12:56 +0000 (09:12 +0000)
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 <gabrioux@ibm.com>
(cherry picked from commit f06dad9bf93dd1671419932a1853b963c39d229d)

15 files changed:
src/ceph-volume/ceph_volume/objectstore/lvmbluestore.py
src/ceph-volume/ceph_volume/tests/api/test_lvm.py
src/ceph-volume/ceph_volume/tests/conftest.py
src/ceph-volume/ceph_volume/tests/devices/lvm/test_activate.py
src/ceph-volume/ceph_volume/tests/devices/lvm/test_batch.py
src/ceph-volume/ceph_volume/tests/devices/lvm/test_migrate.py
src/ceph-volume/ceph_volume/tests/devices/lvm/test_prepare.py
src/ceph-volume/ceph_volume/tests/devices/lvm/test_zap.py
src/ceph-volume/ceph_volume/tests/devices/raw/test_prepare.py
src/ceph-volume/ceph_volume/tests/objectstore/test_baseobjectstore.py [new file with mode: 0644]
src/ceph-volume/ceph_volume/tests/objectstore/test_bluestore.py [new file with mode: 0644]
src/ceph-volume/ceph_volume/tests/objectstore/test_lvmbluestore.py [new file with mode: 0644]
src/ceph-volume/ceph_volume/tests/objectstore/test_rawbluestore.py [new file with mode: 0644]
src/ceph-volume/ceph_volume/tests/util/test_disk.py
src/ceph-volume/ceph_volume/tests/util/test_prepare.py

index a76502e3bffc93f3df5ae8c0f454470afa6f8f08..5dc46361e92ec71ddfb549cba0882facacfcafcb 100644 (file)
@@ -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':
index 139328b4a0d576aec9371608084c748c7ec65356..9ad2f701f1298b58f80b1d0b549732f14f7fb893 100644 (file)
@@ -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'))
index 7a7c57d9721dc09a348de231383b8a050f3001bd..4a6820852efba43fa48a720954a989adfb8fff6a 100644 (file)
@@ -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
index 5d48a0ef4044f5ffac82ed50e643fbd1a94a8f1a..6f38097a1ab9fddc6af37a6c1d6c62a5201875f8 100644 (file)
@@ -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
index 51072da120a911ccb02c01895a7ab32140b048df..e26a733b09cd020b737e3cddadb752436efc2227 100644 (file)
@@ -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
 
index 91e6155f38cd92a97bd7b8604bd2728b58c7a0e0..13f4acb075c1fd2312f85544ee3359050653d866 100644 (file)
@@ -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',
index 0a356988eebc5151d9c685d243810e48e3aba597..7f51896ea8f6fc3531c56e6fa3b82221d1672918 100644 (file)
@@ -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()
 
index 2446c5ed6651e36aacb081677deef856cfb47ee8..51f66abfc78053a3e277542581cdf02a5adc8b4f 100644 (file)
@@ -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'})
         ]
index f814bbf136b7bc920771874987aac1dca6bbacb4..0802f923249868d579f0c441d86230ecf34de0c8 100644 (file)
@@ -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 (file)
index 0000000..248adf6
--- /dev/null
@@ -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 (file)
index 0000000..77bb383
--- /dev/null
@@ -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 (file)
index 0000000..49872bb
--- /dev/null
@@ -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 (file)
index 0000000..4e9861b
--- /dev/null
@@ -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
index b287530dc17fcf8a91bb26fe14229bd8d2d38974..da2cedae1be2c46bb2638673e22fcfa834730ac2 100644 (file)
@@ -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"
index ee9774ecc833c98ddb4297638375d46c93349c04..c45beb45c7a14bb992e2bdbf0dab575932160e14 100644 (file)
@@ -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',