]>
Commit | Line | Data |
---|---|---|
1adf2230 | 1 | import argparse |
f91f0fd5 | 2 | from collections import namedtuple |
f6b5b4d7 | 3 | import json |
f91f0fd5 | 4 | import logging |
1adf2230 AA |
5 | from textwrap import dedent |
6 | from ceph_volume import terminal, decorators | |
f91f0fd5 TL |
7 | from ceph_volume.util import disk, prompt_bool, arg_validators, templates |
8 | from ceph_volume.util import prepare | |
9 | from . import common | |
10 | from .create import Create | |
11 | from .prepare import Prepare | |
1adf2230 | 12 | |
91327a77 AA |
13 | mlogger = terminal.MultiLogger(__name__) |
14 | logger = logging.getLogger(__name__) | |
15 | ||
1adf2230 AA |
16 | |
17 | device_list_template = """ | |
18 | * {path: <25} {size: <10} {state}""" | |
19 | ||
20 | ||
21 | def device_formatter(devices): | |
22 | lines = [] | |
23 | for path, details in devices: | |
24 | lines.append(device_list_template.format( | |
25 | path=path, size=details['human_readable_size'], | |
26 | state='solid' if details['rotational'] == '0' else 'rotational') | |
27 | ) | |
28 | ||
29 | return ''.join(lines) | |
30 | ||
31 | ||
f91f0fd5 TL |
32 | def ensure_disjoint_device_lists(data, db=[], wal=[], journal=[]): |
33 | # check that all device lists are disjoint with each other | |
34 | if not all([set(data).isdisjoint(set(db)), | |
35 | set(data).isdisjoint(set(wal)), | |
36 | set(data).isdisjoint(set(journal)), | |
37 | set(db).isdisjoint(set(wal))]): | |
38 | raise Exception('Device lists are not disjoint') | |
39 | ||
40 | ||
41 | def separate_devices_from_lvs(devices): | |
42 | phys = [] | |
43 | lvm = [] | |
44 | for d in devices: | |
45 | phys.append(d) if d.is_device else lvm.append(d) | |
46 | return phys, lvm | |
47 | ||
48 | ||
49 | def get_physical_osds(devices, args): | |
50 | ''' | |
51 | Goes through passed physical devices and assigns OSDs | |
52 | ''' | |
53 | data_slots = args.osds_per_device | |
54 | if args.data_slots: | |
55 | data_slots = max(args.data_slots, args.osds_per_device) | |
56 | rel_data_size = 1.0 / data_slots | |
57 | mlogger.debug('relative data size: {}'.format(rel_data_size)) | |
58 | ret = [] | |
59 | for dev in devices: | |
60 | if dev.available_lvm: | |
61 | dev_size = dev.vg_size[0] | |
62 | abs_size = disk.Size(b=int(dev_size * rel_data_size)) | |
63 | free_size = dev.vg_free[0] | |
64 | for _ in range(args.osds_per_device): | |
65 | if abs_size > free_size: | |
66 | break | |
67 | free_size -= abs_size.b | |
68 | osd_id = None | |
69 | if args.osd_ids: | |
70 | osd_id = args.osd_ids.pop() | |
71 | ret.append(Batch.OSD(dev.path, | |
72 | rel_data_size, | |
73 | abs_size, | |
74 | args.osds_per_device, | |
75 | osd_id, | |
76 | 'dmcrypt' if args.dmcrypt else None)) | |
77 | return ret | |
78 | ||
79 | ||
80 | def get_lvm_osds(lvs, args): | |
81 | ''' | |
82 | Goes through passed LVs and assigns planned osds | |
83 | ''' | |
84 | ret = [] | |
85 | for lv in lvs: | |
86 | if lv.used_by_ceph: | |
87 | continue | |
88 | osd_id = None | |
89 | if args.osd_ids: | |
90 | osd_id = args.osd_ids.pop() | |
91 | osd = Batch.OSD("{}/{}".format(lv.vg_name, lv.lv_name), | |
92 | 100.0, | |
93 | disk.Size(b=int(lv.lvs[0].lv_size)), | |
94 | 1, | |
95 | osd_id, | |
96 | 'dmcrypt' if args.dmcrypt else None) | |
97 | ret.append(osd) | |
98 | return ret | |
99 | ||
100 | ||
101 | def get_physical_fast_allocs(devices, type_, fast_slots_per_device, new_osds, args): | |
102 | requested_slots = getattr(args, '{}_slots'.format(type_)) | |
103 | if not requested_slots or requested_slots < fast_slots_per_device: | |
104 | if requested_slots: | |
105 | mlogger.info('{}_slots argument is to small, ignoring'.format(type_)) | |
106 | requested_slots = fast_slots_per_device | |
107 | ||
108 | requested_size = getattr(args, '{}_size'.format(type_), 0) | |
109 | if requested_size == 0: | |
110 | # no size argument was specified, check ceph.conf | |
111 | get_size_fct = getattr(prepare, 'get_{}_size'.format(type_)) | |
112 | requested_size = get_size_fct(lv_format=False) | |
113 | ||
114 | ret = [] | |
115 | for dev in devices: | |
116 | if not dev.available_lvm: | |
117 | continue | |
118 | # any LV present is considered a taken slot | |
119 | occupied_slots = len(dev.lvs) | |
120 | # this only looks at the first vg on device, unsure if there is a better | |
121 | # way | |
122 | dev_size = dev.vg_size[0] | |
123 | abs_size = disk.Size(b=int(dev_size / requested_slots)) | |
124 | free_size = dev.vg_free[0] | |
125 | relative_size = int(abs_size) / dev_size | |
126 | if requested_size: | |
127 | if requested_size <= abs_size: | |
128 | abs_size = requested_size | |
1911f103 | 129 | else: |
f91f0fd5 TL |
130 | mlogger.error( |
131 | '{} was requested for {}, but only {} can be fulfilled'.format( | |
132 | requested_size, | |
133 | '{}_size'.format(type_), | |
134 | abs_size, | |
135 | )) | |
136 | exit(1) | |
137 | while abs_size <= free_size and len(ret) < new_osds and occupied_slots < fast_slots_per_device: | |
138 | free_size -= abs_size.b | |
139 | occupied_slots += 1 | |
140 | ret.append((dev.path, relative_size, abs_size, requested_slots)) | |
141 | return ret | |
142 | ||
143 | ||
144 | def get_lvm_fast_allocs(lvs): | |
145 | return [("{}/{}".format(d.vg_name, d.lv_name), 100.0, | |
146 | disk.Size(b=int(d.lvs[0].lv_size)), 1) for d in lvs if not | |
147 | d.used_by_ceph] | |
1adf2230 AA |
148 | |
149 | ||
150 | class Batch(object): | |
151 | ||
152 | help = 'Automatically size devices for multi-OSD provisioning with minimal interaction' | |
153 | ||
154 | _help = dedent(""" | |
155 | Automatically size devices ready for OSD provisioning based on default strategies. | |
156 | ||
1adf2230 AA |
157 | Usage: |
158 | ||
159 | ceph-volume lvm batch [DEVICE...] | |
160 | ||
f91f0fd5 | 161 | Devices can be physical block devices or LVs. |
1adf2230 AA |
162 | Optional reporting on possible outcomes is enabled with --report |
163 | ||
164 | ceph-volume lvm batch --report [DEVICE...] | |
165 | """) | |
166 | ||
167 | def __init__(self, argv): | |
1adf2230 AA |
168 | parser = argparse.ArgumentParser( |
169 | prog='ceph-volume lvm batch', | |
170 | formatter_class=argparse.RawDescriptionHelpFormatter, | |
f91f0fd5 | 171 | description=self._help, |
1adf2230 AA |
172 | ) |
173 | ||
174 | parser.add_argument( | |
175 | 'devices', | |
176 | metavar='DEVICES', | |
177 | nargs='*', | |
f91f0fd5 | 178 | type=arg_validators.ValidBatchDevice(), |
1adf2230 AA |
179 | default=[], |
180 | help='Devices to provision OSDs', | |
181 | ) | |
11fdf7f2 TL |
182 | parser.add_argument( |
183 | '--db-devices', | |
184 | nargs='*', | |
f91f0fd5 | 185 | type=arg_validators.ValidBatchDevice(), |
11fdf7f2 TL |
186 | default=[], |
187 | help='Devices to provision OSDs db volumes', | |
188 | ) | |
189 | parser.add_argument( | |
190 | '--wal-devices', | |
191 | nargs='*', | |
f91f0fd5 | 192 | type=arg_validators.ValidBatchDevice(), |
11fdf7f2 TL |
193 | default=[], |
194 | help='Devices to provision OSDs wal volumes', | |
195 | ) | |
196 | parser.add_argument( | |
197 | '--journal-devices', | |
198 | nargs='*', | |
f91f0fd5 | 199 | type=arg_validators.ValidBatchDevice(), |
11fdf7f2 TL |
200 | default=[], |
201 | help='Devices to provision OSDs journal volumes', | |
202 | ) | |
203 | parser.add_argument( | |
f91f0fd5 | 204 | '--auto', |
11fdf7f2 | 205 | action='store_true', |
f91f0fd5 TL |
206 | help=('deploy multi-device OSDs if rotational and non-rotational drives ' |
207 | 'are passed in DEVICES'), | |
208 | default=True | |
209 | ) | |
210 | parser.add_argument( | |
211 | '--no-auto', | |
212 | action='store_false', | |
213 | dest='auto', | |
11fdf7f2 TL |
214 | help=('deploy standalone OSDs if rotational and non-rotational drives ' |
215 | 'are passed in DEVICES'), | |
216 | ) | |
1adf2230 AA |
217 | parser.add_argument( |
218 | '--bluestore', | |
219 | action='store_true', | |
220 | help='bluestore objectstore (default)', | |
221 | ) | |
222 | parser.add_argument( | |
223 | '--filestore', | |
224 | action='store_true', | |
225 | help='filestore objectstore', | |
226 | ) | |
227 | parser.add_argument( | |
228 | '--report', | |
229 | action='store_true', | |
f91f0fd5 | 230 | help='Only report on OSD that would be created and exit', |
1adf2230 AA |
231 | ) |
232 | parser.add_argument( | |
233 | '--yes', | |
234 | action='store_true', | |
235 | help='Avoid prompting for confirmation when provisioning', | |
236 | ) | |
237 | parser.add_argument( | |
238 | '--format', | |
239 | help='output format, defaults to "pretty"', | |
240 | default='pretty', | |
f91f0fd5 | 241 | choices=['json', 'json-pretty', 'pretty'], |
1adf2230 AA |
242 | ) |
243 | parser.add_argument( | |
244 | '--dmcrypt', | |
245 | action='store_true', | |
246 | help='Enable device encryption via dm-crypt', | |
247 | ) | |
248 | parser.add_argument( | |
249 | '--crush-device-class', | |
250 | dest='crush_device_class', | |
251 | help='Crush device class to assign this OSD to', | |
252 | ) | |
253 | parser.add_argument( | |
254 | '--no-systemd', | |
255 | dest='no_systemd', | |
256 | action='store_true', | |
257 | help='Skip creating and enabling systemd units and starting OSD services', | |
258 | ) | |
91327a77 AA |
259 | parser.add_argument( |
260 | '--osds-per-device', | |
261 | type=int, | |
262 | default=1, | |
263 | help='Provision more than 1 (the default) OSD per device', | |
264 | ) | |
265 | parser.add_argument( | |
f91f0fd5 | 266 | '--data-slots', |
91327a77 | 267 | type=int, |
f91f0fd5 TL |
268 | help=('Provision more than 1 (the default) OSD slot per device' |
269 | ' if more slots then osds-per-device are specified, slots' | |
270 | 'will stay unoccupied'), | |
271 | ) | |
272 | parser.add_argument( | |
273 | '--block-db-size', | |
274 | type=disk.Size.parse, | |
91327a77 AA |
275 | help='Set (or override) the "bluestore_block_db_size" value, in bytes' |
276 | ) | |
11fdf7f2 | 277 | parser.add_argument( |
f91f0fd5 | 278 | '--block-db-slots', |
11fdf7f2 | 279 | type=int, |
f91f0fd5 TL |
280 | help='Provision slots on DB device, can remain unoccupied' |
281 | ) | |
282 | parser.add_argument( | |
283 | '--block-wal-size', | |
284 | type=disk.Size.parse, | |
11fdf7f2 TL |
285 | help='Set (or override) the "bluestore_block_wal_size" value, in bytes' |
286 | ) | |
91327a77 | 287 | parser.add_argument( |
f91f0fd5 | 288 | '--block-wal-slots', |
91327a77 | 289 | type=int, |
f91f0fd5 TL |
290 | help='Provision slots on WAL device, can remain unoccupied' |
291 | ) | |
292 | def journal_size_in_mb_hack(size): | |
293 | # TODO give user time to adjust, then remove this | |
294 | if size and size[-1].isdigit(): | |
295 | mlogger.warning('DEPRECATION NOTICE') | |
296 | mlogger.warning('--journal-size as integer is parsed as megabytes') | |
297 | mlogger.warning('A future release will parse integers as bytes') | |
298 | mlogger.warning('Add a "M" to explicitly pass a megabyte size') | |
299 | size += 'M' | |
300 | return disk.Size.parse(size) | |
301 | parser.add_argument( | |
302 | '--journal-size', | |
303 | type=journal_size_in_mb_hack, | |
91327a77 AA |
304 | help='Override the "osd_journal_size" value, in megabytes' |
305 | ) | |
f91f0fd5 TL |
306 | parser.add_argument( |
307 | '--journal-slots', | |
308 | type=int, | |
309 | help='Provision slots on journal device, can remain unoccupied' | |
310 | ) | |
91327a77 AA |
311 | parser.add_argument( |
312 | '--prepare', | |
313 | action='store_true', | |
314 | help='Only prepare all OSDs, do not activate', | |
315 | ) | |
11fdf7f2 TL |
316 | parser.add_argument( |
317 | '--osd-ids', | |
318 | nargs='*', | |
319 | default=[], | |
320 | help='Reuse existing OSD ids', | |
321 | ) | |
322 | self.args = parser.parse_args(argv) | |
323 | self.parser = parser | |
324 | for dev_list in ['', 'db_', 'wal_', 'journal_']: | |
325 | setattr(self, '{}usable'.format(dev_list), []) | |
326 | ||
f91f0fd5 TL |
327 | def report(self, plan): |
328 | report = self._create_report(plan) | |
329 | print(report) | |
11fdf7f2 | 330 | |
f91f0fd5 | 331 | def _create_report(self, plan): |
11fdf7f2 | 332 | if self.args.format == 'pretty': |
f91f0fd5 TL |
333 | report = '' |
334 | report += templates.total_osds.format(total_osds=len(plan)) | |
335 | ||
336 | report += templates.osd_component_titles | |
337 | for osd in plan: | |
338 | report += templates.osd_header | |
339 | report += osd.report() | |
340 | return report | |
11fdf7f2 | 341 | else: |
f91f0fd5 TL |
342 | json_report = [] |
343 | for osd in plan: | |
344 | json_report.append(osd.report_json()) | |
345 | if self.args.format == 'json': | |
346 | return json.dumps(json_report) | |
347 | elif self.args.format == 'json-pretty': | |
348 | return json.dumps(json_report, indent=4, | |
349 | sort_keys=True) | |
350 | ||
351 | def _check_slot_args(self): | |
352 | ''' | |
353 | checking if -slots args are consistent with other arguments | |
354 | ''' | |
355 | if self.args.data_slots and self.args.osds_per_device: | |
356 | if self.args.data_slots < self.args.osds_per_device: | |
357 | raise ValueError('data_slots is smaller then osds_per_device') | |
358 | ||
359 | def _sort_rotational_disks(self): | |
360 | ''' | |
361 | Helper for legacy auto behaviour. | |
362 | Sorts drives into rotating and non-rotating, the latter being used for | |
363 | db or journal. | |
364 | ''' | |
365 | mlogger.warning('DEPRECATION NOTICE') | |
366 | mlogger.warning('You are using the legacy automatic disk sorting behavior') | |
367 | mlogger.warning('The Pacific release will change the default to --no-auto') | |
368 | rotating = [] | |
369 | ssd = [] | |
370 | for d in self.args.devices: | |
371 | rotating.append(d) if d.rotational else ssd.append(d) | |
372 | if ssd and not rotating: | |
373 | # no need for additional sorting, we'll only deploy standalone on ssds | |
374 | return | |
375 | self.args.devices = rotating | |
376 | if self.args.filestore: | |
377 | self.args.journal_devices = ssd | |
11fdf7f2 | 378 | else: |
f91f0fd5 | 379 | self.args.db_devices = ssd |
11fdf7f2 TL |
380 | |
381 | @decorators.needs_root | |
382 | def main(self): | |
383 | if not self.args.devices: | |
384 | return self.parser.print_help() | |
1adf2230 AA |
385 | |
386 | # Default to bluestore here since defaulting it in add_argument may | |
387 | # cause both to be True | |
11fdf7f2 TL |
388 | if not self.args.bluestore and not self.args.filestore: |
389 | self.args.bluestore = True | |
1adf2230 | 390 | |
f91f0fd5 TL |
391 | if (self.args.auto and not self.args.db_devices and not |
392 | self.args.wal_devices and not self.args.journal_devices): | |
393 | self._sort_rotational_disks() | |
394 | ||
395 | self._check_slot_args() | |
396 | ||
397 | ensure_disjoint_device_lists(self.args.devices, | |
398 | self.args.db_devices, | |
399 | self.args.wal_devices, | |
400 | self.args.journal_devices) | |
401 | ||
402 | plan = self.get_plan(self.args) | |
11fdf7f2 TL |
403 | |
404 | if self.args.report: | |
f91f0fd5 TL |
405 | self.report(plan) |
406 | return 0 | |
11fdf7f2 | 407 | |
f91f0fd5 TL |
408 | if not self.args.yes: |
409 | self.report(plan) | |
410 | terminal.info('The above OSDs would be created if the operation continues') | |
411 | if not prompt_bool('do you want to proceed? (yes/no)'): | |
412 | terminal.error('aborting OSD provisioning') | |
413 | raise SystemExit(0) | |
11fdf7f2 | 414 | |
f91f0fd5 TL |
415 | self._execute(plan) |
416 | ||
417 | def _execute(self, plan): | |
418 | defaults = common.get_default_args() | |
419 | global_args = [ | |
420 | 'bluestore', | |
421 | 'filestore', | |
422 | 'dmcrypt', | |
423 | 'crush_device_class', | |
424 | 'no_systemd', | |
425 | ] | |
426 | defaults.update({arg: getattr(self.args, arg) for arg in global_args}) | |
427 | for osd in plan: | |
428 | args = osd.get_args(defaults) | |
429 | if self.args.prepare: | |
430 | p = Prepare([]) | |
431 | p.safe_prepare(argparse.Namespace(**args)) | |
432 | else: | |
433 | c = Create([]) | |
434 | c.create(argparse.Namespace(**args)) | |
435 | ||
436 | ||
437 | def get_plan(self, args): | |
438 | if args.bluestore: | |
439 | plan = self.get_deployment_layout(args, args.devices, args.db_devices, | |
440 | args.wal_devices) | |
441 | elif args.filestore: | |
442 | plan = self.get_deployment_layout(args, args.devices, args.journal_devices) | |
443 | return plan | |
444 | ||
445 | def get_deployment_layout(self, args, devices, fast_devices=[], | |
446 | very_fast_devices=[]): | |
447 | ''' | |
448 | The methods here are mostly just organization, error reporting and | |
449 | setting up of (default) args. The heavy lifting code for the deployment | |
450 | layout can be found in the static get_*_osds and get_*_fast_allocs | |
451 | functions. | |
452 | ''' | |
453 | plan = [] | |
454 | phys_devs, lvm_devs = separate_devices_from_lvs(devices) | |
455 | mlogger.debug(('passed data devices: {} physical,' | |
456 | ' {} LVM').format(len(phys_devs), len(lvm_devs))) | |
457 | ||
458 | plan.extend(get_physical_osds(phys_devs, args)) | |
459 | ||
460 | plan.extend(get_lvm_osds(lvm_devs, args)) | |
461 | ||
462 | num_osds = len(plan) | |
463 | if num_osds == 0: | |
464 | mlogger.info('All data devices are unavailable') | |
465 | return plan | |
466 | requested_osds = args.osds_per_device * len(phys_devs) + len(lvm_devs) | |
467 | ||
468 | fast_type = 'block_db' if args.bluestore else 'journal' | |
469 | fast_allocations = self.fast_allocations(fast_devices, | |
470 | requested_osds, | |
471 | num_osds, | |
472 | fast_type) | |
473 | if fast_devices and not fast_allocations: | |
474 | mlogger.info('{} fast devices were passed, but none are available'.format(len(fast_devices))) | |
475 | return [] | |
476 | if fast_devices and not len(fast_allocations) == num_osds: | |
477 | mlogger.error('{} fast allocations != {} num_osds'.format( | |
478 | len(fast_allocations), num_osds)) | |
479 | exit(1) | |
480 | ||
481 | very_fast_allocations = self.fast_allocations(very_fast_devices, | |
482 | requested_osds, | |
483 | num_osds, | |
484 | 'block_wal') | |
485 | if very_fast_devices and not very_fast_allocations: | |
486 | mlogger.info('{} very fast devices were passed, but none are available'.format(len(very_fast_devices))) | |
487 | return [] | |
488 | if very_fast_devices and not len(very_fast_allocations) == num_osds: | |
489 | mlogger.error('{} very fast allocations != {} num_osds'.format( | |
490 | len(very_fast_allocations), num_osds)) | |
491 | exit(1) | |
492 | ||
493 | for osd in plan: | |
494 | if fast_devices: | |
495 | osd.add_fast_device(*fast_allocations.pop(), | |
496 | type_=fast_type) | |
497 | if very_fast_devices and args.bluestore: | |
498 | osd.add_very_fast_device(*very_fast_allocations.pop()) | |
499 | return plan | |
500 | ||
501 | def fast_allocations(self, devices, requested_osds, new_osds, type_): | |
502 | ret = [] | |
503 | if not devices: | |
504 | return ret | |
505 | phys_devs, lvm_devs = separate_devices_from_lvs(devices) | |
506 | mlogger.debug(('passed {} devices: {} physical,' | |
507 | ' {} LVM').format(type_, len(phys_devs), len(lvm_devs))) | |
508 | ||
509 | ret.extend(get_lvm_fast_allocs(lvm_devs)) | |
510 | ||
511 | # fill up uneven distributions across fast devices: 5 osds and 2 fast | |
512 | # devices? create 3 slots on each device rather then deploying | |
513 | # heterogeneous osds | |
514 | if (requested_osds - len(lvm_devs)) % len(phys_devs): | |
515 | fast_slots_per_device = int((requested_osds - len(lvm_devs)) / len(phys_devs)) + 1 | |
516 | else: | |
517 | fast_slots_per_device = int((requested_osds - len(lvm_devs)) / len(phys_devs)) | |
518 | ||
519 | ||
520 | ret.extend(get_physical_fast_allocs(phys_devs, | |
521 | type_, | |
522 | fast_slots_per_device, | |
523 | new_osds, | |
524 | self.args)) | |
525 | return ret | |
526 | ||
527 | class OSD(object): | |
528 | ''' | |
529 | This class simply stores info about to-be-deployed OSDs and provides an | |
530 | easy way to retrieve the necessary create arguments. | |
531 | ''' | |
532 | VolSpec = namedtuple('VolSpec', | |
533 | ['path', | |
534 | 'rel_size', | |
535 | 'abs_size', | |
536 | 'slots', | |
537 | 'type_']) | |
538 | ||
539 | def __init__(self, | |
540 | data_path, | |
541 | rel_size, | |
542 | abs_size, | |
543 | slots, | |
544 | id_, | |
545 | encryption): | |
546 | self.id_ = id_ | |
547 | self.data = self.VolSpec(path=data_path, | |
548 | rel_size=rel_size, | |
549 | abs_size=abs_size, | |
550 | slots=slots, | |
551 | type_='data') | |
552 | self.fast = None | |
553 | self.very_fast = None | |
554 | self.encryption = encryption | |
555 | ||
556 | def add_fast_device(self, path, rel_size, abs_size, slots, type_): | |
557 | self.fast = self.VolSpec(path=path, | |
558 | rel_size=rel_size, | |
559 | abs_size=abs_size, | |
560 | slots=slots, | |
561 | type_=type_) | |
562 | ||
563 | def add_very_fast_device(self, path, rel_size, abs_size, slots): | |
564 | self.very_fast = self.VolSpec(path=path, | |
565 | rel_size=rel_size, | |
566 | abs_size=abs_size, | |
567 | slots=slots, | |
568 | type_='block_wal') | |
569 | ||
570 | def _get_osd_plan(self): | |
571 | plan = { | |
572 | 'data': self.data.path, | |
573 | 'data_size': self.data.abs_size, | |
574 | 'encryption': self.encryption, | |
575 | } | |
576 | if self.fast: | |
577 | type_ = self.fast.type_.replace('.', '_') | |
578 | plan.update( | |
579 | { | |
580 | type_: self.fast.path, | |
581 | '{}_size'.format(type_): self.fast.abs_size, | |
582 | }) | |
583 | if self.very_fast: | |
584 | plan.update( | |
585 | { | |
586 | 'block_wal': self.very_fast.path, | |
587 | 'block_wal_size': self.very_fast.abs_size, | |
588 | }) | |
589 | if self.id_: | |
590 | plan.update({'osd_id': self.id_}) | |
591 | return plan | |
592 | ||
593 | def get_args(self, defaults): | |
594 | my_defaults = defaults.copy() | |
595 | my_defaults.update(self._get_osd_plan()) | |
596 | return my_defaults | |
597 | ||
598 | def report(self): | |
599 | report = '' | |
600 | if self.id_: | |
601 | report += templates.osd_reused_id.format( | |
602 | id_=self.id_) | |
603 | if self.encryption: | |
604 | report += templates.osd_encryption.format( | |
605 | enc=self.encryption) | |
606 | report += templates.osd_component.format( | |
607 | _type=self.data.type_, | |
608 | path=self.data.path, | |
609 | size=self.data.abs_size, | |
610 | percent=self.data.rel_size) | |
611 | if self.fast: | |
612 | report += templates.osd_component.format( | |
613 | _type=self.fast.type_, | |
614 | path=self.fast.path, | |
615 | size=self.fast.abs_size, | |
616 | percent=self.fast.rel_size) | |
617 | if self.very_fast: | |
618 | report += templates.osd_component.format( | |
619 | _type=self.very_fast.type_, | |
620 | path=self.very_fast.path, | |
621 | size=self.very_fast.abs_size, | |
622 | percent=self.very_fast.rel_size) | |
623 | return report | |
624 | ||
625 | def report_json(self): | |
626 | # cast all values to string so that the report can be dumped in to | |
627 | # json.dumps | |
628 | return {k: str(v) for k, v in self._get_osd_plan().items()} |