Skip to content

Commit 080c083

Browse files
authored
Merge pull request ceph#58652 from adk3798/mgr-rgw-create-ec-data-pool
mgr/rgw: add ability for rgw realm bootstrap to create pools Reviewed-by: Kushal Deb <[email protected]>
2 parents 0c01a33 + d5fef51 commit 080c083

File tree

2 files changed

+109
-1
lines changed

2 files changed

+109
-1
lines changed

src/pybind/mgr/rgw/module.py

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@
66
import functools
77
import sys
88

9-
from mgr_module import MgrModule, CLICommand, HandleCommandResult, Option
9+
from mgr_module import (
10+
MgrModule,
11+
CLICommand,
12+
HandleCommandResult,
13+
Option,
14+
MonCommandFailed,
15+
)
1016
import orchestrator
1117

1218
from ceph.deployment.service_spec import RGWSpec, PlacementSpec, SpecValidationError
@@ -49,6 +55,10 @@ class RGWSpecParsingError(Exception):
4955
pass
5056

5157

58+
class PoolCreationError(Exception):
59+
pass
60+
61+
5262
class OrchestratorAPI(OrchestratorClientMixin):
5363
def __init__(self, mgr: MgrModule):
5464
super(OrchestratorAPI, self).__init__()
@@ -196,10 +206,14 @@ def _cmd_rgw_realm_bootstrap(self,
196206

197207
try:
198208
for spec in rgw_specs:
209+
self.create_pools(spec)
199210
RGWAM(self.env).realm_bootstrap(spec, start_radosgw)
200211
except RGWAMException as e:
201212
self.log.error('cmd run exception: (%d) %s' % (e.retcode, e.message))
202213
return HandleCommandResult(retval=e.retcode, stdout=e.stdout, stderr=e.stderr)
214+
except PoolCreationError as e:
215+
self.log.error(f'Pool creation failure: {str(e)}')
216+
return HandleCommandResult(retval=-errno.EINVAL, stderr=str(e))
203217

204218
return HandleCommandResult(retval=0, stdout="Realm(s) created correctly. Please, use 'ceph rgw realm tokens' to get the token.", stderr='')
205219

@@ -229,6 +243,85 @@ def _parse_rgw_specs(self, inbuf: str) -> List[RGWSpec]:
229243

230244
return rgw_specs
231245

246+
def create_pools(self, spec: RGWSpec) -> None:
247+
def _pool_create_command(
248+
pool_name: str,
249+
pool_type: str,
250+
pool_attrs: Optional[Dict[str, Union[str, List[str]]]] = None
251+
) -> None:
252+
try:
253+
cmd_dict: Dict[str, Union[str, List[str]]] = {
254+
'prefix': 'osd pool create',
255+
'pool': pool_name,
256+
'pool_type': pool_type,
257+
}
258+
if pool_attrs:
259+
for k, v in pool_attrs.items():
260+
cmd_dict[k] = v
261+
self.check_mon_command(cmd_dict)
262+
except MonCommandFailed as e:
263+
raise PoolCreationError(f'RGW module failed to create pool {pool_name} '
264+
f'of type {pool_type} with attrs [{pool_attrs}]: {str(e)}')
265+
# enable the rgw application on the pool
266+
try:
267+
self.check_mon_command({
268+
'prefix': 'osd pool application enable',
269+
'pool': pool_name,
270+
'app': 'rgw',
271+
})
272+
except MonCommandFailed as e:
273+
raise PoolCreationError(f'Failed enabling application "rgw" on pool {pool_name}: {str(e)}')
274+
275+
zone_name = spec.rgw_zone
276+
for pool_suffix in [
277+
'buckets.index',
278+
'meta',
279+
'log',
280+
'control'
281+
]:
282+
# TODO: add size?
283+
non_data_pool_attrs: Dict[str, Union[str, List[str]]] = {
284+
'pg-num': '16' if 'index' in pool_suffix else '8',
285+
}
286+
_pool_create_command(f'{zone_name}.rgw.{pool_suffix}', 'replicated', non_data_pool_attrs)
287+
288+
if spec.data_pool_attributes:
289+
if spec.data_pool_attributes.get('type', 'ec') == 'ec':
290+
# we need to create ec profile
291+
assert zone_name is not None
292+
profile_name = self.create_zone_ec_profile(zone_name, spec.data_pool_attributes)
293+
# now we can pass the ec profile into the pool create command
294+
data_pool_attrs: Dict[str, Union[str, List[str]]] = {
295+
'erasure_code_profile': profile_name
296+
}
297+
if 'pg_num' in spec.data_pool_attributes:
298+
data_pool_attrs['pg_num'] = spec.data_pool_attributes['pg_num']
299+
_pool_create_command(f'{zone_name}.rgw.buckets.data', 'erasure', data_pool_attrs)
300+
else:
301+
# replicated pool
302+
data_pool_attrs = {k: v for k, v in spec.data_pool_attributes.items() if k != 'type'}
303+
_pool_create_command(f'{zone_name}.rgw.buckets.data', 'replicated', data_pool_attrs)
304+
305+
def create_zone_ec_profile(self, zone_name: str, pool_attributes: Optional[Dict[str, str]]) -> str:
306+
# creates ec profile and returns profile name
307+
ec_pool_kv_pairs = {}
308+
if pool_attributes is not None:
309+
ec_pool_kv_pairs = {k: v for k, v in pool_attributes.items() if k not in ['type', 'pg_num']}
310+
profile_name = f'{zone_name}_zone_data_pool_ec_profile'
311+
profile_attrs = [f'{k}={v}' for k, v in ec_pool_kv_pairs.items()]
312+
cmd_dict: Dict[str, Union[str, List[str]]] = {
313+
'prefix': 'osd erasure-code-profile set',
314+
'name': profile_name,
315+
}
316+
if profile_attrs:
317+
cmd_dict['profile'] = profile_attrs
318+
try:
319+
self.check_mon_command(cmd_dict)
320+
except MonCommandFailed as e:
321+
raise PoolCreationError(f'RGW module failed to create ec profile {profile_name} '
322+
f'with attrs {profile_attrs}: {str(e)}')
323+
return profile_name
324+
232325
@CLICommand('rgw realm zone-creds create', perm='rw')
233326
def _cmd_rgw_realm_new_zone_creds(self,
234327
realm_name: Optional[str] = None,

src/python-common/ceph/deployment/service_spec.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,6 +1228,7 @@ def __init__(self,
12281228
update_endpoints: Optional[bool] = False,
12291229
zone_endpoints: Optional[str] = None, # comma separated endpoints list
12301230
zonegroup_hostnames: Optional[List[str]] = None,
1231+
data_pool_attributes: Optional[Dict[str, str]] = None,
12311232
rgw_user_counters_cache: Optional[bool] = False,
12321233
rgw_user_counters_cache_size: Optional[int] = None,
12331234
rgw_bucket_counters_cache: Optional[bool] = False,
@@ -1290,6 +1291,8 @@ def __init__(self,
12901291
#: Used to make RGW not do multisite replication so it can dedicate to IO
12911292
self.disable_multisite_sync_traffic = disable_multisite_sync_traffic
12921293
self.wildcard_enabled = wildcard_enabled
1294+
#: Attributes for <zone-name>.rgw.buckets.data pool created in rgw realm bootstrap command
1295+
self.data_pool_attributes = data_pool_attributes
12931296

12941297
def get_port_start(self) -> List[int]:
12951298
ports = self.get_port()
@@ -1340,6 +1343,18 @@ def validate(self) -> None:
13401343
raise SpecValidationError('"generate_cert" field and "rgw_frontend_ssl_certificate" '
13411344
'field are mutually exclusive')
13421345

1346+
if self.data_pool_attributes:
1347+
if self.data_pool_attributes.get('type', 'ec') == 'ec':
1348+
if any(attr not in self.data_pool_attributes.keys() for attr in ['k', 'm']):
1349+
raise SpecValidationError(
1350+
'"k" and "m" are required parameters for ec pool (defaults to ec pool)'
1351+
)
1352+
if 'erasure_code_profile' in self.data_pool_attributes.keys():
1353+
raise SpecValidationError(
1354+
'invalid option in data_pool_attribues "erasure_code_profile"'
1355+
'ec profile will be generated automatically based on provided attributes'
1356+
)
1357+
13431358

13441359
yaml.add_representer(RGWSpec, ServiceSpec.yaml_representer)
13451360

0 commit comments

Comments
 (0)