]>
git.proxmox.com Git - pve-manager.git/blob - PVE/API2/Ceph/Pools.pm
1 package PVE
::API2
::Ceph
::Pools
;
7 use PVE
::Ceph
::Services
;
8 use PVE
::JSONSchema
qw(get_standard_option);
11 use PVE
::RPCEnvironment
;
13 use PVE
::Tools
qw(extract_param);
15 use PVE
::API2
::Storage
::Config
;
17 use base
qw(PVE::RESTHandler);
19 my $get_autoscale_status = sub {
22 $rados = PVE
::RADOS-
>new() if !defined($rados);
24 my $autoscale = $rados->mon_command({
25 prefix
=> 'osd pool autoscale-status'});
28 foreach my $p (@$autoscale) {
29 $p->{would_adjust
} = "$p->{would_adjust}"; # boolean
30 $data->{$p->{pool_name
}} = $p;
37 __PACKAGE__-
>register_method ({
41 description
=> "List all pools.",
45 check
=> ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any
=> 1],
48 additionalProperties
=> 0,
50 node
=> get_standard_option
('pve-node'),
58 pool
=> { type
=> 'integer', title
=> 'ID' },
59 pool_name
=> { type
=> 'string', title
=> 'Name' },
60 size
=> { type
=> 'integer', title
=> 'Size' },
61 min_size
=> { type
=> 'integer', title
=> 'Min Size' },
62 pg_num
=> { type
=> 'integer', title
=> 'PG Num' },
63 pg_num_min
=> { type
=> 'integer', title
=> 'min. PG Num', optional
=> 1, },
64 pg_num_final
=> { type
=> 'integer', title
=> 'Optimal PG Num', optional
=> 1, },
65 pg_autoscale_mode
=> { type
=> 'string', title
=> 'PG Autoscale Mode', optional
=> 1, },
66 crush_rule
=> { type
=> 'integer', title
=> 'Crush Rule' },
67 crush_rule_name
=> { type
=> 'string', title
=> 'Crush Rule Name' },
68 percent_used
=> { type
=> 'number', title
=> '%-Used' },
69 bytes_used
=> { type
=> 'integer', title
=> 'Used' },
70 target_size
=> { type
=> 'integer', title
=> 'PG Autoscale Target Size', optional
=> 1 },
71 target_size_ratio
=> { type
=> 'number', title
=> 'PG Autoscale Target Ratio',optional
=> 1, },
72 autoscale_status
=> { type
=> 'object', title
=> 'Autoscale Status', optional
=> 1 },
75 links
=> [ { rel
=> 'child', href
=> "{pool_name}" } ],
80 PVE
::Ceph
::Tools
::check_ceph_inited
();
82 my $rados = PVE
::RADOS-
>new();
85 my $res = $rados->mon_command({ prefix
=> 'df' });
87 foreach my $d (@{$res->{pools
}}) {
89 next if !defined($d->{id
});
90 $stats->{$d->{id
}} = $d->{stats
};
93 $res = $rados->mon_command({ prefix
=> 'osd dump' });
94 my $rulestmp = $rados->mon_command({ prefix
=> 'osd crush rule dump'});
97 for my $rule (@$rulestmp) {
98 $rules->{$rule->{rule_id
}} = $rule->{rule_name
};
112 # pg_autoscaler module is not enabled in Nautilus
113 my $autoscale = eval { $get_autoscale_status->($rados) };
115 foreach my $e (@{$res->{pools
}}) {
117 foreach my $attr (@$attr_list) {
118 $d->{$attr} = $e->{$attr} if defined($e->{$attr});
122 $d->{autoscale_status
} = $autoscale->{$d->{pool_name
}};
123 $d->{pg_num_final
} = $d->{autoscale_status
}->{pg_num_final
};
124 # some info is nested under options instead
125 $d->{pg_num_min
} = $e->{options
}->{pg_num_min
};
126 $d->{target_size
} = $e->{options
}->{target_size_bytes
};
127 $d->{target_size_ratio
} = $e->{options
}->{target_size_ratio
};
130 if (defined($d->{crush_rule
}) && defined($rules->{$d->{crush_rule
}})) {
131 $d->{crush_rule_name
} = $rules->{$d->{crush_rule
}};
134 if (my $s = $stats->{$d->{pool
}}) {
135 $d->{bytes_used
} = $s->{bytes_used
};
136 $d->{percent_used
} = $s->{percent_used
};
146 my $ceph_pool_common_options = sub {
147 my ($nodefault) = shift;
151 description
=> "The name of the pool. It must be unique.",
156 description
=> 'Number of replicas per object',
165 description
=> 'Minimum number of replicas per object',
174 description
=> "Number of placement groups.",
182 title
=> 'min. PG Num',
183 description
=> "Minimal number of placement groups.",
189 title
=> 'Crush Rule Name',
190 description
=> "The rule to use for mapping object placement in the cluster.",
195 title
=> 'Application',
196 description
=> "The application of the pool.",
199 enum
=> ['rbd', 'cephfs', 'rgw'],
202 pg_autoscale_mode
=> {
203 title
=> 'PG Autoscale Mode',
204 description
=> "The automatic PG scaling mode of the pool.",
206 enum
=> ['on', 'off', 'warn'],
211 description
=> "The estimated target size of the pool for the PG autoscaler.",
212 title
=> 'PG Autoscale Target Size',
214 pattern
=> '^(\d+(\.\d+)?)([KMGT])?$',
217 target_size_ratio
=> {
218 description
=> "The estimated target ratio of the pool for the PG autoscaler.",
219 title
=> 'PG Autoscale Target Ratio',
226 delete $options->{$_}->{default} for keys %$options;
232 my $add_storage = sub {
233 my ($pool, $storeid) = @_;
235 my $storage_params = {
240 content
=> 'rootdir,images',
243 PVE
::API2
::Storage
::Config-
>create($storage_params);
246 my $get_storages = sub {
249 my $cfg = PVE
::Storage
::config
();
251 my $storages = $cfg->{ids
};
253 foreach my $storeid (keys %$storages) {
254 my $curr = $storages->{$storeid};
255 $res->{$storeid} = $storages->{$storeid}
256 if $curr->{type
} eq 'rbd' && $pool eq $curr->{pool
};
263 __PACKAGE__-
>register_method ({
264 name
=> 'createpool',
267 description
=> "Create POOL",
271 check
=> ['perm', '/', [ 'Sys.Modify' ]],
274 additionalProperties
=> 0,
276 node
=> get_standard_option
('pve-node'),
278 description
=> "Configure VM and CT storage using the new pool.",
282 %{ $ceph_pool_common_options->() },
285 returns
=> { type
=> 'string' },
289 PVE
::Cluster
::check_cfs_quorum
();
290 PVE
::Ceph
::Tools
::check_ceph_configured
();
292 my $pool = extract_param
($param, 'name');
293 my $node = extract_param
($param, 'node');
294 my $add_storages = extract_param
($param, 'add_storages');
296 my $rpcenv = PVE
::RPCEnvironment
::get
();
297 my $user = $rpcenv->get_user();
299 # Ceph uses target_size_bytes
300 if (defined($param->{'target_size'})) {
301 my $target_sizestr = extract_param
($param, 'target_size');
302 $param->{target_size_bytes
} = PVE
::JSONSchema
::parse_size
($target_sizestr);
306 $rpcenv->check($user, '/storage', ['Datastore.Allocate']);
307 die "pool name contains characters which are illegal for storage naming\n"
308 if !PVE
::JSONSchema
::parse_storage_id
($pool);
312 $param->{pg_num
} //= 128;
313 $param->{size
} //= 3;
314 $param->{min_size
} //= 2;
315 $param->{application
} //= 'rbd';
316 $param->{pg_autoscale_mode
} //= 'warn';
320 PVE
::Ceph
::Tools
::create_pool
($pool, $param);
324 eval { $add_storage->($pool, "${pool}"); };
326 warn "failed to add storage: $@";
329 die "adding storage for pool '$pool' failed, check log and add manually!\n"
334 return $rpcenv->fork_worker('cephcreatepool', $pool, $user, $worker);
338 __PACKAGE__-
>register_method ({
339 name
=> 'destroypool',
342 description
=> "Destroy pool",
346 check
=> ['perm', '/', [ 'Sys.Modify' ]],
349 additionalProperties
=> 0,
351 node
=> get_standard_option
('pve-node'),
353 description
=> "The name of the pool. It must be unique.",
357 description
=> "If true, destroys pool even if in use",
363 description
=> "Remove all pveceph-managed storages configured for this pool",
370 returns
=> { type
=> 'string' },
374 PVE
::Ceph
::Tools
::check_ceph_inited
();
376 my $rpcenv = PVE
::RPCEnvironment
::get
();
377 my $user = $rpcenv->get_user();
378 $rpcenv->check($user, '/storage', ['Datastore.Allocate'])
379 if $param->{remove_storages
};
381 my $pool = $param->{name
};
384 my $storages = $get_storages->($pool);
386 # if not forced, destroy ceph pool only when no
387 # vm disks are on it anymore
388 if (!$param->{force
}) {
389 my $storagecfg = PVE
::Storage
::config
();
390 foreach my $storeid (keys %$storages) {
391 my $storage = $storages->{$storeid};
393 # check if any vm disks are on the pool
394 print "checking storage '$storeid' for RBD images..\n";
395 my $res = PVE
::Storage
::vdisk_list
($storagecfg, $storeid);
396 die "ceph pool '$pool' still in use by storage '$storeid'\n"
397 if @{$res->{$storeid}} != 0;
401 PVE
::Ceph
::Tools
::destroy_pool
($pool);
403 if ($param->{remove_storages
}) {
405 foreach my $storeid (keys %$storages) {
406 # skip external clusters, not managed by pveceph
407 next if $storages->{$storeid}->{monhost
};
408 eval { PVE
::API2
::Storage
::Config-
>delete({storage
=> $storeid}) };
410 warn "failed to remove storage '$storeid': $@\n";
414 die "failed to remove (some) storages - check log and remove manually!\n"
418 return $rpcenv->fork_worker('cephdestroypool', $pool, $user, $worker);
422 __PACKAGE__-
>register_method ({
426 description
=> "Change POOL settings",
430 check
=> ['perm', '/', [ 'Sys.Modify' ]],
433 additionalProperties
=> 0,
435 node
=> get_standard_option
('pve-node'),
436 %{ $ceph_pool_common_options->('nodefault') },
439 returns
=> { type
=> 'string' },
443 PVE
::Ceph
::Tools
::check_ceph_configured
();
445 my $rpcenv = PVE
::RPCEnvironment
::get
();
446 my $authuser = $rpcenv->get_user();
448 my $pool = extract_param
($param, 'name');
449 my $node = extract_param
($param, 'node');
451 # Ceph uses target_size_bytes
452 if (defined($param->{'target_size'})) {
453 my $target_sizestr = extract_param
($param, 'target_size');
454 $param->{target_size_bytes
} = PVE
::JSONSchema
::parse_size
($target_sizestr);
458 PVE
::Ceph
::Tools
::set_pool
($pool, $param);
461 return $rpcenv->fork_worker('cephsetpool', $pool, $authuser, $worker);
465 __PACKAGE__-
>register_method ({
469 description
=> "List pool settings.",
473 check
=> ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any
=> 1],
476 additionalProperties
=> 0,
478 node
=> get_standard_option
('pve-node'),
480 description
=> "The name of the pool. It must be unique.",
487 description
=> "If enabled, will display additional data".
495 id
=> { type
=> 'integer', title
=> 'ID' },
496 pgp_num
=> { type
=> 'integer', title
=> 'PGP num' },
497 noscrub
=> { type
=> 'boolean', title
=> 'noscrub' },
498 'nodeep-scrub' => { type
=> 'boolean', title
=> 'nodeep-scrub' },
499 nodelete
=> { type
=> 'boolean', title
=> 'nodelete' },
500 nopgchange
=> { type
=> 'boolean', title
=> 'nopgchange' },
501 nosizechange
=> { type
=> 'boolean', title
=> 'nosizechange' },
502 write_fadvise_dontneed
=> { type
=> 'boolean', title
=> 'write_fadvise_dontneed' },
503 hashpspool
=> { type
=> 'boolean', title
=> 'hashpspool' },
504 use_gmt_hitset
=> { type
=> 'boolean', title
=> 'use_gmt_hitset' },
505 fast_read
=> { type
=> 'boolean', title
=> 'Fast Read' },
506 application_list
=> { type
=> 'array', title
=> 'Application', optional
=> 1 },
507 statistics
=> { type
=> 'object', title
=> 'Statistics', optional
=> 1 },
508 autoscale_status
=> { type
=> 'object', title
=> 'Autoscale Status', optional
=> 1 },
509 %{ $ceph_pool_common_options->() },
515 PVE
::Ceph
::Tools
::check_ceph_inited
();
517 my $verbose = $param->{verbose
};
518 my $pool = $param->{name
};
520 my $rados = PVE
::RADOS-
>new();
521 my $res = $rados->mon_command({
522 prefix
=> 'osd pool get',
528 id
=> $res->{pool_id
},
530 size
=> $res->{size
},
531 min_size
=> $res->{min_size
},
532 pg_num
=> $res->{pg_num
},
533 pg_num_min
=> $res->{pg_num_min
},
534 pgp_num
=> $res->{pgp_num
},
535 crush_rule
=> $res->{crush_rule
},
536 pg_autoscale_mode
=> $res->{pg_autoscale_mode
},
537 noscrub
=> "$res->{noscrub}",
538 'nodeep-scrub' => "$res->{'nodeep-scrub'}",
539 nodelete
=> "$res->{nodelete}",
540 nopgchange
=> "$res->{nopgchange}",
541 nosizechange
=> "$res->{nosizechange}",
542 write_fadvise_dontneed
=> "$res->{write_fadvise_dontneed}",
543 hashpspool
=> "$res->{hashpspool}",
544 use_gmt_hitset
=> "$res->{use_gmt_hitset}",
545 fast_read
=> "$res->{fast_read}",
546 target_size
=> $res->{target_size_bytes
},
547 target_size_ratio
=> $res->{target_size_ratio
},
552 my $res = $rados->mon_command({ prefix
=> 'df' });
554 # pg_autoscaler module is not enabled in Nautilus
555 # avoid partial read further down, use new rados instance
556 my $autoscale_status = eval { $get_autoscale_status->() };
557 $data->{autoscale_status
} = $autoscale_status->{$pool};
559 foreach my $d (@{$res->{pools
}}) {
560 next if !$d->{stats
};
561 next if !defined($d->{name
}) && !$d->{name
} ne "$pool";
562 $data->{statistics
} = $d->{stats
};
565 my $apps = $rados->mon_command({ prefix
=> "osd pool application get", pool
=> "$pool", });
566 $data->{application_list
} = [ keys %$apps ];