1 # -*- coding: utf-8 -*-
2 from __future__
import absolute_import
6 from . import ApiController
, RESTController
, Endpoint
, ReadPermission
, Task
8 from ..security
import Scope
9 from ..services
.ceph_service
import CephService
10 from ..services
.rbd
import RbdConfiguration
11 from ..services
.exception
import handle_send_command_error
12 from ..tools
import str_to_bool
15 def pool_task(name
, metadata
, wait_for
=2.0):
16 return Task("pool/{}".format(name
), metadata
, wait_for
)
19 @ApiController('/pool', Scope
.POOL
)
20 class Pool(RESTController
):
23 def _serialize_pool(pool
, attrs
):
24 if not attrs
or not isinstance(attrs
, list):
27 crush_rules
= {r
['rule_id']: r
["rule_name"] for r
in mgr
.get('osd_map_crush')['rules']}
34 res
[attr
] = {1: 'replicated', 3: 'erasure'}[pool
[attr
]]
35 elif attr
== 'crush_rule':
36 res
[attr
] = crush_rules
[pool
[attr
]]
37 elif attr
== 'application_metadata':
38 res
[attr
] = list(pool
[attr
].keys())
40 res
[attr
] = pool
[attr
]
42 # pool_name is mandatory
43 res
['pool_name'] = pool
['pool_name']
46 def _pool_list(self
, attrs
=None, stats
=False):
48 attrs
= attrs
.split(',')
50 if str_to_bool(stats
):
51 pools
= CephService
.get_pool_list_with_stats()
53 pools
= CephService
.get_pool_list()
55 return [self
._serialize
_pool
(pool
, attrs
) for pool
in pools
]
57 def list(self
, attrs
=None, stats
=False):
58 return self
._pool
_list
(attrs
, stats
)
60 def _get(self
, pool_name
, attrs
=None, stats
=False):
61 # type: (str, str, bool) -> dict
62 pools
= self
._pool
_list
(attrs
, stats
)
63 pool
= [pool
for pool
in pools
if pool
['pool_name'] == pool_name
]
65 raise cherrypy
.NotFound('No such pool')
68 def get(self
, pool_name
, attrs
=None, stats
=False):
69 # type: (str, str, bool) -> dict
70 pool
= self
._get
(pool_name
, attrs
, stats
)
71 pool
['configuration'] = RbdConfiguration(pool_name
).list()
74 @pool_task('delete', ['{pool_name}'])
75 @handle_send_command_error('pool')
76 def delete(self
, pool_name
):
77 return CephService
.send_command('mon', 'osd pool delete', pool
=pool_name
, pool2
=pool_name
,
78 yes_i_really_really_mean_it
=True)
80 @pool_task('edit', ['{pool_name}'])
81 def set(self
, pool_name
, flags
=None, application_metadata
=None, configuration
=None, **kwargs
):
82 self
._set
_pool
_values
(pool_name
, application_metadata
, flags
, True, kwargs
)
83 RbdConfiguration(pool_name
).set_configuration(configuration
)
85 @pool_task('create', {'pool_name': '{pool}'})
86 @handle_send_command_error('pool')
87 def create(self
, pool
, pg_num
, pool_type
, erasure_code_profile
=None, flags
=None,
88 application_metadata
=None, rule_name
=None, configuration
=None, **kwargs
):
89 ecp
= erasure_code_profile
if erasure_code_profile
else None
90 CephService
.send_command('mon', 'osd pool create', pool
=pool
, pg_num
=int(pg_num
),
91 pgp_num
=int(pg_num
), pool_type
=pool_type
, erasure_code_profile
=ecp
,
93 self
._set
_pool
_values
(pool
, application_metadata
, flags
, False, kwargs
)
94 RbdConfiguration(pool
).set_configuration(configuration
)
96 def _set_pool_values(self
, pool
, application_metadata
, flags
, update_existing
, kwargs
):
99 current_pool
= self
._get
(pool
)
100 self
._handle
_update
_compression
_args
(current_pool
.get('options'), kwargs
)
101 if flags
and 'ec_overwrites' in flags
:
102 CephService
.send_command('mon', 'osd pool set', pool
=pool
, var
='allow_ec_overwrites',
104 if application_metadata
is not None:
105 def set_app(what
, app
):
106 CephService
.send_command('mon', 'osd pool application ' + what
, pool
=pool
, app
=app
,
107 yes_i_really_mean_it
=True)
109 original_app_metadata
= set(
110 current_pool
.get('application_metadata'))
112 original_app_metadata
= set()
114 for app
in original_app_metadata
- set(application_metadata
):
115 set_app('disable', app
)
116 for app
in set(application_metadata
) - original_app_metadata
:
117 set_app('enable', app
)
119 def set_key(key
, value
):
120 CephService
.send_command('mon', 'osd pool set', pool
=pool
, var
=key
, val
=str(value
))
122 for key
, value
in kwargs
.items():
129 set_key('pgp_num', value
)
131 CephService
.send_command('mon', 'osd pool rename', srcpool
=pool
, destpool
=destpool
)
133 def _handle_update_compression_args(self
, options
, kwargs
):
134 if kwargs
.get('compression_mode') == 'unset' and options
is not None:
135 def reset_arg(arg
, value
):
138 for arg
in ['compression_min_blob_size', 'compression_max_blob_size',
139 'compression_required_ratio']:
141 reset_arg('compression_algorithm', 'unset')
143 @RESTController.Resource()
145 def configuration(self
, pool_name
):
146 return RbdConfiguration(pool_name
).list()
150 def _info(self
, pool_name
=''):
151 # type: (str) -> dict
152 """Used by the create-pool dialog"""
154 def rules(pool_type
):
156 for r
in mgr
.get('osd_map_crush')['rules']
157 if r
['type'] == pool_type
]
160 return all(o
['osd_objectstore'] == 'bluestore'
161 for o
in mgr
.get('osd_metadata').values())
163 def compression_enum(conf_name
):
164 return [[v
for v
in o
['enum_values'] if len(v
) > 0]
165 for o
in mgr
.get('config_options')['options']
166 if o
['name'] == conf_name
][0]
169 "pool_names": [p
['pool_name'] for p
in self
._pool
_list
()],
170 "crush_rules_replicated": rules(1),
171 "crush_rules_erasure": rules(3),
172 "is_all_bluestore": all_bluestore(),
173 "osd_count": len(mgr
.get('osd_map')['osds']),
174 "bluestore_compression_algorithm": mgr
.get('config')['bluestore_compression_algorithm'],
175 "compression_algorithms": compression_enum('bluestore_compression_algorithm'),
176 "compression_modes": compression_enum('bluestore_compression_mode'),
180 result
['pool_options'] = RbdConfiguration(pool_name
).list()