Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ceph-volume allow filtering by uuid, do not require osd id #17606

Merged
merged 12 commits into from
Sep 11, 2017
Merged
5 changes: 4 additions & 1 deletion src/ceph-volume/ceph_volume/devices/lvm/activate.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ def __init__(self, argv):
def activate(self, args):
lvs = api.Volumes()
# filter them down for the OSD ID and FSID we need to activate
lvs.filter(lv_tags={'ceph.osd_id': args.osd_id, 'ceph.osd_fsid': args.osd_fsid})
if args.osd_id and args.osd_fsid:
lvs.filter(lv_tags={'ceph.osd_id': args.osd_id, 'ceph.osd_fsid': args.osd_fsid})
elif args.osd_fsid and not args.osd_id:
lvs.filter(lv_tags={'ceph.osd_fsid': args.osd_fsid})
if not lvs:
raise RuntimeError('could not find osd.%s with fsid %s' % (args.osd_id, args.osd_fsid))
activate_filestore(lvs)
Expand Down
32 changes: 13 additions & 19 deletions src/ceph-volume/ceph_volume/devices/lvm/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,13 +284,10 @@ def _filter(self, vg_name=None, vg_tags=None):
# actual filtered list if any filters were applied
if vg_tags:
tag_filtered = []
for k, v in vg_tags.items():
for volume in filtered:
if volume.tags.get(k) == str(v):
if volume not in tag_filtered:
tag_filtered.append(volume)
# return the tag_filtered volumes here, the `filtered` list is no
# longer useable
for volume in filtered:
matches = all(volume.tags.get(k) == str(v) for k, v in vg_tags.items())
if matches:
tag_filtered.append(volume)
return tag_filtered

return filtered
Expand Down Expand Up @@ -390,13 +387,11 @@ def _filter(self, lv_name=None, vg_name=None, lv_path=None, lv_uuid=None, lv_tag
# actual filtered list if any filters were applied
if lv_tags:
tag_filtered = []
for k, v in lv_tags.items():
for volume in filtered:
if volume.tags.get(k) == str(v):
if volume not in tag_filtered:
tag_filtered.append(volume)
# return the tag_filtered volumes here, the `filtered` list is no
# longer useable
for volume in filtered:
# all the tags we got need to match on the volume
matches = all(volume.tags.get(k) == str(v) for k, v in lv_tags.items())
if matches:
tag_filtered.append(volume)
return tag_filtered

return filtered
Expand Down Expand Up @@ -493,11 +488,10 @@ def _filter(self, pv_name=None, pv_uuid=None, pv_tags=None):
# or is an actual filtered list if any filters were applied
if pv_tags:
tag_filtered = []
for k, v in pv_tags.items():
for pvolume in filtered:
if pvolume.tags.get(k) == str(v):
if pvolume not in tag_filtered:
tag_filtered.append(pvolume)
for pvolume in filtered:
matches = all(pvolume.tags.get(k) == str(v) for k, v in pv_tags.items())
if matches:
tag_filtered.append(pvolume)
# return the tag_filtered pvolumes here, the `filtered` list is no
# longer useable
return tag_filtered
Expand Down
2 changes: 1 addition & 1 deletion src/ceph-volume/ceph_volume/devices/lvm/trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def parse_osd_id(string):
def parse_osd_uuid(string):
osd_id = '%s-' % parse_osd_id(string)
# remove the id first
osd_uuid = string.split(osd_id)[-1]
osd_uuid = string.split(osd_id, 1)[-1]
if not osd_uuid:
raise SuffixParsingError('OSD uuid', string)
return osd_uuid
Expand Down
26 changes: 26 additions & 0 deletions src/ceph-volume/ceph_volume/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pytest
from ceph_volume.devices.lvm import api

class Capture(object):

Expand All @@ -14,3 +15,28 @@ def __call__(self, *a, **kw):
@pytest.fixture
def capture():
return Capture()


@pytest.fixture
def volumes(monkeypatch):
monkeypatch.setattr('ceph_volume.process.call', lambda x: ('', '', 0))
volumes = api.Volumes()
volumes._purge()
return volumes


@pytest.fixture
def volume_groups(monkeypatch):
monkeypatch.setattr('ceph_volume.process.call', lambda x: ('', '', 0))
vgs = api.VolumeGroups()
vgs._purge()
return vgs


@pytest.fixture
def is_root(monkeypatch):
"""
Patch ``os.getuid()`` so that ceph-volume's decorators that ensure a user
is root (or is sudoing to superuser) can continue as-is
"""
monkeypatch.setattr('os.getuid', lambda: 0)
34 changes: 34 additions & 0 deletions src/ceph-volume/ceph_volume/tests/devices/lvm/test_activate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import pytest
from ceph_volume.devices.lvm import activate, api


class Args(object):

def __init__(self, **kw):
for k, v in kw.items():
setattr(self, k, v)


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(self, is_root, volumes, monkeypatch, capture):
FooVolume = api.Volume(lv_name='foo', lv_path='/dev/vg/foo', lv_tags="ceph.osd_fsid=1234")
volumes.append(FooVolume)
monkeypatch.setattr(api, 'Volumes', lambda: volumes)
monkeypatch.setattr(activate, 'activate_filestore', capture)
args = Args(osd_id=None, osd_fsid='1234')
activate.Activate([]).activate(args)
assert capture.calls[0]['args'][0] == [FooVolume]

def test_no_osd_id_no_matching_fsid(self, is_root, volumes, monkeypatch, capture):
FooVolume = api.Volume(lv_name='foo', lv_path='/dev/vg/foo', lv_tags="ceph.osd_fsid=11234")
volumes.append(FooVolume)
monkeypatch.setattr(api, 'Volumes', lambda: volumes)
monkeypatch.setattr(activate, 'activate_filestore', capture)
args = Args(osd_id=None, osd_fsid='1234')
with pytest.raises(RuntimeError):
activate.Activate([]).activate(args)
53 changes: 46 additions & 7 deletions src/ceph-volume/ceph_volume/tests/devices/lvm/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,35 @@ def test_single_pv_is_matched(self, pvolumes, monkeypatch):
monkeypatch.setattr(api, 'PVolumes', lambda: pvolumes)
assert api.get_pv(pv_uuid='0000') == FooPVolume

def test_single_pv_is_matched_by_uuid(self, volumes, monkeypatch):
FooVolume = api.Volume(
lv_name='foo', lv_path='/dev/vg/foo',
lv_uuid='1111', lv_tags="ceph.type=data")
volumes.append(FooVolume)
monkeypatch.setattr(api, 'Volumes', lambda: volumes)
assert api.get_lv(lv_uuid='1111') == FooVolume
def test_single_pv_is_matched_by_uuid(self, pvolumes, monkeypatch):
FooPVolume = api.PVolume(
pv_name='/dev/vg/foo',
pv_uuid='1111', pv_tags="ceph.type=data")
pvolumes.append(FooPVolume)
monkeypatch.setattr(api, 'PVolumes', lambda: pvolumes)
assert api.get_pv(pv_uuid='1111') == FooPVolume


class TestPVolumes(object):

def test_filter_by_tag_does_not_match_one(self, pvolumes, monkeypatch):
pv_tags = "ceph.type=journal,ceph.osd_id=1,ceph.fsid=000-aaa"
FooPVolume = api.PVolume(
pv_name='/dev/vg/foo',
pv_uuid='1111', pv_tags=pv_tags)
pvolumes.append(FooPVolume)
pvolumes.filter(pv_tags={'ceph.type': 'journal', 'ceph.osd_id': '2'})
assert pvolumes == []

def test_filter_by_tags_matches(self, pvolumes, monkeypatch):
pv_tags = "ceph.type=journal,ceph.osd_id=1"
FooPVolume = api.PVolume(
pv_name='/dev/vg/foo',
pv_uuid='1111', pv_tags=pv_tags)
pvolumes.append(FooPVolume)
pvolumes.filter(pv_tags={'ceph.type': 'journal', 'ceph.osd_id': '1'})
assert pvolumes == [FooPVolume]


class TestGetVG(object):

Expand Down Expand Up @@ -184,6 +206,16 @@ def test_filter_by_tag(self, volumes):
assert len(volumes) == 1
assert volumes[0].lv_name == 'volume1'

def test_filter_by_tag_does_not_match_one(self, volumes):
lv_tags = "ceph.type=data,ceph.fsid=000-aaa"
osd = api.Volume(lv_name='volume1', lv_path='/dev/vg/lv', lv_tags=lv_tags)
journal = api.Volume(lv_name='volume2', lv_path='/dev/vg/lv', lv_tags='ceph.osd_id=1,ceph.type=journal')
volumes.append(osd)
volumes.append(journal)
# note the different osd_id!
volumes.filter(lv_tags={'ceph.type': 'data', 'ceph.osd_id': '2'})
assert volumes == []

def test_filter_by_vg_name(self, volumes):
lv_tags = "ceph.type=data,ceph.fsid=000-aaa"
osd = api.Volume(lv_name='volume1', vg_name='ceph_vg', lv_tags=lv_tags)
Expand Down Expand Up @@ -257,6 +289,13 @@ def test_filter_by_tag(self, volume_groups):
assert len(volume_groups) == 1
assert volume_groups[0].vg_name == 'volume1'

def test_filter_by_tag_does_not_match_one(self, volume_groups):
vg_tags = "ceph.group=dmcache,ceph.disk_type=ssd"
osd = api.VolumeGroup(vg_name='volume1', vg_path='/dev/vg/lv', vg_tags=vg_tags)
volume_groups.append(osd)
volume_groups.filter(vg_tags={'ceph.group': 'data', 'ceph.disk_type': 'ssd'})
assert volume_groups == []

def test_filter_by_vg_name(self, volume_groups):
vg_tags = "ceph.type=data,ceph.fsid=000-aaa"
osd = api.VolumeGroup(vg_name='ceph_vg', vg_tags=vg_tags)
Expand Down
6 changes: 6 additions & 0 deletions src/ceph-volume/ceph_volume/tests/devices/lvm/test_trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,10 @@ def test_uuid_is_not_found_missing_id(self):
with pytest.raises(exceptions.SuffixParsingError):
trigger.parse_osd_uuid('ljahs-dfa-slkjhdfa-foo')

def test_robust_double_id_in_uuid(self):
# it is possible to have the id in the SHA1, this should
# be fine parsing that
result = trigger.parse_osd_uuid("1-abc959fd-1ec9-4864-b141-3154f9b9f8ed")
assert result == 'abc959fd-1ec9-4864-b141-3154f9b9f8ed'


32 changes: 16 additions & 16 deletions src/ceph-volume/ceph_volume/tests/functional/Vagrantfile
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
(0..CLIENTS - 1).each do |i|
config.vm.define "#{LABEL_PREFIX}client#{i}" do |client|
client.vm.box = CLIENT_BOX
client.vm.hostname = "#{LABEL_PREFIX}ceph-client#{i}"
client.vm.hostname = "#{LABEL_PREFIX}client#{i}"
if ASSIGN_STATIC_IP
client.vm.network :private_network,
ip: "#{PUBLIC_SUBNET}.4#{i}"
Expand All @@ -88,7 +88,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

# Parallels
client.vm.provider "parallels" do |prl|
prl.name = "ceph-client#{i}"
prl.name = "client#{i}"
prl.memory = "#{MEMORY}"
end

Expand All @@ -102,7 +102,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.define "#{LABEL_PREFIX}rgw#{i}" do |rgw|
rgw.vm.box = BOX
rgw.vm.box_url = BOX_URL
rgw.vm.hostname = "#{LABEL_PREFIX}ceph-rgw#{i}"
rgw.vm.hostname = "#{LABEL_PREFIX}rgw#{i}"
if ASSIGN_STATIC_IP
rgw.vm.network :private_network,
ip: "#{PUBLIC_SUBNET}.5#{i}"
Expand All @@ -126,7 +126,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

# Parallels
rgw.vm.provider "parallels" do |prl|
prl.name = "ceph-rgw#{i}"
prl.name = "rgw#{i}"
prl.memory = "#{MEMORY}"
end

Expand All @@ -140,7 +140,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.define "nfs#{i}" do |nfs|
nfs.vm.box = BOX
nfs.vm.box_url = BOX_URL
nfs.vm.hostname = "ceph-nfs#{i}"
nfs.vm.hostname = "nfs#{i}"
if ASSIGN_STATIC_IP
nfs.vm.network :private_network,
ip: "#{PUBLIC_SUBNET}.6#{i}"
Expand All @@ -164,7 +164,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

# Parallels
nfs.vm.provider "parallels" do |prl|
prl.name = "ceph-nfs#{i}"
prl.name = "nfs#{i}"
prl.memory = "#{MEMORY}"
end

Expand All @@ -178,7 +178,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.define "#{LABEL_PREFIX}mds#{i}" do |mds|
mds.vm.box = BOX
mds.vm.box_url = BOX_URL
mds.vm.hostname = "#{LABEL_PREFIX}ceph-mds#{i}"
mds.vm.hostname = "#{LABEL_PREFIX}mds#{i}"
if ASSIGN_STATIC_IP
mds.vm.network :private_network,
ip: "#{PUBLIC_SUBNET}.7#{i}"
Expand All @@ -200,7 +200,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
end
# Parallels
mds.vm.provider "parallels" do |prl|
prl.name = "ceph-mds#{i}"
prl.name = "mds#{i}"
prl.memory = "#{MEMORY}"
end

Expand All @@ -214,7 +214,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.define "#{LABEL_PREFIX}rbd_mirror#{i}" do |rbd_mirror|
rbd_mirror.vm.box = BOX
rbd_mirror.vm.box_url = BOX_URL
rbd_mirror.vm.hostname = "#{LABEL_PREFIX}ceph-rbd-mirror#{i}"
rbd_mirror.vm.hostname = "#{LABEL_PREFIX}rbd-mirror#{i}"
if ASSIGN_STATIC_IP
rbd_mirror.vm.network :private_network,
ip: "#{PUBLIC_SUBNET}.8#{i}"
Expand All @@ -236,7 +236,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
end
# Parallels
rbd_mirror.vm.provider "parallels" do |prl|
prl.name = "ceph-rbd-mirror#{i}"
prl.name = "rbd-mirror#{i}"
prl.memory = "#{MEMORY}"
end

Expand All @@ -250,7 +250,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.define "#{LABEL_PREFIX}iscsi_gw#{i}" do |iscsi_gw|
iscsi_gw.vm.box = BOX
iscsi_gw.vm.box_url = BOX_URL
iscsi_gw.vm.hostname = "#{LABEL_PREFIX}ceph-iscsi-gw#{i}"
iscsi_gw.vm.hostname = "#{LABEL_PREFIX}iscsi-gw#{i}"
if ASSIGN_STATIC_IP
iscsi_gw.vm.network :private_network,
ip: "#{PUBLIC_SUBNET}.9#{i}"
Expand All @@ -272,7 +272,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
end
# Parallels
iscsi_gw.vm.provider "parallels" do |prl|
prl.name = "ceph-iscsi-gw#{i}"
prl.name = "iscsi-gw#{i}"
prl.memory = "#{MEMORY}"
end

Expand All @@ -286,7 +286,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.define "#{LABEL_PREFIX}mon#{i}" do |mon|
mon.vm.box = BOX
mon.vm.box_url = BOX_URL
mon.vm.hostname = "#{LABEL_PREFIX}ceph-mon#{i}"
mon.vm.hostname = "#{LABEL_PREFIX}mon#{i}"
if ASSIGN_STATIC_IP
mon.vm.network :private_network,
ip: "#{PUBLIC_SUBNET}.1#{i}"
Expand All @@ -309,7 +309,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

# Parallels
mon.vm.provider "parallels" do |prl|
prl.name = "ceph-mon#{i}"
prl.name = "mon#{i}"
prl.memory = "#{MEMORY}"
end

Expand All @@ -323,7 +323,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.define "#{LABEL_PREFIX}osd#{i}" do |osd|
osd.vm.box = BOX
osd.vm.box_url = BOX_URL
osd.vm.hostname = "#{LABEL_PREFIX}ceph-osd#{i}"
osd.vm.hostname = "#{LABEL_PREFIX}osd#{i}"
if ASSIGN_STATIC_IP
osd.vm.network :private_network,
ip: "#{PUBLIC_SUBNET}.10#{i}"
Expand Down Expand Up @@ -378,7 +378,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

# Parallels
osd.vm.provider "parallels" do |prl|
prl.name = "ceph-osd#{i}"
prl.name = "osd#{i}"
prl.memory = "#{MEMORY}"
(0..1).each do |d|
prl.customize ["set", :id,
Expand Down