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
9 device_list_template
= """
10 * {path: <25} {size: <10} {state}"""
13 def device_formatter(devices
):
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')
24 # Scenario filtering/detection
25 def bluestore_single_type(device_facts
):
27 Detect devices that are just HDDs or solid state so that a 1:1
28 device-to-osd provisioning can be done
30 types
= [device
.sys_api
['rotational'] for device
in device_facts
]
31 if len(set(types
)) == 1:
32 return strategies
.bluestore
.SingleType
35 def bluestore_mixed_type(device_facts
):
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.
40 types
= [device
.sys_api
['rotational'] for device
in device_facts
]
41 if len(set(types
)) > 1:
42 return strategies
.bluestore
.MixedType
45 def filestore_single_type(device_facts
):
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
50 types
= [device
.sys_api
['rotational'] for device
in device_facts
]
51 if len(set(types
)) == 1:
52 return strategies
.filestore
.SingleType
55 def filestore_mixed_type(device_facts
):
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.
60 types
= [device
.sys_api
['rotational'] for device
in device_facts
]
61 if len(set(types
)) > 1:
62 return strategies
.filestore
.MixedType
65 def get_strategy(args
):
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
71 * Single device type on Bluestore
72 * Mixed device types on Bluestore
73 * Single device type on Filestore
74 * Mixed device types on Filestore
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
80 bluestore_strategies
= [bluestore_mixed_type
, bluestore_single_type
]
81 filestore_strategies
= [filestore_mixed_type
, filestore_single_type
]
83 strategies
= bluestore_strategies
85 strategies
= filestore_strategies
87 for strategy
in strategies
:
88 backend
= strategy(args
.devices
)
90 return backend(args
.devices
, args
)
95 help = 'Automatically size devices for multi-OSD provisioning with minimal interaction'
98 Automatically size devices ready for OSD provisioning based on default strategies.
105 ceph-volume lvm batch [DEVICE...]
107 Optional reporting on possible outcomes is enabled with --report
109 ceph-volume lvm batch --report [DEVICE...]
112 def __init__(self
, argv
):
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
)
125 def print_help(self
):
126 return self
._help
.format(
127 detected_devices
=self
.get_devices(),
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()
137 raise RuntimeError('report format must be "pretty" or "json"')
139 def execute(self
, args
):
140 strategy
= get_strategy(args
)
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
))
150 @decorators.needs_root
152 parser
= argparse
.ArgumentParser(
153 prog
='ceph-volume lvm batch',
154 formatter_class
=argparse
.RawDescriptionHelpFormatter
,
155 description
=self
.print_help(),
162 type=arg_validators
.ValidDevice(),
164 help='Devices to provision OSDs',
169 help='bluestore objectstore (default)',
174 help='filestore objectstore',
179 help='Autodetect the objectstore by inspecting the OSD',
184 help='Avoid prompting for confirmation when provisioning',
188 help='output format, defaults to "pretty"',
190 choices
=['json', 'pretty'],
195 help='Enable device encryption via dm-crypt',
198 '--crush-device-class',
199 dest
='crush_device_class',
200 help='Crush device class to assign this OSD to',
206 help='Skip creating and enabling systemd units and starting OSD services',
208 args
= parser
.parse_args(self
.argv
)
211 return parser
.print_help()
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