]>
Commit | Line | Data |
---|---|---|
3efd9988 FG |
1 | import argparse |
2 | import logging | |
3 | ||
4 | from textwrap import dedent | |
5 | ||
6 | from ceph_volume import decorators, terminal, process | |
7 | from ceph_volume.api import lvm as api | |
3a9019d9 | 8 | from ceph_volume.util import system, encryption, disk |
3efd9988 FG |
9 | |
10 | logger = logging.getLogger(__name__) | |
b32b8144 | 11 | mlogger = terminal.MultiLogger(__name__) |
3efd9988 FG |
12 | |
13 | ||
14 | def wipefs(path): | |
15 | """ | |
16 | Removes the filesystem from an lv or partition. | |
17 | """ | |
18 | process.run([ | |
3efd9988 FG |
19 | 'wipefs', |
20 | '--all', | |
21 | path | |
22 | ]) | |
23 | ||
24 | ||
25 | def zap_data(path): | |
26 | """ | |
27 | Clears all data from the given path. Path should be | |
28 | an absolute path to an lv or partition. | |
29 | ||
30 | 10M of data is written to the path to make sure that | |
31 | there is no trace left of any previous Filesystem. | |
32 | """ | |
33 | process.run([ | |
34 | 'dd', | |
35 | 'if=/dev/zero', | |
36 | 'of={path}'.format(path=path), | |
37 | 'bs=1M', | |
38 | 'count=10', | |
39 | ]) | |
40 | ||
41 | ||
42 | class Zap(object): | |
43 | ||
44 | help = 'Removes all data and filesystems from a logical volume or partition.' | |
45 | ||
46 | def __init__(self, argv): | |
47 | self.argv = argv | |
48 | ||
49 | @decorators.needs_root | |
50 | def zap(self, args): | |
51 | device = args.device | |
52 | lv = api.get_lv_from_argument(device) | |
53 | if lv: | |
54 | # we are zapping a logical volume | |
55 | path = lv.lv_path | |
56 | else: | |
57 | # we are zapping a partition | |
58 | #TODO: ensure device is a partition | |
59 | path = device | |
60 | ||
b32b8144 FG |
61 | mlogger.info("Zapping: %s", path) |
62 | ||
63 | # check if there was a pv created with the | |
64 | # name of device | |
65 | pv = api.get_pv(pv_name=device) | |
66 | if pv: | |
67 | vg_name = pv.vg_name | |
68 | lv = api.get_lv(vg_name=vg_name) | |
69 | ||
3a9019d9 FG |
70 | dmcrypt = False |
71 | dmcrypt_uuid = None | |
b32b8144 FG |
72 | if lv: |
73 | osd_path = "/var/lib/ceph/osd/{}-{}".format(lv.tags['ceph.cluster_name'], lv.tags['ceph.osd_id']) | |
3a9019d9 FG |
74 | dmcrypt_uuid = lv.lv_uuid |
75 | dmcrypt = lv.encrypted | |
b32b8144 FG |
76 | if system.path_is_mounted(osd_path): |
77 | mlogger.info("Unmounting %s", osd_path) | |
78 | system.unmount(osd_path) | |
3a9019d9 FG |
79 | else: |
80 | # we're most likely dealing with a partition here, check to | |
81 | # see if it was encrypted | |
82 | partuuid = disk.get_partuuid(device) | |
83 | if encryption.status("/dev/mapper/{}".format(partuuid)): | |
84 | dmcrypt_uuid = partuuid | |
85 | dmcrypt = True | |
86 | ||
87 | if dmcrypt and dmcrypt_uuid: | |
88 | dmcrypt_path = "/dev/mapper/{}".format(dmcrypt_uuid) | |
89 | mlogger.info("Closing encrypted path %s", dmcrypt_path) | |
90 | encryption.dmcrypt_close(dmcrypt_path) | |
b32b8144 FG |
91 | |
92 | if args.destroy and pv: | |
93 | logger.info("Found a physical volume created from %s, will destroy all it's vgs and lvs", device) | |
94 | vg_name = pv.vg_name | |
95 | mlogger.info("Destroying volume group %s because --destroy was given", vg_name) | |
96 | api.remove_vg(vg_name) | |
97 | mlogger.info("Destroying physical volume %s because --destroy was given", device) | |
98 | api.remove_pv(device) | |
99 | elif args.destroy and not pv: | |
100 | mlogger.info("Skipping --destroy because no associated physical volumes are found for %s", device) | |
3efd9988 FG |
101 | |
102 | wipefs(path) | |
103 | zap_data(path) | |
104 | ||
b32b8144 | 105 | if lv and not pv: |
3efd9988 FG |
106 | # remove all lvm metadata |
107 | lv.clear_tags() | |
108 | ||
109 | terminal.success("Zapping successful for: %s" % path) | |
110 | ||
111 | def main(self): | |
112 | sub_command_help = dedent(""" | |
b32b8144 FG |
113 | Zaps the given logical volume, raw device or partition for reuse by ceph-volume. |
114 | If given a path to a logical volume it must be in the format of vg/lv. Any | |
115 | filesystems present on the given device, vg/lv, or partition will be removed and | |
116 | all data will be purged. | |
117 | ||
118 | If the logical volume, raw device or partition is being used for any ceph related | |
119 | mount points they will be unmounted. | |
3efd9988 FG |
120 | |
121 | However, the lv or partition will be kept intact. | |
122 | ||
123 | Example calls for supported scenarios: | |
124 | ||
125 | Zapping a logical volume: | |
126 | ||
127 | ceph-volume lvm zap {vg name/lv name} | |
128 | ||
129 | Zapping a partition: | |
130 | ||
131 | ceph-volume lvm zap /dev/sdc1 | |
132 | ||
b32b8144 FG |
133 | If the --destroy flag is given and you are zapping a raw device or partition |
134 | then all vgs and lvs that exist on that raw device or partition will be destroyed. | |
135 | ||
136 | This is especially useful if a raw device or partition was used by ceph-volume lvm create | |
137 | or ceph-volume lvm prepare commands previously and now you want to reuse that device. | |
138 | ||
139 | For example: | |
140 | ||
141 | ceph-volume lvm zap /dev/sda --destroy | |
142 | ||
143 | If the --destroy flag is given and you are zapping an lv then the lv is still | |
144 | kept intact for reuse. | |
145 | ||
3efd9988 FG |
146 | """) |
147 | parser = argparse.ArgumentParser( | |
148 | prog='ceph-volume lvm zap', | |
149 | formatter_class=argparse.RawDescriptionHelpFormatter, | |
150 | description=sub_command_help, | |
151 | ) | |
152 | ||
153 | parser.add_argument( | |
154 | 'device', | |
155 | metavar='DEVICE', | |
156 | nargs='?', | |
b32b8144 FG |
157 | help='Path to an lv (as vg/lv), partition (as /dev/sda1) or device (as /dev/sda)' |
158 | ) | |
159 | parser.add_argument( | |
160 | '--destroy', | |
161 | action='store_true', | |
162 | default=False, | |
163 | help='Destroy all volume groups and logical volumes if you are zapping a raw device or partition', | |
3efd9988 FG |
164 | ) |
165 | if len(self.argv) == 0: | |
166 | print(sub_command_help) | |
167 | return | |
168 | args = parser.parse_args(self.argv) | |
169 | self.zap(args) |