]> git.proxmox.com Git - ceph.git/blob - ceph/src/ceph-volume/ceph_volume/devices/lvm/batch.py
update sources to 12.2.8
[ceph.git] / ceph / src / ceph-volume / ceph_volume / devices / lvm / batch.py
1 import argparse
2 from textwrap import dedent
3 from ceph_volume import terminal, decorators
4 from ceph_volume.util import disk, prompt_bool
5 from ceph_volume.util import arg_validators
6 from . import strategies
7
8
9 device_list_template = """
10 * {path: <25} {size: <10} {state}"""
11
12
13 def device_formatter(devices):
14 lines = []
15 for path, details in devices:
16 lines.append(device_list_template.format(
17 path=path, size=details['human_readable_size'],
18 state='solid' if details['rotational'] == '0' else 'rotational')
19 )
20
21 return ''.join(lines)
22
23
24 # Scenario filtering/detection
25 def bluestore_single_type(device_facts):
26 """
27 Detect devices that are just HDDs or solid state so that a 1:1
28 device-to-osd provisioning can be done
29 """
30 types = [device.sys_api['rotational'] for device in device_facts]
31 if len(set(types)) == 1:
32 return strategies.bluestore.SingleType
33
34
35 def bluestore_mixed_type(device_facts):
36 """
37 Detect if devices are HDDs as well as solid state so that block.db can be
38 placed in solid devices while data is kept in the spinning drives.
39 """
40 types = [device.sys_api['rotational'] for device in device_facts]
41 if len(set(types)) > 1:
42 return strategies.bluestore.MixedType
43
44
45 def filestore_single_type(device_facts):
46 """
47 Detect devices that are just HDDs or solid state so that a 1:1
48 device-to-osd provisioning can be done, keeping the journal on the OSD
49 """
50 types = [device.sys_api['rotational'] for device in device_facts]
51 if len(set(types)) == 1:
52 return strategies.filestore.SingleType
53
54
55 def filestore_mixed_type(device_facts):
56 """
57 Detect if devices are HDDs as well as solid state so that the journal can be
58 placed in solid devices while data is kept in the spinning drives.
59 """
60 types = [device.sys_api['rotational'] for device in device_facts]
61 if len(set(types)) > 1:
62 return strategies.filestore.MixedType
63
64
65 def get_strategy(args):
66 """
67 Given a set of devices as input, go through the different detection
68 mechanisms to narrow down on a strategy to use. The strategies are 4 in
69 total:
70
71 * Single device type on Bluestore
72 * Mixed device types on Bluestore
73 * Single device type on Filestore
74 * Mixed device types on Filestore
75
76 When the function matches to a scenario it returns the strategy class. This
77 allows for dynamic loading of the conditions needed for each scenario, with
78 normalized classes
79 """
80 bluestore_strategies = [bluestore_mixed_type, bluestore_single_type]
81 filestore_strategies = [filestore_mixed_type, filestore_single_type]
82 if args.bluestore:
83 strategies = bluestore_strategies
84 else:
85 strategies = filestore_strategies
86
87 for strategy in strategies:
88 backend = strategy(args.devices)
89 if backend:
90 return backend(args.devices, args)
91
92
93 class Batch(object):
94
95 help = 'Automatically size devices for multi-OSD provisioning with minimal interaction'
96
97 _help = dedent("""
98 Automatically size devices ready for OSD provisioning based on default strategies.
99
100 Detected devices:
101 {detected_devices}
102
103 Usage:
104
105 ceph-volume lvm batch [DEVICE...]
106
107 Optional reporting on possible outcomes is enabled with --report
108
109 ceph-volume lvm batch --report [DEVICE...]
110 """)
111
112 def __init__(self, argv):
113 self.argv = argv
114
115 def get_devices(self):
116 all_devices = disk.get_devices()
117 # remove devices with partitions
118 # XXX Should be optional when getting device info
119 for device, detail in all_devices.items():
120 if detail.get('partitions') != {}:
121 del all_devices[device]
122 devices = sorted(all_devices.items(), key=lambda x: (x[0], x[1]['size']))
123 return device_formatter(devices)
124
125 def print_help(self):
126 return self._help.format(
127 detected_devices=self.get_devices(),
128 )
129
130 def report(self, args):
131 strategy = get_strategy(args)
132 if args.format == 'pretty':
133 strategy.report_pretty()
134 elif args.format == 'json':
135 strategy.report_json()
136 else:
137 raise RuntimeError('report format must be "pretty" or "json"')
138
139 def execute(self, args):
140 strategy = get_strategy(args)
141 if not args.yes:
142 strategy.report_pretty()
143 terminal.info('The above OSDs would be created if the operation continues')
144 if not prompt_bool('do you want to proceed? (yes/no)'):
145 terminal.error('aborting OSD provisioning for %s' % ','.join(args.devices))
146 raise SystemExit(0)
147
148 strategy.execute()
149
150 @decorators.needs_root
151 def main(self):
152 parser = argparse.ArgumentParser(
153 prog='ceph-volume lvm batch',
154 formatter_class=argparse.RawDescriptionHelpFormatter,
155 description=self.print_help(),
156 )
157
158 parser.add_argument(
159 'devices',
160 metavar='DEVICES',
161 nargs='*',
162 type=arg_validators.ValidDevice(),
163 default=[],
164 help='Devices to provision OSDs',
165 )
166 parser.add_argument(
167 '--bluestore',
168 action='store_true',
169 help='bluestore objectstore (default)',
170 )
171 parser.add_argument(
172 '--filestore',
173 action='store_true',
174 help='filestore objectstore',
175 )
176 parser.add_argument(
177 '--report',
178 action='store_true',
179 help='Autodetect the objectstore by inspecting the OSD',
180 )
181 parser.add_argument(
182 '--yes',
183 action='store_true',
184 help='Avoid prompting for confirmation when provisioning',
185 )
186 parser.add_argument(
187 '--format',
188 help='output format, defaults to "pretty"',
189 default='pretty',
190 choices=['json', 'pretty'],
191 )
192 parser.add_argument(
193 '--dmcrypt',
194 action='store_true',
195 help='Enable device encryption via dm-crypt',
196 )
197 parser.add_argument(
198 '--crush-device-class',
199 dest='crush_device_class',
200 help='Crush device class to assign this OSD to',
201 )
202 parser.add_argument(
203 '--no-systemd',
204 dest='no_systemd',
205 action='store_true',
206 help='Skip creating and enabling systemd units and starting OSD services',
207 )
208 args = parser.parse_args(self.argv)
209
210 if not args.devices:
211 return parser.print_help()
212
213 # Default to bluestore here since defaulting it in add_argument may
214 # cause both to be True
215 if not args.bluestore and not args.filestore:
216 args.bluestore = True
217
218 if args.report:
219 self.report(args)
220 else:
221 self.execute(args)