]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/controllers/pool.py
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / pybind / mgr / dashboard / controllers / pool.py
1 # -*- coding: utf-8 -*-
2 from __future__ import absolute_import
3
4 import cherrypy
5
6 from . import ApiController, RESTController, Endpoint, ReadPermission, Task
7 from .. import mgr
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
13
14
15 def pool_task(name, metadata, wait_for=2.0):
16 return Task("pool/{}".format(name), metadata, wait_for)
17
18
19 @ApiController('/pool', Scope.POOL)
20 class Pool(RESTController):
21
22 @staticmethod
23 def _serialize_pool(pool, attrs):
24 if not attrs or not isinstance(attrs, list):
25 attrs = pool.keys()
26
27 crush_rules = {r['rule_id']: r["rule_name"] for r in mgr.get('osd_map_crush')['rules']}
28
29 res = {}
30 for attr in attrs:
31 if attr not in pool:
32 continue
33 if attr == 'type':
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())
39 else:
40 res[attr] = pool[attr]
41
42 # pool_name is mandatory
43 res['pool_name'] = pool['pool_name']
44 return res
45
46 def _pool_list(self, attrs=None, stats=False):
47 if attrs:
48 attrs = attrs.split(',')
49
50 if str_to_bool(stats):
51 pools = CephService.get_pool_list_with_stats()
52 else:
53 pools = CephService.get_pool_list()
54
55 return [self._serialize_pool(pool, attrs) for pool in pools]
56
57 def list(self, attrs=None, stats=False):
58 return self._pool_list(attrs, stats)
59
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]
64 if not pool:
65 raise cherrypy.NotFound('No such pool')
66 return pool[0]
67
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()
72 return pool
73
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)
79
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)
84
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,
92 rule=rule_name)
93 self._set_pool_values(pool, application_metadata, flags, False, kwargs)
94 RbdConfiguration(pool).set_configuration(configuration)
95
96 def _set_pool_values(self, pool, application_metadata, flags, update_existing, kwargs):
97 update_name = False
98 if update_existing:
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',
103 val='true')
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)
108 if update_existing:
109 original_app_metadata = set(
110 current_pool.get('application_metadata'))
111 else:
112 original_app_metadata = set()
113
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)
118
119 def set_key(key, value):
120 CephService.send_command('mon', 'osd pool set', pool=pool, var=key, val=str(value))
121
122 for key, value in kwargs.items():
123 if key == 'pool':
124 update_name = True
125 destpool = value
126 else:
127 set_key(key, value)
128 if key == 'pg_num':
129 set_key('pgp_num', value)
130 if update_name:
131 CephService.send_command('mon', 'osd pool rename', srcpool=pool, destpool=destpool)
132
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):
136 if options.get(arg):
137 kwargs[arg] = value
138 for arg in ['compression_min_blob_size', 'compression_max_blob_size',
139 'compression_required_ratio']:
140 reset_arg(arg, '0')
141 reset_arg('compression_algorithm', 'unset')
142
143 @RESTController.Resource()
144 @ReadPermission
145 def configuration(self, pool_name):
146 return RbdConfiguration(pool_name).list()
147
148 @Endpoint()
149 @ReadPermission
150 def _info(self, pool_name=''):
151 # type: (str) -> dict
152 """Used by the create-pool dialog"""
153
154 def rules(pool_type):
155 return [r
156 for r in mgr.get('osd_map_crush')['rules']
157 if r['type'] == pool_type]
158
159 def all_bluestore():
160 return all(o['osd_objectstore'] == 'bluestore'
161 for o in mgr.get('osd_metadata').values())
162
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]
167
168 result = {
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'),
177 }
178
179 if pool_name:
180 result['pool_options'] = RbdConfiguration(pool_name).list()
181
182 return result