On December 9, 2022 1:58 pm, Aaron Lauterer wrote: > /nodes/{node}/ceph/pools/{pool} returns the pool details right away on a > GET. This makes it bad practice to add additional sub API endpoints. > > By deprecating it and replacing it with /nodes/{node}/ceph/pool/{pool} > (singular instead of plural) we can turn that into an index GET > response, making it possible to expand it more in the future. > > The GET call returning the pool details is moved into > /nodes/{node}/ceph/pool/{pool}/status > > The code in the new Pool.pm is basically a copy of Pools.pm to avoid > a close coupling with the old code as it is possible that it will divert > until we can entirely remove the old code. > > Signed-off-by: Aaron Lauterer <a.laute...@proxmox.com>
high level: pveceph also should be switched to the new endpoints ;) two small nits inline.. > --- > The next step is to add a pool/{name}/namespace API so that we can list > available namespaces and maybe also manage them via the API/UI in the > future. > > PVE/API2/Ceph.pm | 7 + > PVE/API2/Ceph/Makefile | 1 + > PVE/API2/Ceph/Pool.pm | 801 +++++++++++++++++++++++++++++++++++++++++ > PVE/API2/Ceph/Pools.pm | 11 +- > 4 files changed, 815 insertions(+), 5 deletions(-) > create mode 100644 PVE/API2/Ceph/Pool.pm > > diff --git a/PVE/API2/Ceph.pm b/PVE/API2/Ceph.pm > index f3442408..946aebd3 100644 > --- a/PVE/API2/Ceph.pm > +++ b/PVE/API2/Ceph.pm > @@ -23,6 +23,7 @@ use PVE::API2::Ceph::FS; > use PVE::API2::Ceph::MDS; > use PVE::API2::Ceph::MGR; > use PVE::API2::Ceph::MON; > +use PVE::API2::Ceph::Pool; > use PVE::API2::Ceph::Pools; > use PVE::API2::Storage::Config; > > @@ -55,6 +56,12 @@ __PACKAGE__->register_method ({ > path => 'fs', > }); > > +__PACKAGE__->register_method ({ > + subclass => "PVE::API2::Ceph::Pool", > + path => 'pool', > +}); > + > +# TODO: deprecrated, remove with PVE 8 > __PACKAGE__->register_method ({ > subclass => "PVE::API2::Ceph::Pools", > path => 'pools', > diff --git a/PVE/API2/Ceph/Makefile b/PVE/API2/Ceph/Makefile > index 45daafda..5d6f642b 100644 > --- a/PVE/API2/Ceph/Makefile > +++ b/PVE/API2/Ceph/Makefile > @@ -5,6 +5,7 @@ PERLSOURCE= \ > MON.pm \ > OSD.pm \ > FS.pm \ > + Pool.pm \ > Pools.pm \ > MDS.pm > > diff --git a/PVE/API2/Ceph/Pool.pm b/PVE/API2/Ceph/Pool.pm > new file mode 100644 > index 00000000..cd46311b > --- /dev/null > +++ b/PVE/API2/Ceph/Pool.pm > @@ -0,0 +1,801 @@ > +package PVE::API2::Ceph::Pool; > + > +use strict; > +use warnings; > + > +use PVE::Ceph::Tools; > +use PVE::Ceph::Services; > +use PVE::JSONSchema qw(get_standard_option parse_property_string); > +use PVE::RADOS; > +use PVE::RESTHandler; > +use PVE::RPCEnvironment; > +use PVE::Storage; > +use PVE::Tools qw(extract_param); > + > +use PVE::API2::Storage::Config; > + > +use base qw(PVE::RESTHandler); > + > +my $get_autoscale_status = sub { > + my ($rados) = shift; > + > + $rados = PVE::RADOS->new() if !defined($rados); > + > + my $autoscale = $rados->mon_command({ > + prefix => 'osd pool autoscale-status'}); > + > + my $data; > + foreach my $p (@$autoscale) { > + $data->{$p->{pool_name}} = $p; > + } > + > + return $data; > +}; > + > + > +__PACKAGE__->register_method ({ > + name => 'lspools', > + path => '', > + method => 'GET', > + description => "List all pools.", and their settings (which are settable by the POST/PUT endpoints). > + proxyto => 'node', > + protected => 1, > + permissions => { > + check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1], > + }, > + parameters => { > + additionalProperties => 0, > + properties => { > + node => get_standard_option('pve-node'), > + }, > + }, > + returns => { > + type => 'array', > + items => { > + type => "object", > + properties => { > + pool => { > + type => 'integer', > + title => 'ID', > + }, > + pool_name => { > + type => 'string', > + title => 'Name', > + }, > + size => { > + type => 'integer', > + title => 'Size', > + }, > + type => { > + type => 'string', > + title => 'Type', > + enum => ['replicated', 'erasure', 'unknown'], > + }, > + min_size => { > + type => 'integer', > + title => 'Min Size', > + }, > + pg_num => { > + type => 'integer', > + title => 'PG Num', > + }, > + pg_num_min => { > + type => 'integer', > + title => 'min. PG Num', > + optional => 1, > + }, > + pg_num_final => { > + type => 'integer', > + title => 'Optimal PG Num', > + optional => 1, > + }, > + pg_autoscale_mode => { > + type => 'string', > + title => 'PG Autoscale Mode', > + optional => 1, > + }, > + crush_rule => { > + type => 'integer', > + title => 'Crush Rule', > + }, > + crush_rule_name => { > + type => 'string', > + title => 'Crush Rule Name', > + }, > + percent_used => { > + type => 'number', > + title => '%-Used', > + }, > + bytes_used => { > + type => 'integer', > + title => 'Used', > + }, > + target_size => { > + type => 'integer', > + title => 'PG Autoscale Target Size', > + optional => 1, > + }, > + target_size_ratio => { > + type => 'number', > + title => 'PG Autoscale Target Ratio', > + optional => 1, > + }, > + autoscale_status => { > + type => 'object', > + title => 'Autoscale Status', > + optional => 1, > + }, > + application_metadata => { > + type => 'object', > + title => 'Associated Applications', > + optional => 1, > + }, > + }, > + }, > + links => [ { rel => 'child', href => "{pool_name}" } ], > + }, > + code => sub { > + my ($param) = @_; > + > + PVE::Ceph::Tools::check_ceph_inited(); > + > + my $rados = PVE::RADOS->new(); > + > + my $stats = {}; > + my $res = $rados->mon_command({ prefix => 'df' }); > + > + foreach my $d (@{$res->{pools}}) { > + next if !$d->{stats}; > + next if !defined($d->{id}); > + $stats->{$d->{id}} = $d->{stats}; > + } > + > + $res = $rados->mon_command({ prefix => 'osd dump' }); > + my $rulestmp = $rados->mon_command({ prefix => 'osd crush rule dump'}); > + > + my $rules = {}; > + for my $rule (@$rulestmp) { > + $rules->{$rule->{rule_id}} = $rule->{rule_name}; > + } > + > + my $data = []; > + my $attr_list = [ > + 'pool', > + 'pool_name', > + 'size', > + 'min_size', > + 'pg_num', > + 'crush_rule', > + 'pg_autoscale_mode', > + 'application_metadata', > + ]; > + > + # pg_autoscaler module is not enabled in Nautilus > + my $autoscale = eval { $get_autoscale_status->($rados) }; > + > + foreach my $e (@{$res->{pools}}) { > + my $d = {}; > + foreach my $attr (@$attr_list) { > + $d->{$attr} = $e->{$attr} if defined($e->{$attr}); > + } > + > + if ($autoscale) { > + $d->{autoscale_status} = $autoscale->{$d->{pool_name}}; > + $d->{pg_num_final} = $d->{autoscale_status}->{pg_num_final}; > + # some info is nested under options instead > + $d->{pg_num_min} = $e->{options}->{pg_num_min}; > + $d->{target_size} = $e->{options}->{target_size_bytes}; > + $d->{target_size_ratio} = $e->{options}->{target_size_ratio}; > + } > + > + if (defined($d->{crush_rule}) && > defined($rules->{$d->{crush_rule}})) { > + $d->{crush_rule_name} = $rules->{$d->{crush_rule}}; > + } > + > + if (my $s = $stats->{$d->{pool}}) { > + $d->{bytes_used} = $s->{bytes_used}; > + $d->{percent_used} = $s->{percent_used}; > + } > + > + # Cephs numerical pool types are barely documented. Found the > following in the Ceph > + # codebase: > https://github.com/ceph/ceph/blob/ff144995a849407c258bcb763daa3e03cfce5059/src/osd/osd_types.h#L1221-L1233 > + if ($e->{type} == 1) { > + $d->{type} = 'replicated'; > + } elsif ($e->{type} == 3) { > + $d->{type} = 'erasure'; > + } else { > + # we should never get here, but better be safe > + $d->{type} = 'unknown'; > + } > + push @$data, $d; > + } > + > + > + return $data; > + }}); > + > + > +my $ceph_pool_common_options = sub { > + my ($nodefault) = shift; > + my $options = { > + name => { > + title => 'Name', > + description => "The name of the pool. It must be unique.", > + type => 'string', > + }, > + size => { > + title => 'Size', > + description => 'Number of replicas per object', > + type => 'integer', > + default => 3, > + optional => 1, > + minimum => 1, > + maximum => 7, > + }, > + min_size => { > + title => 'Min Size', > + description => 'Minimum number of replicas per object', > + type => 'integer', > + default => 2, > + optional => 1, > + minimum => 1, > + maximum => 7, > + }, > + pg_num => { > + title => 'PG Num', > + description => "Number of placement groups.", > + type => 'integer', > + default => 128, > + optional => 1, > + minimum => 1, > + maximum => 32768, > + }, > + pg_num_min => { > + title => 'min. PG Num', > + description => "Minimal number of placement groups.", > + type => 'integer', > + optional => 1, > + maximum => 32768, > + }, > + crush_rule => { > + title => 'Crush Rule Name', > + description => "The rule to use for mapping object placement in the > cluster.", > + type => 'string', > + optional => 1, > + }, > + application => { > + title => 'Application', > + description => "The application of the pool.", > + default => 'rbd', > + type => 'string', > + enum => ['rbd', 'cephfs', 'rgw'], > + optional => 1, > + }, > + pg_autoscale_mode => { > + title => 'PG Autoscale Mode', > + description => "The automatic PG scaling mode of the pool.", > + type => 'string', > + enum => ['on', 'off', 'warn'], > + default => 'warn', > + optional => 1, > + }, > + target_size => { > + description => "The estimated target size of the pool for the PG > autoscaler.", > + title => 'PG Autoscale Target Size', > + type => 'string', > + pattern => '^(\d+(\.\d+)?)([KMGT])?$', > + optional => 1, > + }, > + target_size_ratio => { > + description => "The estimated target ratio of the pool for the PG > autoscaler.", > + title => 'PG Autoscale Target Ratio', > + type => 'number', > + optional => 1, > + }, > + }; > + > + if ($nodefault) { > + delete $options->{$_}->{default} for keys %$options; > + } > + return $options; > +}; > + > + > +my $add_storage = sub { > + my ($pool, $storeid, $ec_data_pool) = @_; > + > + my $storage_params = { > + type => 'rbd', > + pool => $pool, > + storage => $storeid, > + krbd => 0, > + content => 'rootdir,images', > + }; > + > + $storage_params->{'data-pool'} = $ec_data_pool if $ec_data_pool; > + > + PVE::API2::Storage::Config->create($storage_params); > +}; > + > +my $get_storages = sub { > + my ($pool) = @_; > + > + my $cfg = PVE::Storage::config(); > + > + my $storages = $cfg->{ids}; > + my $res = {}; > + foreach my $storeid (keys %$storages) { > + my $curr = $storages->{$storeid}; > + next if $curr->{type} ne 'rbd'; > + $curr->{pool} = 'rbd' if !defined $curr->{pool}; # set default > + if ( > + $pool eq $curr->{pool} || > + (defined $curr->{'data-pool'} && $pool eq $curr->{'data-pool'}) > + ) { > + $res->{$storeid} = $storages->{$storeid}; > + } > + } > + > + return $res; > +}; > + > +my $ec_format = { > + k => { > + type => 'integer', > + description => "Number of data chunks. Will create an erasure coded > pool plus a" > + ." replicated pool for metadata.", > + minimum => 2, > + }, > + m => { > + type => 'integer', > + description => "Number of coding chunks. Will create an erasure coded > pool plus a" > + ." replicated pool for metadata.", > + minimum => 1, > + }, > + 'failure-domain' => { > + type => 'string', > + description => "CRUSH failure domain. Default is 'host'. Will create an > erasure" > + ." coded pool plus a replicated pool for metadata.", > + format_description => 'domain', > + optional => 1, > + default => 'host', > + }, > + 'device-class' => { > + type => 'string', > + description => "CRUSH device class. Will create an erasure coded pool > plus a" > + ." replicated pool for metadata.", > + format_description => 'class', > + optional => 1, > + }, > + profile => { > + description => "Override the erasure code (EC) profile to use. Will > create an" > + ." erasure coded pool plus a replicated pool for metadata.", > + type => 'string', > + format_description => 'profile', > + optional => 1, > + }, > +}; > + > +sub ec_parse_and_check { > + my ($property, $rados) = @_; > + return if !$property; > + > + my $ec = parse_property_string($ec_format, $property); > + > + die "Erasure code profile '$ec->{profile}' does not exist.\n" > + if $ec->{profile} && > !PVE::Ceph::Tools::ecprofile_exists($ec->{profile}, $rados); > + > + return $ec; > +} > + > + > +__PACKAGE__->register_method ({ > + name => 'createpool', > + path => '', > + method => 'POST', > + description => "Create Ceph pool", > + proxyto => 'node', > + protected => 1, > + permissions => { > + check => ['perm', '/', [ 'Sys.Modify' ]], > + }, > + parameters => { > + additionalProperties => 0, > + properties => { > + node => get_standard_option('pve-node'), > + add_storages => { > + description => "Configure VM and CT storage using the new > pool.", > + type => 'boolean', > + optional => 1, > + default => "0; for erasure coded pools: 1", > + }, > + 'erasure-coding' => { > + description => "Create an erasure coded pool for RBD with an > accompaning" > + ." replicated pool for metadata storage. With EC, the > common ceph options 'size'," > + ." 'min_size' and 'crush_rule' parameters will be applied > to the metadata pool.", > + type => 'string', > + format => $ec_format, > + optional => 1, > + }, > + %{ $ceph_pool_common_options->() }, > + }, > + }, > + returns => { type => 'string' }, > + code => sub { > + my ($param) = @_; > + > + PVE::Cluster::check_cfs_quorum(); > + PVE::Ceph::Tools::check_ceph_configured(); > + > + my $pool = my $name = extract_param($param, 'name'); > + my $node = extract_param($param, 'node'); > + my $add_storages = extract_param($param, 'add_storages'); > + > + my $rpcenv = PVE::RPCEnvironment::get(); > + my $user = $rpcenv->get_user(); > + # Ceph uses target_size_bytes > + if (defined($param->{'target_size'})) { > + my $target_sizestr = extract_param($param, 'target_size'); > + $param->{target_size_bytes} = > PVE::JSONSchema::parse_size($target_sizestr); > + } > + > + my $rados = PVE::RADOS->new(); > + my $ec = ec_parse_and_check(extract_param($param, 'erasure-coding'), > $rados); > + $add_storages = 1 if $ec && !defined($add_storages); > + > + if ($add_storages) { > + $rpcenv->check($user, '/storage', ['Datastore.Allocate']); > + die "pool name contains characters which are illegal for storage > naming\n" > + if !PVE::JSONSchema::parse_storage_id($pool); > + } > + > + # pool defaults > + $param->{pg_num} //= 128; > + $param->{size} //= 3; > + $param->{min_size} //= 2; > + $param->{application} //= 'rbd'; > + $param->{pg_autoscale_mode} //= 'warn'; > + > + my $worker = sub { > + # reopen with longer timeout > + $rados = PVE::RADOS->new(timeout => > PVE::Ceph::Tools::get_config('long_rados_timeout')); > + > + if ($ec) { > + if (!$ec->{profile}) { > + $ec->{profile} = > PVE::Ceph::Tools::get_ecprofile_name($pool, $rados); > + eval { > + PVE::Ceph::Tools::create_ecprofile( > + $ec->@{'profile', 'k', 'm', 'failure-domain', > 'device-class'}, > + $rados, > + ); > + }; > + die "could not create erasure code profile > '$ec->{profile}': $@\n" if $@; > + print "created new erasure code profile '$ec->{profile}'\n"; > + } > + > + my $ec_data_param = {}; > + # copy all params, should be a flat hash > + $ec_data_param = { map { $_ => $param->{$_} } keys %$param }; > + > + $ec_data_param->{pool_type} = 'erasure'; > + $ec_data_param->{allow_ec_overwrites} = 'true'; > + $ec_data_param->{erasure_code_profile} = $ec->{profile}; > + delete $ec_data_param->{size}; > + delete $ec_data_param->{min_size}; > + delete $ec_data_param->{crush_rule}; > + > + # metadata pool should be ok with 32 PGs > + $param->{pg_num} = 32; > + > + $pool = "${name}-metadata"; > + $ec->{data_pool} = "${name}-data"; > + > + PVE::Ceph::Tools::create_pool($ec->{data_pool}, $ec_data_param, > $rados); > + } > + > + PVE::Ceph::Tools::create_pool($pool, $param, $rados); > + > + if ($add_storages) { > + eval { $add_storage->($pool, "${name}", $ec->{data_pool}) }; > + die "adding PVE storage for ceph pool '$name' failed: $@\n" if > $@; > + } > + }; > + > + return $rpcenv->fork_worker('cephcreatepool', $pool, $user, $worker); > + }}); > + > + > +__PACKAGE__->register_method ({ > + name => 'destroypool', > + path => '{name}', > + method => 'DELETE', > + description => "Destroy pool", > + proxyto => 'node', > + protected => 1, > + permissions => { > + check => ['perm', '/', [ 'Sys.Modify' ]], > + }, > + parameters => { > + additionalProperties => 0, > + properties => { > + node => get_standard_option('pve-node'), > + name => { > + description => "The name of the pool. It must be unique.", > + type => 'string', > + }, > + force => { > + description => "If true, destroys pool even if in use", > + type => 'boolean', > + optional => 1, > + default => 0, > + }, > + remove_storages => { > + description => "Remove all pveceph-managed storages configured > for this pool", > + type => 'boolean', > + optional => 1, > + default => 0, > + }, > + remove_ecprofile => { > + description => "Remove the erasure code profile. Defaults to > true, if applicable.", > + type => 'boolean', > + optional => 1, > + default => 1, > + }, > + }, > + }, > + returns => { type => 'string' }, > + code => sub { > + my ($param) = @_; > + > + PVE::Ceph::Tools::check_ceph_inited(); > + > + my $rpcenv = PVE::RPCEnvironment::get(); > + my $user = $rpcenv->get_user(); > + $rpcenv->check($user, '/storage', ['Datastore.Allocate']) > + if $param->{remove_storages}; > + > + my $pool = $param->{name}; > + > + my $worker = sub { > + my $storages = $get_storages->($pool); > + > + # if not forced, destroy ceph pool only when no > + # vm disks are on it anymore > + if (!$param->{force}) { > + my $storagecfg = PVE::Storage::config(); > + foreach my $storeid (keys %$storages) { > + my $storage = $storages->{$storeid}; > + > + # check if any vm disks are on the pool > + print "checking storage '$storeid' for RBD images..\n"; > + my $res = PVE::Storage::vdisk_list($storagecfg, $storeid); > + die "ceph pool '$pool' still in use by storage '$storeid'\n" > + if @{$res->{$storeid}} != 0; > + } > + } > + my $rados = PVE::RADOS->new(); > + > + my $pool_properties = PVE::Ceph::Tools::get_pool_properties($pool, > $rados); > + > + PVE::Ceph::Tools::destroy_pool($pool, $rados); > + > + if (my $ecprofile = $pool_properties->{erasure_code_profile}) { > + print "found erasure coded profile '$ecprofile', destroying its > CRUSH rule\n"; > + my $crush_rule = $pool_properties->{crush_rule}; > + eval { PVE::Ceph::Tools::destroy_crush_rule($crush_rule, > $rados); }; > + warn "removing crush rule '${crush_rule}' failed: $@\n" if $@; > + > + if ($param->{remove_ecprofile} // 1) { > + print "destroying erasure coded profile '$ecprofile'\n"; > + eval { PVE::Ceph::Tools::destroy_ecprofile($ecprofile, > $rados) }; > + warn "removing EC profile '${ecprofile}' failed: $@\n" if > $@; > + } > + } > + > + if ($param->{remove_storages}) { > + my $err; > + foreach my $storeid (keys %$storages) { > + # skip external clusters, not managed by pveceph > + next if $storages->{$storeid}->{monhost}; > + eval { PVE::API2::Storage::Config->delete({storage => > $storeid}) }; > + if ($@) { > + warn "failed to remove storage '$storeid': $@\n"; > + $err = 1; > + } > + } > + die "failed to remove (some) storages - check log and remove > manually!\n" > + if $err; > + } > + }; > + return $rpcenv->fork_worker('cephdestroypool', $pool, $user, $worker); > + }}); > + > + > +__PACKAGE__->register_method ({ > + name => 'setpool', > + path => '{name}', > + method => 'PUT', > + description => "Change POOL settings", > + proxyto => 'node', > + protected => 1, > + permissions => { > + check => ['perm', '/', [ 'Sys.Modify' ]], > + }, > + parameters => { > + additionalProperties => 0, > + properties => { > + node => get_standard_option('pve-node'), > + %{ $ceph_pool_common_options->('nodefault') }, > + }, > + }, > + returns => { type => 'string' }, > + code => sub { > + my ($param) = @_; > + > + PVE::Ceph::Tools::check_ceph_configured(); > + > + my $rpcenv = PVE::RPCEnvironment::get(); > + my $authuser = $rpcenv->get_user(); > + > + my $pool = extract_param($param, 'name'); > + my $node = extract_param($param, 'node'); > + > + # Ceph uses target_size_bytes > + if (defined($param->{'target_size'})) { > + my $target_sizestr = extract_param($param, 'target_size'); > + $param->{target_size_bytes} = > PVE::JSONSchema::parse_size($target_sizestr); > + } > + > + my $worker = sub { > + PVE::Ceph::Tools::set_pool($pool, $param); > + }; > + > + return $rpcenv->fork_worker('cephsetpool', $pool, $authuser, $worker); > + }}); > + > +__PACKAGE__->register_method ({ > + name => 'poolindex', > + path => '{name}', > + method => 'GET', > + permissions => { > + check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1], > + }, > + description => "Pool index.", > + parameters => { > + additionalProperties => 0, > + properties => { > + node => get_standard_option('pve-node'), > + name => { > + description => 'The name of the pool.', > + type => 'string', > + }, > + }, > + }, > + returns => { > + type => 'array', > + items => { > + type => "object", > + properties => {}, > + }, > + links => [ { rel => 'child', href => "{name}" } ], > + }, > + code => sub { > + my ($param) = @_; > + > + my $result = [ > + { name => 'status' }, > + ]; > + > + return $result; > + }}); > + > + > +__PACKAGE__->register_method ({ > + name => 'getpool', > + path => '{name}/status', > + method => 'GET', > + description => "List pool settings.", whereas this actually returns *much more* than just the settings, and is therefor rightly named "status", so maybe the description should also make that clear ;) > + proxyto => 'node', > + protected => 1, > + permissions => { > + check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1], > + }, > + parameters => { > + additionalProperties => 0, > + properties => { > + node => get_standard_option('pve-node'), > + name => { > + description => "The name of the pool. It must be unique.", > + type => 'string', > + }, > + verbose => { > + type => 'boolean', > + default => 0, > + optional => 1, > + description => "If enabled, will display additional data". > + "(eg. statistics).", > + }, > + }, > + }, > + returns => { > + type => "object", > + properties => { > + id => { type => 'integer', title => 'ID' }, > + pgp_num => { type => 'integer', title => 'PGP num' }, > + noscrub => { type => 'boolean', title => 'noscrub' }, > + 'nodeep-scrub' => { type => 'boolean', title => > 'nodeep-scrub' }, > + nodelete => { type => 'boolean', title => 'nodelete' > }, > + nopgchange => { type => 'boolean', title => > 'nopgchange' }, > + nosizechange => { type => 'boolean', title => > 'nosizechange' }, > + write_fadvise_dontneed => { type => 'boolean', title => > 'write_fadvise_dontneed' }, > + hashpspool => { type => 'boolean', title => > 'hashpspool' }, > + use_gmt_hitset => { type => 'boolean', title => > 'use_gmt_hitset' }, > + fast_read => { type => 'boolean', title => 'Fast Read' > }, > + application_list => { type => 'array', title => > 'Application', optional => 1 }, > + statistics => { type => 'object', title => > 'Statistics', optional => 1 }, > + autoscale_status => { type => 'object', title => 'Autoscale > Status', optional => 1 }, > + %{ $ceph_pool_common_options->() }, > + }, > + }, > + code => sub { > + my ($param) = @_; > + > + PVE::Ceph::Tools::check_ceph_inited(); > + > + my $verbose = $param->{verbose}; > + my $pool = $param->{name}; > + > + my $rados = PVE::RADOS->new(); > + my $res = $rados->mon_command({ > + prefix => 'osd pool get', > + pool => "$pool", > + var => 'all', > + }); > + > + my $data = { > + id => $res->{pool_id}, > + name => $pool, > + size => $res->{size}, > + min_size => $res->{min_size}, > + pg_num => $res->{pg_num}, > + pg_num_min => $res->{pg_num_min}, > + pgp_num => $res->{pgp_num}, > + crush_rule => $res->{crush_rule}, > + pg_autoscale_mode => $res->{pg_autoscale_mode}, > + noscrub => "$res->{noscrub}", > + 'nodeep-scrub' => "$res->{'nodeep-scrub'}", > + nodelete => "$res->{nodelete}", > + nopgchange => "$res->{nopgchange}", > + nosizechange => "$res->{nosizechange}", > + write_fadvise_dontneed => "$res->{write_fadvise_dontneed}", > + hashpspool => "$res->{hashpspool}", > + use_gmt_hitset => "$res->{use_gmt_hitset}", > + fast_read => "$res->{fast_read}", > + target_size => $res->{target_size_bytes}, > + target_size_ratio => $res->{target_size_ratio}, > + }; > + > + if ($verbose) { > + my $stats; > + my $res = $rados->mon_command({ prefix => 'df' }); > + > + # pg_autoscaler module is not enabled in Nautilus > + # avoid partial read further down, use new rados instance > + my $autoscale_status = eval { $get_autoscale_status->() }; > + $data->{autoscale_status} = $autoscale_status->{$pool}; > + > + foreach my $d (@{$res->{pools}}) { > + next if !$d->{stats}; > + next if !defined($d->{name}) && !$d->{name} ne "$pool"; > + $data->{statistics} = $d->{stats}; > + } > + > + my $apps = $rados->mon_command({ prefix => "osd pool application > get", pool => "$pool", }); > + $data->{application_list} = [ keys %$apps ]; > + } > + > + return $data; > + }}); > + > + > +1; > diff --git a/PVE/API2/Ceph/Pools.pm b/PVE/API2/Ceph/Pools.pm > index fce56787..ffae73b9 100644 > --- a/PVE/API2/Ceph/Pools.pm > +++ b/PVE/API2/Ceph/Pools.pm > @@ -1,4 +1,5 @@ > package PVE::API2::Ceph::Pools; > +# TODO: Deprecated, drop with PVE 8.0! PVE::API2::Ceph::Pool is the > replacement > > use strict; > use warnings; > @@ -37,7 +38,7 @@ __PACKAGE__->register_method ({ > name => 'lspools', > path => '', > method => 'GET', > - description => "List all pools.", > + description => "List all pools. Deprecated, please use > `/nodes/{node}/ceph/pool`.", > proxyto => 'node', > protected => 1, > permissions => { > @@ -393,7 +394,7 @@ __PACKAGE__->register_method ({ > name => 'createpool', > path => '', > method => 'POST', > - description => "Create Ceph pool", > + description => "Create Ceph pool. Deprecated, please use > `/nodes/{node}/ceph/pool`.", > proxyto => 'node', > protected => 1, > permissions => { > @@ -509,7 +510,7 @@ __PACKAGE__->register_method ({ > name => 'destroypool', > path => '{name}', > method => 'DELETE', > - description => "Destroy pool", > + description => "Destroy pool. Deprecated, please use > `/nodes/{node}/ceph/pool/{name}`.", > proxyto => 'node', > protected => 1, > permissions => { > @@ -615,7 +616,7 @@ __PACKAGE__->register_method ({ > name => 'setpool', > path => '{name}', > method => 'PUT', > - description => "Change POOL settings", > + description => "Change POOL settings. Deprecated, please use > `/nodes/{node}/ceph/pool/{name}`.", > proxyto => 'node', > protected => 1, > permissions => { > @@ -658,7 +659,7 @@ __PACKAGE__->register_method ({ > name => 'getpool', > path => '{name}', > method => 'GET', > - description => "List pool settings.", > + description => "List pool settings. Deprecated, please use > `/nodes/{node}/ceph/pool/{pool}/status`.", > proxyto => 'node', > protected => 1, > permissions => { > -- > 2.30.2 > > > > _______________________________________________ > pve-devel mailing list > pve-devel@lists.proxmox.com > https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel > > > _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel