author | Tero Marttila <tero.marttila@aalto.fi> |
Mon, 28 Jul 2014 13:14:53 +0300 | |
changeset 80 | b332d99f988e |
parent 69 | 468704db09c4 |
permissions | -rw-r--r-- |
5
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
1 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
2 |
Simple /sbin/lvm wrapper for handling snapshots. |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
3 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
4 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
5 |
from pvl.backup.invoke import invoke, optargs, InvokeError |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
6 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
7 |
import contextlib |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
8 |
import os.path |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
9 |
import logging |
42
43e27a3e9efe
pvlbackup-rsync-wrapper: add --snapshot-size / --snapshot-wait opts
Tero Marttila <terom@paivola.fi>
parents:
29
diff
changeset
|
10 |
import time |
5
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
11 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
12 |
log = logging.getLogger('pvl.backup.lvm') |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
13 |
|
42
43e27a3e9efe
pvlbackup-rsync-wrapper: add --snapshot-size / --snapshot-wait opts
Tero Marttila <terom@paivola.fi>
parents:
29
diff
changeset
|
14 |
# default snapshot size |
43e27a3e9efe
pvlbackup-rsync-wrapper: add --snapshot-size / --snapshot-wait opts
Tero Marttila <terom@paivola.fi>
parents:
29
diff
changeset
|
15 |
LVM_SNAPSHOT_SIZE = '5G' |
43e27a3e9efe
pvlbackup-rsync-wrapper: add --snapshot-size / --snapshot-wait opts
Tero Marttila <terom@paivola.fi>
parents:
29
diff
changeset
|
16 |
|
43e27a3e9efe
pvlbackup-rsync-wrapper: add --snapshot-size / --snapshot-wait opts
Tero Marttila <terom@paivola.fi>
parents:
29
diff
changeset
|
17 |
# number of seconds to wait for lvm snapshot to settle after unmount.. |
43e27a3e9efe
pvlbackup-rsync-wrapper: add --snapshot-size / --snapshot-wait opts
Tero Marttila <terom@paivola.fi>
parents:
29
diff
changeset
|
18 |
LVM_SNAPSHOT_WAIT = 5 |
43e27a3e9efe
pvlbackup-rsync-wrapper: add --snapshot-size / --snapshot-wait opts
Tero Marttila <terom@paivola.fi>
parents:
29
diff
changeset
|
19 |
|
61
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
20 |
# number of times to retry removal, due to lvm/udev bug.. |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
21 |
LVM_SNAPSHOT_RETRY = 5 |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
22 |
|
5
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
23 |
class LVMError (Exception) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
24 |
pass |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
25 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
26 |
class LVM (object) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
27 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
28 |
LVM VolumeGroup |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
29 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
30 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
31 |
# path to lvm2 binary |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
32 |
LVM = '/sbin/lvm' |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
33 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
34 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
35 |
# VG name |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
36 |
name = None |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
37 |
|
69
468704db09c4
pvl.backup.mount/lvm: implement optional sudo invoke
Tero Marttila <terom@paivola.fi>
parents:
61
diff
changeset
|
38 |
def __init__ (self, name, sudo=None) : |
468704db09c4
pvl.backup.mount/lvm: implement optional sudo invoke
Tero Marttila <terom@paivola.fi>
parents:
61
diff
changeset
|
39 |
""" |
468704db09c4
pvl.backup.mount/lvm: implement optional sudo invoke
Tero Marttila <terom@paivola.fi>
parents:
61
diff
changeset
|
40 |
name - VG name |
468704db09c4
pvl.backup.mount/lvm: implement optional sudo invoke
Tero Marttila <terom@paivola.fi>
parents:
61
diff
changeset
|
41 |
sudo - invoke sudo |
468704db09c4
pvl.backup.mount/lvm: implement optional sudo invoke
Tero Marttila <terom@paivola.fi>
parents:
61
diff
changeset
|
42 |
""" |
468704db09c4
pvl.backup.mount/lvm: implement optional sudo invoke
Tero Marttila <terom@paivola.fi>
parents:
61
diff
changeset
|
43 |
|
5
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
44 |
self.name = name |
69
468704db09c4
pvl.backup.mount/lvm: implement optional sudo invoke
Tero Marttila <terom@paivola.fi>
parents:
61
diff
changeset
|
45 |
self.sudo = sudo |
5
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
46 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
47 |
def lv_name (self, lv) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
48 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
49 |
vg/lv name. |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
50 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
51 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
52 |
return '{vg}/{lv}'.format(vg=self.name, lv=lv) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
53 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
54 |
def lv_path (self, lv) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
55 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
56 |
/dev/vg/lv path. |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
57 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
58 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
59 |
return '/dev/{vg}/{lv}'.format(vg=self.name, lv=lv) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
60 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
61 |
def command (self, cmd, *args, **opts) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
62 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
63 |
Invoke a command with options/arguments, given via Python arguments/keyword arguments |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
64 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
65 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
66 |
log.debug("{cmd} {opts} {args}".format(cmd=cmd, args=args, opts=opts)) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
67 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
68 |
# invoke |
69
468704db09c4
pvl.backup.mount/lvm: implement optional sudo invoke
Tero Marttila <terom@paivola.fi>
parents:
61
diff
changeset
|
69 |
invoke(self.LVM, [cmd] + optargs(*args, **opts), sudo=self.sudo) |
5
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
70 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
71 |
def volume (self, name) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
72 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
73 |
Return an LVMVolume for given named LV. |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
74 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
75 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
76 |
return LVMVolume(self, name) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
77 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
78 |
@contextlib.contextmanager |
61
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
79 |
def snapshot (self, base, wait=LVM_SNAPSHOT_WAIT, retry=LVM_SNAPSHOT_RETRY, **opts) : |
5
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
80 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
81 |
A Context Manager for handling an LVMSnapshot. |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
82 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
83 |
See LVMSnapshot.create() |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
84 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
85 |
with lvm.snapshot(lv) as snapshot : ... |
42
43e27a3e9efe
pvlbackup-rsync-wrapper: add --snapshot-size / --snapshot-wait opts
Tero Marttila <terom@paivola.fi>
parents:
29
diff
changeset
|
86 |
|
43e27a3e9efe
pvlbackup-rsync-wrapper: add --snapshot-size / --snapshot-wait opts
Tero Marttila <terom@paivola.fi>
parents:
29
diff
changeset
|
87 |
wait - wait given interval for the snapshot device to settle before unmounting it |
61
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
88 |
retry - retry removal given number of times |
42
43e27a3e9efe
pvlbackup-rsync-wrapper: add --snapshot-size / --snapshot-wait opts
Tero Marttila <terom@paivola.fi>
parents:
29
diff
changeset
|
89 |
**opts - LVMSnapshot.create() options (e.g. size) |
5
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
90 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
91 |
|
61
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
92 |
log.debug("creating snapshot from {base}: wait={wait}, retry={retry} {opts}".format(base=base, wait=wait, retry=retry, opts=opts)) |
42
43e27a3e9efe
pvlbackup-rsync-wrapper: add --snapshot-size / --snapshot-wait opts
Tero Marttila <terom@paivola.fi>
parents:
29
diff
changeset
|
93 |
snapshot = LVMSnapshot.create(self, base, **opts) |
5
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
94 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
95 |
try : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
96 |
log.debug("got: {0}".format(snapshot)) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
97 |
yield snapshot |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
98 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
99 |
finally: |
61
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
100 |
# XXX: there's some common udev bug with removing lvm snapshots |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
101 |
# https://bugzilla.redhat.com/show_bug.cgi?id=577798 |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
102 |
# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=618016 |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
103 |
# possibly fixed in lvm2 2.02.86? |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
104 |
# try to just patiently wait for it to settle down... then retry... if this isn't enough, we need some dmremove magic? |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
105 |
while True : |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
106 |
# wait.. |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
107 |
if wait : |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
108 |
log.debug("%s: cleanup: waiting %.2f seconds for snapshot volume to settle...", snapshot, wait) |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
109 |
time.sleep(wait) |
29
5abd153d78eb
lvm: try and workaround an umount -> lvremove udev timing bug with a time.sleep(1)
Tero Marttila <terom@paivola.fi>
parents:
10
diff
changeset
|
110 |
|
61
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
111 |
# lvremove |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
112 |
try : |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
113 |
log.debug("%s: cleanup", snapshot) |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
114 |
snapshot.close() |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
115 |
|
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
116 |
except InvokeError as ex : |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
117 |
if ex.exit != 5 : |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
118 |
# lvremove sez "Can't remove open logical volume ..." -> exit(5); |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
119 |
raise |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
120 |
|
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
121 |
# retry counter? |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
122 |
if retry : |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
123 |
log.warn("%s: cleanup: lvremove failed, retrying...", snapshot) |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
124 |
retry -= 1 |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
125 |
|
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
126 |
# retry |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
127 |
continue |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
128 |
|
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
129 |
else : |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
130 |
# failed |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
131 |
log.error("%s: cleanup: lvremove failed, aborting...", snapshot) |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
132 |
raise |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
133 |
|
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
134 |
else : |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
135 |
# done |
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
136 |
break |
5
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
137 |
|
10 | 138 |
def __str__ (self) : |
139 |
return self.name |
|
140 |
||
5
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
141 |
def __repr__ (self) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
142 |
return "LVM(name={name})".format(name=repr(self.name)) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
143 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
144 |
class LVMVolume (object) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
145 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
146 |
LVM Logical Volume. |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
147 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
148 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
149 |
# VG |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
150 |
lvm = None |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
151 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
152 |
# name |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
153 |
name = None |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
154 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
155 |
def __init__ (self, lvm, name) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
156 |
self.lvm = lvm |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
157 |
self.name = name |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
158 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
159 |
@property |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
160 |
def lvm_path (self) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
161 |
return self.lvm.lv_name(self.name) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
162 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
163 |
@property |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
164 |
def dev_path (self) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
165 |
return self.lvm.lv_path(self.name) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
166 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
167 |
def verify_exists (self) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
168 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
169 |
Verify that the LV exists. |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
170 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
171 |
Raises an LVMError otherwise. |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
172 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
173 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
174 |
# lvdisplay |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
175 |
try : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
176 |
self.lvm.command('lvs', self.lvm_path) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
177 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
178 |
except InvokeError : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
179 |
raise LVMError("Unable to lvdisplay LV: {path}".format(path=self.lvm_path)) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
180 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
181 |
# dev |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
182 |
if not self.test_dev() : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
183 |
raise LVMError("LV dev does not exist: {path}".format(path=self.dev_path)) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
184 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
185 |
def verify_missing (self) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
186 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
187 |
Verify that the LV does NOT exist. |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
188 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
189 |
Raises an LVMError otherwise. |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
190 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
191 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
192 |
if self.test_dev() : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
193 |
raise Exception("LV already exists: {path}".format(path=self.dev_path)) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
194 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
195 |
def test_dev (self) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
196 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
197 |
Tests for existance of device file, returning True/False. |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
198 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
199 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
200 |
return os.path.exists(self.dev_path) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
201 |
|
10 | 202 |
def __str__ (self) : |
203 |
return self.lvm_path |
|
204 |
||
5
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
205 |
def __repr__ (self) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
206 |
return "LVMVolume(lvm={lvm}, name={name})".format( |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
207 |
lvm = repr(self.lvm), |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
208 |
name = repr(self.name), |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
209 |
) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
210 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
211 |
class LVMSnapshot (LVMVolume) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
212 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
213 |
LVM snapshot |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
214 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
215 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
216 |
# base lv |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
217 |
base = None |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
218 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
219 |
@classmethod |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
220 |
def create (cls, lvm, base, tag, size=LVM_SNAPSHOT_SIZE) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
221 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
222 |
Create a new LVM snapshot of the given LV. |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
223 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
224 |
Returns a (snapshot_name, dev_path) tuple. |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
225 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
226 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
227 |
# snapshot name |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
228 |
name = '{name}-{tag}'.format(name=base.name, tag=tag) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
229 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
230 |
# snapshot instance |
42
43e27a3e9efe
pvlbackup-rsync-wrapper: add --snapshot-size / --snapshot-wait opts
Tero Marttila <terom@paivola.fi>
parents:
29
diff
changeset
|
231 |
snapshot = cls(lvm, base, name, size=size) |
5
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
232 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
233 |
## verify |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
234 |
# base should exist |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
235 |
base.verify_exists() |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
236 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
237 |
# snapshot should not |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
238 |
snapshot.verify_missing() |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
239 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
240 |
## create |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
241 |
snapshot.open() |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
242 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
243 |
# verify |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
244 |
if not snapshot.test_dev() : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
245 |
raise LVMError("Failed to find new snapshot LV device: {path}".format(path=snapshot.dev_path)) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
246 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
247 |
# yay |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
248 |
return snapshot |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
249 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
250 |
def __init__ (self, lvm, base, name, size=LVM_SNAPSHOT_SIZE) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
251 |
LVMVolume.__init__(self, lvm, name) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
252 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
253 |
self.base = base |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
254 |
self.size = size |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
255 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
256 |
def open (self) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
257 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
258 |
Create snapshot volume. |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
259 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
260 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
261 |
# create |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
262 |
self.lvm.command('lvcreate', self.base.lvm_path, snapshot=True, name=self.name, size=self.size) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
263 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
264 |
def close (self) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
265 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
266 |
Remove snapshot volume. |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
267 |
""" |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
268 |
|
61
4fdf70cbc9b0
pvl.backup.lvm: snapshot: retry removal if fails with exit == 5 ("Can't remove open logical volume ...")
Tero Marttila <terom@paivola.fi>
parents:
42
diff
changeset
|
269 |
# don't typo me! |
5
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
270 |
self.lvm.command('lvremove', '-f', self.lvm_path) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
271 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
272 |
def __repr__ (self) : |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
273 |
return "LVMSnapshot(lvm={lvm}, base={base}, name={name})".format( |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
274 |
lvm = str(self.lvm), |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
275 |
base = str(self.base), |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
276 |
name = repr(self.name), |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
277 |
) |
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
278 |
|
23371d26fdd0
split up into pvl.backup package
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
279 |