Skip to content
This repository has been archived by the owner on Jul 27, 2023. It is now read-only.

Commit

Permalink
Devicemapper support
Browse files Browse the repository at this point in the history
  • Loading branch information
avnik committed Mar 24, 2016
1 parent ff3a46d commit e91aefa
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 25 deletions.
9 changes: 8 additions & 1 deletion roles/docker/templates/docker-volume.conf.j2
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{% if docker_lvm_backed|bool and docker_storage_driver in ["btrfs", "overlay"] %}
[volume:docker]
group = {{ volume_group_name }}
volume = {{ docker_volume_name }}
size = {{ docker_volume_size }}

{% if docker_lvm_backed|bool and docker_storage_driver in ["btrfs", "overlay"] %}
[filesystem:docker]
dev = {{ docker_volume_device }}
fstype = {{ docker_volume_fs_type }}
Expand All @@ -14,3 +14,10 @@ required_by = docker-storage-setup.service docker.service
file = /etc/sysconfig/docker-storage
content = DOCKER_STORAGE_OPTIONS=--storage-driver {{ docker_storage_driver }}
{% endif %}
{%if docker_lvm_backed|bool and docker_storage_driver == "devicemapper" %}
[thin:docker]
group = {{ volume_group_name }}
pool = {{ docker_volume_name }}
size = {{ docker_lvm_data_volume_size }}

{% endif %}
100 changes: 76 additions & 24 deletions roles/lvm/files/mantl-storage-setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@
LVCREATE_CMD = "/sbin/lvcreate"
VGEXTEND_CMD = "/sbin/vgextend"
VGREDUCE_CMD = "/sbin/vgreduce"
LVCONVERT_CMD = "/sbin/lvconvert"

systemd_units = []

def fail(*a):
sys.stderr.write("ERROR:" + " ".join(*a))
sys.stderr.write("ERROR:" + " ".join(a) + "\n")
sys.exit(1)


Expand Down Expand Up @@ -49,29 +50,41 @@ def mapper_device_name(dm_device):
return "/dev/mapper/{}".format(dm_name.rstrip())

def query_lvm(mod, o="all", extra=None):
query = [mod, "--nameprefix", "--noheadings", "-o", o, "--separator", ";"]
query = [mod, "--nameprefix", "--noheadings", "--unquoted", "-o", o, "--separator", ";"]
if extra:
query.extend(extra)
output = check_output(query)
def chunk(ch):
k, v = ch.split("=")
return k.replace("LVM2_", "").lower(), v
return k.replace("LVM2_", "").lower(), v.strip()
for line in output.splitlines():
yield dict([chunk(each) for each in line.split(";")])


def lvm_profile_dir():
return check_output(["lvm", "config", "config/profile_dir"]).splitlines()[0].split("=")[1].replace('"', "")

def pvs():
for each in query_lvm(PVS_CMD):
for each in query_lvm(PVS_CMD, o="pv_all,vg_name"):
if each["pv_name"].startswith("/dev/dm-"):
each["pv_name"] = mapper_device_name(each["pv_name"])
yield each

def vgs():
return query_lvm(VGS_CMD)

def free_space(vg, units):
return int(find_this(query_lvm(VGS_CMD, extra=["--nosuffix", "--units", units, vg]), "vg_name", vg)["vg_free"])

def lvs(vg, units):
return query_lvm(LVS_CMD, extra=["--units", units, vg])

def find_this(lst, key, val):
for each in lst:
print each
if each[key] == val:
return each

def process_vg(sec, params):
name = params.get(sec, "name")
force = optional(params.getboolean, sec, "force", False)
Expand All @@ -88,20 +101,13 @@ def process_vg(sec, params):
fail("Device not found: {}".format(test_dev))

# check pv for already used devices
parsed_pvs = pvs()
for each in parsed_pvs:
for each in pvs():
if each['pv_name'] in dev_list and each['vg_name'] != name:
fail("Device {} is already in {} volume group.".format(each['pv_name'],each['vg_name']))
if each['vg_name'] == name:
current_devs.add(os.path.realpath(each['name']))
current_devs.add(os.path.realpath(each['pv_name']))

parsed_vgs = vgs()

this = None
for test in parsed_vgs:
if test['vg_name'] == name:
this = test
break
this = find_this(vgs(), "vg_name", name)

if this:
devs_to_remove = current_devs - dev_list
Expand Down Expand Up @@ -141,15 +147,13 @@ def process_volume(sec, params):
force = optional(params.getboolean, sec, "force", False)
size, size_opt, size_unit = parse_size(size)

this = None
for test in lvs(vg, size_opt == 'l' and 'm' or size_unit):
if test['lv_name'] == lv:
this = test
this = find_this(lvs(vg, size_opt == 'l' and 'm' or size_unit), "lv_name", lv)

if not this:
print "--> Create volume {}".format(lv)
check_call([LVCREATE_CMD, "-n", lv, "-" + size_opt, str(size) + size_unit, vg])
else:
print "Volume {} already exists".format(lv)
print "--> Do nothing. Volume {} already exists".format(lv)


UNIT_TEMPLATE = """
Expand Down Expand Up @@ -180,11 +184,13 @@ def process_fs(sec, params):

# FIXME: should we stop, if it contain FS of different type?
if exist_fs != fstype:
print "--> Formatting filesystem {} with {}".format(dev, fstype)
check_call(["mkfs", "-t", fstype, dev])
else:
print "Filesystem {} already formatted".format(dev)
print "--> Do nothing. Filesystem {} already formatted".format(dev)

if params.has_option(sec, "mount"):
print "--> Create mount for {}".format(dev)
mount = params.get(sec, "mount")
mountname = mount.lstrip("/").replace("/", "-")
unit = "{}.mount".format(mountname)
Expand All @@ -195,29 +201,75 @@ def process_fs(sec, params):

if not os.path.exists(unitfile):
with closing(open(unitfile, "w")) as f:
print "--> Writing {}".format(unitfile)
f.write(UNIT_TEMPLATE.format(
what=dev,
where=mount,
type=fstype,
wanted_by=" ".join(wanted_by),
required_by=" ".join(required_by),
before=" ".join(wanted_by+required_by)))
else:
print "--> Not writing {}, it already exists".format(unitfile)
check_call(["systemctl", "enable", unit])
check_call(["systemctl", "daemon-reload"])
else:
print "--> Not mounting {}".format(dev)

def write_file(sec, params):
filename = params.get(sec, "file")
content = params.get(sec, "content")
crlf = optional(params.getboolean, sec, "crlf", True)


if not os.path.exists(filename):
with closing(open(filename, "w")) as f:
print "WRITE: " + filename
f.write(content)
if crlf:
f.write("\n")

def process_thin(sec, params):
pool = params.get(sec, "pool")
meta = optional(params.get, sec, "meta", "{}-meta".format(pool))
data = optional(params.get, sec, "data", pool)
chunk_size = optional(params.get, sec, "chunk_size", None)
extra = optional(params.get, sec, "extra_docker_params", "")
vg = params.get(sec, "group")
size = params.get(sec, "size")
size, size_opt, size_unit = parse_size(size)

this = find_this(lvs(vg, size_opt == 'l' and 'm' or size_unit), "lv_name", pool)
if this:
if not "thin" in this['lv_layout']:
fail("Volume {} exists, and it not thin pool".format(pool))
print "--> Volume {} already created".format(pool)
else:

meta_size = free_space(vg, "s") / 1000 + 1
print "--> Create meta volume {} for thin pool".format(meta)
check_call([LVCREATE_CMD, "-n", meta, "-L", str(meta_size) + "s", vg])
print "--> Create data volume {} for thin pool".format(data)
check_call([LVCREATE_CMD, "-n", data, "-" + size_opt, str(size) + size_unit, vg])
print "--> Create thin pool {}".format(pool)
convert = [LVCONVERT_CMD, "-y", "--zero", "n" ]
if chunk_size:
convert.extend(["-c", chunk_size])
convert.extend(["--thinpool", "{}/{}".format(vg, data), "--poolmetadata", "{}/{}".format(vg, meta)])
check_call(convert)

# re-read lvs after all
this = find_this(lvs(vg, size_opt == 'l' and 'm' or size_unit), "lv_name", pool)
dm_name = "/sys/dev/block/{lv_kernel_major}:{lv_kernel_minor}/dm/name".format(**this)
with closing(open(dm_name, "r")) as f:
mapper_device = f.readline().strip()

DOCKER_STORAGE_CONF = "/etc/sysconfig/docker-storage"
print "--> Write {}".format(DOCKER_STORAGE_CONF)
with closing(open(DOCKER_STORAGE_CONF, "w")) as f:
f.write("""DOCKER_STORAGE_OPTIONS=--storage-driver devicemapper --storage-opt dm.thinpooldev=/dev/mapper/{mapper} {extra}""".format(mapper=mapper_device, extra=extra))



def iterate_config(prefix, fun, cp):
for each in sorted(cp.sections()):
if each.startswith(prefix):
Expand All @@ -229,15 +281,15 @@ def main():
for each in sorted(os.listdir(dir)):
cp = ConfigParser()
fn = os.path.join(dir, each)
print "PROCESSING: " + fn
print "==> Processing: " + fn
cp.read(fn)
iterate_config("group", process_vg, cp)
iterate_config("thin", process_thin, cp)
iterate_config("volume", process_volume, cp)
iterate_config("filesystem", process_fs, cp)
iterate_config("write", write_file, cp)


print "ALL DONE!"
print "==> ALL DONE!"

if __name__ == '__main__':
main()

0 comments on commit e91aefa

Please sign in to comment.