Newer
Older
# -*- coding: utf-8 -*-
import os
from errors import LVMError
class LVM(object):
'''
'''
BIN_PATH = '/sbin'
LVM = os.path.join(BIN_PATH, 'lvm')
LVMDISKSCAN = os.path.join(BIN_PATH, 'lvmdiskscan')
LVDISPLAY = os.path.join(BIN_PATH, 'lvdisplay')
LVCREATE = os.path.join(BIN_PATH, 'lvcreate')
LVCHANGE = os.path.join(BIN_PATH, 'lvchange')
LVCONVERT = os.path.join(BIN_PATH, 'lvconvert')
LVRENAME = os.path.join(BIN_PATH, 'lvrename')
LVEXTEND = os.path.join(BIN_PATH, 'lvextend')
LVREDUCE = os.path.join(BIN_PATH, 'lvreduce')
LVREMOVE = os.path.join(BIN_PATH, 'lvremove')
PVCREATE = os.path.join(BIN_PATH, 'pvcreate')
PVREMOVE = os.path.join(BIN_PATH, 'pvremove')
PVMOVE = os.path.join(BIN_PATH, 'pvmove')
VGCREATE = os.path.join(BIN_PATH, 'vgcreate')
VGCHANGE = os.path.join(BIN_PATH, 'vgchange')
VGEXTEND = os.path.join(BIN_PATH, 'vgextend')
VGREDUCE = os.path.join(BIN_PATH, 'vgreduce')
VGREMOVE = os.path.join(BIN_PATH, 'vgremove')
DMSETUP = os.path.join(BIN_PATH, 'dmsetup')
# global class lock : do not abuse LVM/DM too much
_mutex = RWLock()
def __init__(self):
'''
'''
self.reload()
def __str__(self):
'''
'''
s = ''
for vgname, vg in self._vgs.iteritems():
s += 'VG %s (total: %s, allocated: %s, free: %s)\n' % (vgname,
vg.total, vg.allocated, vg.free)
s += ' * PV(s):\n'
for pv in vg.pvs:
s += (' %s (total: %s, allocated: %s, free: %s, format: %s)'
'\n' % (pv.name, pv.total, pv.allocated, pv.free, pv.format))
s += ' * LV(s):\n'
for lv in vg.lvs:
s += ' %s (path: %s, size: %s)' % (lv.name, lv.path,
lv.total)
return s
def _reload_pvs(self):
'''
'''
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
with self._mutex.write:
self._pvs = {}
# execute query command
(rc, output) = Exec.call([self.LVM,
'pvs',
'--nosuffix',
'--noheadings',
'--units', 'b',
'--separator', '~',
'-o', ('pv_uuid,pv_name,vg_name,pv_fmt,'
'pv_attr,dev_size,pv_size,pv_free,'
'pv_used,pv_pe_count,'
'pv_pe_alloc_count')],
merge_output = False)
if rc != 0:
raise LVMError('error getting list of PV')
# parse command output
for line in output[0].splitlines():
# extract tokens
(
p_uuid,
p_name,
p_vg,
p_format,
p_attr,
p_devsize,
p_size,
p_free,
p_used,
p_extent,
p_ext_alloc,
) = line.strip().split('~')
# if the PV is not used, set VG to None
if not len(p_vg):
p_vg = None
else:
p_vg_obj = self._vgs[p_vg]
# create PV object
pv = self._PV(self, p_vg_obj, p_uuid, p_name, p_format, p_attr,
int(p_devsize), int(p_size), int(p_free), int(p_used),
int(p_extent), int(p_ext_alloc))
# register obj
self._pvs[p_name] = pv
if p_vg:
self._vgs[p_vg]._pvs[p_name] = pv
def _reload_vgs(self):
'''
'''
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
with self._mutex.write:
self._vgs = {}
# execute query command
(rc, output) = Exec.call([self.LVM,
'vgs',
'--nosuffix',
'--noheadings',
'--units', 'b',
'--separator', '~',
'-o', ('vg_uuid,vg_name,vg_fmt,vg_attr,'
'vg_size,vg_free,vg_extent_size,'
'vg_extent_count,vg_free_count')],
merge_output = False)
if rc != 0:
raise LVMError('error getting list of VG')
# parse command output
for line in output[0].splitlines():
# extract tokens
(
v_uuid,
v_name,
v_format,
v_attr,
v_size,
v_free,
v_ext_size,
v_extent,
v_ext_free,
) = line.strip().split('~')
# create VG object
vg = self._VG(self, v_uuid, v_name, v_format, v_attr, int(v_size),
int(v_free), int(v_ext_size), int(v_extent),
int(v_ext_free))
# register object
self._vgs[v_name] = vg
def _reload_lvs(self):
'''
'''
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
with self._mutex.write:
# execute query command
(rc, output) = Exec.call([self.LVM,
'lvs',
'--nosuffix',
'--noheadings',
'--units', 'b',
'--separator', '~',
'-o', ('lv_uuid,lv_name,vg_name,lv_attr,'
'lv_size')],
merge_output = False)
if rc != 0:
raise LVMError('error getting list of LV')
# parse command output
for line in output[0].splitlines():
# extract tokens
(
l_uuid,
l_name,
l_vg,
l_attr,
l_size,
) = line.strip().split('~')
# create LV object
lv = self._LV(self, self._vgs[l_vg], l_uuid, l_name, l_attr,
l_size)
# register object
self._vgs[l_vg]._lvs[l_name] = lv
def reload(self):
# VG must be reloaded before PV
self._reload_vgs()
self._reload_pvs()
self._reload_lvs()
def get_pv(self, path):
'''
'''
with self._mutex.read:
return self._pvs[path]
def get_vg(self, name):
'''
'''
with self._mutex.read:
return self._vgs[name]
def get_lv(self, vgname, name):
'''
'''
with self._mutex.read:
return self._vgs[vgname]._lvs[name]
def dm_create(self, name, table):
'''
'''
with self._mutex.write:
rc = Exec.silent([self.DMSETUP,
'create',
name],
input=table)
if rc:
raise LVMError('failed to create DM device')
def dm_remove(self, name, force=True):
'''
'''
with self._mutex.write:
# build command arguments
argv = [self.DMSETUP, 'remove']
if force is True:
argv.append('--force')
argv.append(name)
# execute command
if Exec.silent(argv):
raise LVMError('failed to remove DM')
def dm_get_table(self, name):
'''
'''
with self._mutex.read:
rc, output = Exec.call([self.DMSETUP,
'table',
'--showkeys',
name],
merge_output=False)
table = str(output[0]).strip()
if rc or not len(table):
raise LVMError('failed to get DM table')
return table
def dm_set_table(self, name, table):
'''
'''
with self._mutex.write:
rc = Exec.silent([self.DMSETUP,
'load',
name],
input=table)
if rc:
raise LVMError('failed to change DM table')
class _Vol(object):
'''
'''
def __init__(self, mngr, vg, uuid, name, attrs):
self._mngr = mngr
self.vg = vg
self.uuid = str(uuid)
self.name = str(name)
self.attrs = str(attrs)
class _PV(_Vol):
'''
'''
def __init__(self, mngr, vg, uuid, name, format, attrs, device_size,
size, free, used, extent_total, extent_used):
super(LVM._PV, self).__init__(mngr, vg, uuid, name, attrs)
self.format = str(format)
self.device_size = int(device_size)
self.size = int(size)
self.free = int(free)
self.used = int(used)
self.extent_total = int(extent_total)
self.extent_used = int(extent_used)
class _VG(_Vol):
'''
'''
def __init__(self, mngr, uuid, name, format, attrs, size, free,
extent_size, extent_total, extent_free):
super(LVM._VG, self).__init__(mngr, self, uuid, name, attrs)
self._pvs = {}
self._lvs = {}
self.format = str(format)
self.size = int(size)
self.free = int(free)
self.extent_size = int(extent_size)
self.extent_total = int(extent_total)
self.extent_free = int(extent_free)
def create(self, name, size):
'''
'''
# execute create command
if Exec.silent([LVM.LVCREATE,
'-L', '%iB' % size,
'-n', name,
self.name]) != 0:
def remove(self, name):
'''
'''
# execute create command
if Exec.silent([LVM.LVREMOVE,
'-f',
'%s/%s' % (self.name, name)]) != 0:
raise LVMError('error removing LV')
def get_lv(self, name):
'''
'''
with self._mngr._mutex.read:
return self._lvs[name]
class _LV(_Vol):
'''
'''
def __init__(self, mngr, vg, uuid, name, attrs, size):
super(LVM._LV, self).__init__(mngr, vg, uuid, name, attrs)
self.size = int(size)
#fixme
self.path = '/dev/%s/%s' % (self.vg.name, self.name)
def dm_name(self):
'''
'''
return '%s-%s' % (self.vg.name.replace('-', '--'),
self.name.replace('-', '--'))
def dm_table(self):
'''
'''
return self._mngr.dm_get_table(self.dm_name())