]> git.proxmox.com Git - pve-manager.git/blame - PVE/API2/Ceph/Pools.pm
ceph: add titles to ceph_pool_common_options
[pve-manager.git] / PVE / API2 / Ceph / Pools.pm
CommitLineData
56d02a86
AA
1package PVE::API2::Ceph::Pools;
2
3use strict;
4use warnings;
5
6use PVE::Ceph::Tools;
7use PVE::Ceph::Services;
8use PVE::JSONSchema qw(get_standard_option);
9use PVE::RADOS;
10use PVE::RESTHandler;
11use PVE::RPCEnvironment;
12use PVE::Storage;
13use PVE::Tools qw(extract_param);
14
15use PVE::API2::Storage::Config;
16
17use base qw(PVE::RESTHandler);
18
19__PACKAGE__->register_method ({
20 name => 'lspools',
21 path => '',
22 method => 'GET',
23 description => "List all pools.",
24 proxyto => 'node',
25 protected => 1,
26 permissions => {
27 check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1],
28 },
29 parameters => {
30 additionalProperties => 0,
31 properties => {
32 node => get_standard_option('pve-node'),
33 },
34 },
35 returns => {
36 type => 'array',
37 items => {
38 type => "object",
39 properties => {
40 pool => { type => 'integer', title => 'ID' },
41 pool_name => { type => 'string', title => 'Name' },
42 size => { type => 'integer', title => 'Size' },
43 min_size => { type => 'integer', title => 'Min Size' },
44 pg_num => { type => 'integer', title => 'PG Num' },
45 pg_autoscale_mode => { type => 'string', optional => 1, title => 'PG Autoscale Mode' },
46 crush_rule => { type => 'integer', title => 'Crush Rule' },
47 crush_rule_name => { type => 'string', title => 'Crush Rule Name' },
48 percent_used => { type => 'number', title => '%-Used' },
49 bytes_used => { type => 'integer', title => 'Used' },
50 },
51 },
52 links => [ { rel => 'child', href => "{pool_name}" } ],
53 },
54 code => sub {
55 my ($param) = @_;
56
57 PVE::Ceph::Tools::check_ceph_inited();
58
59 my $rados = PVE::RADOS->new();
60
61 my $stats = {};
62 my $res = $rados->mon_command({ prefix => 'df' });
63
64 foreach my $d (@{$res->{pools}}) {
65 next if !$d->{stats};
66 next if !defined($d->{id});
67 $stats->{$d->{id}} = $d->{stats};
68 }
69
70 $res = $rados->mon_command({ prefix => 'osd dump' });
71 my $rulestmp = $rados->mon_command({ prefix => 'osd crush rule dump'});
72
73 my $rules = {};
74 for my $rule (@$rulestmp) {
75 $rules->{$rule->{rule_id}} = $rule->{rule_name};
76 }
77
78 my $data = [];
79 my $attr_list = [
80 'pool',
81 'pool_name',
82 'size',
83 'min_size',
84 'pg_num',
85 'crush_rule',
86 'pg_autoscale_mode',
87 ];
88
89 foreach my $e (@{$res->{pools}}) {
90 my $d = {};
91 foreach my $attr (@$attr_list) {
92 $d->{$attr} = $e->{$attr} if defined($e->{$attr});
93 }
94
95 if (defined($d->{crush_rule}) && defined($rules->{$d->{crush_rule}})) {
96 $d->{crush_rule_name} = $rules->{$d->{crush_rule}};
97 }
98
99 if (my $s = $stats->{$d->{pool}}) {
100 $d->{bytes_used} = $s->{bytes_used};
101 $d->{percent_used} = $s->{percent_used};
102 }
103 push @$data, $d;
104 }
105
106
107 return $data;
108 }});
109
110
111my $ceph_pool_common_options = sub {
112 my ($nodefault) = shift;
113 my $options = {
114 name => {
461e2141 115 title => 'Name',
56d02a86
AA
116 description => "The name of the pool. It must be unique.",
117 type => 'string',
118 },
119 size => {
461e2141 120 title => 'Size',
56d02a86
AA
121 description => 'Number of replicas per object',
122 type => 'integer',
123 default => 3,
124 optional => 1,
125 minimum => 1,
126 maximum => 7,
127 },
128 min_size => {
461e2141 129 title => 'Min Size',
56d02a86
AA
130 description => 'Minimum number of replicas per object',
131 type => 'integer',
132 default => 2,
133 optional => 1,
134 minimum => 1,
135 maximum => 7,
136 },
137 pg_num => {
461e2141 138 title => 'PG Num',
56d02a86
AA
139 description => "Number of placement groups.",
140 type => 'integer',
141 default => 128,
142 optional => 1,
143 minimum => 8,
144 maximum => 32768,
145 },
146 crush_rule => {
461e2141 147 title => 'Crush Rule Name',
56d02a86
AA
148 description => "The rule to use for mapping object placement in the cluster.",
149 type => 'string',
150 optional => 1,
151 },
152 application => {
461e2141 153 title => 'Application',
56d02a86
AA
154 description => "The application of the pool.",
155 default => 'rbd',
156 type => 'string',
157 enum => ['rbd', 'cephfs', 'rgw'],
158 optional => 1,
159 },
160 pg_autoscale_mode => {
461e2141 161 title => 'PG Autoscale Mode',
56d02a86
AA
162 description => "The automatic PG scaling mode of the pool.",
163 type => 'string',
164 enum => ['on', 'off', 'warn'],
165 default => 'warn',
166 optional => 1,
167 },
168 };
169
170 if ($nodefault) {
171 delete $options->{$_}->{default} for keys %$options;
172 }
173 return $options;
174};
175
176
177my $add_storage = sub {
178 my ($pool, $storeid) = @_;
179
180 my $storage_params = {
181 type => 'rbd',
182 pool => $pool,
183 storage => $storeid,
184 krbd => 0,
185 content => 'rootdir,images',
186 };
187
188 PVE::API2::Storage::Config->create($storage_params);
189};
190
191my $get_storages = sub {
192 my ($pool) = @_;
193
194 my $cfg = PVE::Storage::config();
195
196 my $storages = $cfg->{ids};
197 my $res = {};
198 foreach my $storeid (keys %$storages) {
199 my $curr = $storages->{$storeid};
200 $res->{$storeid} = $storages->{$storeid}
201 if $curr->{type} eq 'rbd' && $pool eq $curr->{pool};
202 }
203
204 return $res;
205};
206
207
208__PACKAGE__->register_method ({
209 name => 'createpool',
210 path => '',
211 method => 'POST',
212 description => "Create POOL",
213 proxyto => 'node',
214 protected => 1,
215 permissions => {
216 check => ['perm', '/', [ 'Sys.Modify' ]],
217 },
218 parameters => {
219 additionalProperties => 0,
220 properties => {
221 node => get_standard_option('pve-node'),
222 add_storages => {
223 description => "Configure VM and CT storage using the new pool.",
224 type => 'boolean',
225 optional => 1,
226 },
227 %{ $ceph_pool_common_options->() },
228 },
229 },
230 returns => { type => 'string' },
231 code => sub {
232 my ($param) = @_;
233
234 PVE::Cluster::check_cfs_quorum();
235 PVE::Ceph::Tools::check_ceph_configured();
236
237 my $pool = extract_param($param, 'name');
238 my $node = extract_param($param, 'node');
239 my $add_storages = extract_param($param, 'add_storages');
240
241 my $rpcenv = PVE::RPCEnvironment::get();
242 my $user = $rpcenv->get_user();
243
244 if ($add_storages) {
245 $rpcenv->check($user, '/storage', ['Datastore.Allocate']);
246 die "pool name contains characters which are illegal for storage naming\n"
247 if !PVE::JSONSchema::parse_storage_id($pool);
248 }
249
250 # pool defaults
251 $param->{pg_num} //= 128;
252 $param->{size} //= 3;
253 $param->{min_size} //= 2;
254 $param->{application} //= 'rbd';
255 $param->{pg_autoscale_mode} //= 'warn';
256
257 my $worker = sub {
258
259 PVE::Ceph::Tools::create_pool($pool, $param);
260
261 if ($add_storages) {
262 my $err;
263 eval { $add_storage->($pool, "${pool}"); };
264 if ($@) {
265 warn "failed to add storage: $@";
266 $err = 1;
267 }
268 die "adding storage for pool '$pool' failed, check log and add manually!\n"
269 if $err;
270 }
271 };
272
273 return $rpcenv->fork_worker('cephcreatepool', $pool, $user, $worker);
274 }});
275
276
277__PACKAGE__->register_method ({
278 name => 'destroypool',
279 path => '{name}',
280 method => 'DELETE',
281 description => "Destroy pool",
282 proxyto => 'node',
283 protected => 1,
284 permissions => {
285 check => ['perm', '/', [ 'Sys.Modify' ]],
286 },
287 parameters => {
288 additionalProperties => 0,
289 properties => {
290 node => get_standard_option('pve-node'),
291 name => {
292 description => "The name of the pool. It must be unique.",
293 type => 'string',
294 },
295 force => {
296 description => "If true, destroys pool even if in use",
297 type => 'boolean',
298 optional => 1,
299 default => 0,
300 },
301 remove_storages => {
302 description => "Remove all pveceph-managed storages configured for this pool",
303 type => 'boolean',
304 optional => 1,
305 default => 0,
306 },
307 },
308 },
309 returns => { type => 'string' },
310 code => sub {
311 my ($param) = @_;
312
313 PVE::Ceph::Tools::check_ceph_inited();
314
315 my $rpcenv = PVE::RPCEnvironment::get();
316 my $user = $rpcenv->get_user();
317 $rpcenv->check($user, '/storage', ['Datastore.Allocate'])
318 if $param->{remove_storages};
319
320 my $pool = $param->{name};
321
322 my $worker = sub {
323 my $storages = $get_storages->($pool);
324
325 # if not forced, destroy ceph pool only when no
326 # vm disks are on it anymore
327 if (!$param->{force}) {
328 my $storagecfg = PVE::Storage::config();
329 foreach my $storeid (keys %$storages) {
330 my $storage = $storages->{$storeid};
331
332 # check if any vm disks are on the pool
333 print "checking storage '$storeid' for RBD images..\n";
334 my $res = PVE::Storage::vdisk_list($storagecfg, $storeid);
335 die "ceph pool '$pool' still in use by storage '$storeid'\n"
336 if @{$res->{$storeid}} != 0;
337 }
338 }
339
340 PVE::Ceph::Tools::destroy_pool($pool);
341
342 if ($param->{remove_storages}) {
343 my $err;
344 foreach my $storeid (keys %$storages) {
345 # skip external clusters, not managed by pveceph
346 next if $storages->{$storeid}->{monhost};
347 eval { PVE::API2::Storage::Config->delete({storage => $storeid}) };
348 if ($@) {
349 warn "failed to remove storage '$storeid': $@\n";
350 $err = 1;
351 }
352 }
353 die "failed to remove (some) storages - check log and remove manually!\n"
354 if $err;
355 }
356 };
357 return $rpcenv->fork_worker('cephdestroypool', $pool, $user, $worker);
358 }});
359
360
361__PACKAGE__->register_method ({
362 name => 'setpool',
363 path => '{name}',
364 method => 'PUT',
365 description => "Change POOL settings",
366 proxyto => 'node',
367 protected => 1,
368 permissions => {
369 check => ['perm', '/', [ 'Sys.Modify' ]],
370 },
371 parameters => {
372 additionalProperties => 0,
373 properties => {
374 node => get_standard_option('pve-node'),
375 %{ $ceph_pool_common_options->('nodefault') },
376 },
377 },
378 returns => { type => 'string' },
379 code => sub {
380 my ($param) = @_;
381
382 PVE::Ceph::Tools::check_ceph_configured();
383
384 my $rpcenv = PVE::RPCEnvironment::get();
385 my $authuser = $rpcenv->get_user();
386
51d6db58
AA
387 my $pool = extract_param($param, 'name');
388 my $node = extract_param($param, 'node');
56d02a86
AA
389
390 my $worker = sub {
51d6db58 391 PVE::Ceph::Tools::set_pool($pool, $param);
56d02a86
AA
392 };
393
394 return $rpcenv->fork_worker('cephsetpool', $pool, $authuser, $worker);
395 }});
396
397
3981;