From: Friedrich Weber <f.weber@proxmox.com>
To: pve-devel@lists.proxmox.com, Aaron Lauterer <a.lauterer@proxmox.com>
Subject: Re: [pve-devel] [PATCH manager v2 1/6] api: ceph: add rbd namespace management endpoints
Date: Wed, 2 Apr 2025 16:14:43 +0200 [thread overview]
Message-ID: <85eeb1e7-2e78-46a4-81ed-c3ab5f850a36@proxmox.com> (raw)
In-Reply-To: <20241223160008.218710-2-a.lauterer@proxmox.com>
Hi, I have some minor comments inline:
On 23/12/2024 17:00, Aaron Lauterer wrote:
> RBD supports namespaces. To make the management easier and possible via
> the web UI, we need to add API endpoints to:
> * list
> * create
> * delete
> namespaces.
>
> We only allow creatng namespaces for pools that have the RBD application
> set.
>
> Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
> ---
> changes since v1:
> * integrated recommendations:
> * code style in many places
> * added check on removal if a storage config that uses the namespace
> exists. I can be overriden with the new optional force flag
> * on create we trim the namespace parameter and check if it has any
> length. Is there an option in the API that would do that for us
> already?
> * added TODO note as we might want to rethink the ACL privileges
>
> PVE/API2/Ceph/Pool.pm | 205 +++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 203 insertions(+), 2 deletions(-)
>
> diff --git a/PVE/API2/Ceph/Pool.pm b/PVE/API2/Ceph/Pool.pm
> index 5ee982f4..94121dea 100644
> --- a/PVE/API2/Ceph/Pool.pm
> +++ b/PVE/API2/Ceph/Pool.pm
> @@ -3,6 +3,8 @@ package PVE::API2::Ceph::Pool;
> use strict;
> use warnings;
>
> +use JSON qw(decode_json);
> +
> use PVE::Ceph::Tools;
> use PVE::Ceph::Services;
> use PVE::JSONSchema qw(get_standard_option parse_property_string);
> @@ -10,7 +12,7 @@ use PVE::RADOS;
> use PVE::RESTHandler;
> use PVE::RPCEnvironment;
> use PVE::Storage;
> -use PVE::Tools qw(extract_param);
> +use PVE::Tools qw(extract_param run_command);
>
> use PVE::API2::Storage::Config;
>
> @@ -32,6 +34,7 @@ my $get_autoscale_status = sub {
> return $data;
> };
>
> +# TODO: think about adding dedicated Ceph ACL privileges as the currently used ones don't match well
>
> __PACKAGE__->register_method ({
> name => 'lspools',
> @@ -302,7 +305,7 @@ my $ceph_pool_common_options = sub {
>
>
> my $add_storage = sub {
> - my ($pool, $storeid, $ec_data_pool) = @_;
> + my ($pool, $storeid, $ec_data_pool, $namespace) = @_;
>
> my $storage_params = {
> type => 'rbd',
> @@ -312,6 +315,8 @@ my $add_storage = sub {
> content => 'rootdir,images',
> };
>
> + $storage_params->{namespace} = $namespace if $namespace;
> +
> $storage_params->{'data-pool'} = $ec_data_pool if $ec_data_pool;
>
> PVE::API2::Storage::Config->create($storage_params);
> @@ -798,4 +803,200 @@ __PACKAGE__->register_method ({
> }});
>
>
> +my $get_rbd_namespaces = sub {
> + my ($pool) = @_;
> +
> + my $raw = '';
> + run_command(
> + ['/usr/bin/rbd', 'namespace', 'list', $pool, '--format', 'json'],
> + outfunc => sub { $raw .= shift },
> + errmsg => "rbd error",
> + errfunc => sub {},
> + );
> + return [] if $raw eq '[]';
> +
> + my ($untainted_raw) = $raw =~ /^(.+)$/; # untaint
> + my $namespaces = eval { decode_json($untainted_raw) };
> + die "failed to parse as JSON - $@\n" if $@;
> +
> + return [
> + map { { name => $_->{name} } } $namespaces->@*
> + ];
> +};
> +
> +__PACKAGE__->register_method ({
> + name => 'listnamespaces',
> + path => '{name}/namespace',
> + method => 'GET',
> + permissions => {
> + check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1],
> + },
> + description => "Get pool RBD namespaces.",
> + proxyto => 'node',
> + protected => 1,
> + parameters => {
> + additionalProperties => 0,
> + properties => {
> + node => get_standard_option('pve-node'),
> + name => {
> + description => 'The name of the pool.',
> + type => 'string',
> + default => 'rbd',
I was a bit confused about this default -- seeing that {name} is part of
the path, is there a situation where we can fallback to 'rbd'?
> + },
> + },
> + },
> + returns => {
> + type => 'array',
> + items => {
> + type => 'object',
> + properties => {
> + name => { type => 'string', title => "Namespace" }
> + },
> + },
> + },
> + code => sub {
> + my ($param) = @_;
> +
> + my $pool = extract_param($param, 'name') // 'rbd';
Do we need this fallback?
> + return $get_rbd_namespaces->($pool);
> + }});
> +
> +
> +__PACKAGE__->register_method ({
> + name => 'createnamespace',
> + path => '{name}/namespace',
> + method => 'POST',
> + permissions => {
> + check => ['perm', '/', [ 'Sys.Modify' ]],
> + },
> + description => "Create new RBD namespace.",
> + proxyto => 'node',
> + protected => 1,
> + parameters => {
> + additionalProperties => 0,
> + properties => {
> + node => get_standard_option('pve-node'),
> + name => {
> + description => 'The name of the pool.',
> + type => 'string',
> + default => 'rbd',
same as above
> + },
> + namespace => {
> + description => 'The name of the new namespace',
> + type => 'string',
> + },
> + 'add-storage' => {
> + description => "Configure VM and CT storage using the new namespace.",
> + type => 'boolean',
> + optional => 1,
> + default => "0",
> + },
> + },
> + },
> + returns => { type => 'string' },
> + code => sub {
> + my ($param) = @_;
> +
> + my $pool = extract_param($param, 'name') // 'rbd';
same as above
> + my $namespace = PVE::Tools::trim(extract_param($param, 'namespace'));
> + my $add_storages = extract_param($param, 'add-storage');
> +
> + die "namespace cannot be empty" if length($namespace) < 1; # in case it was just whitespace
missing a \n at the end
> +
> + my $rpcenv = PVE::RPCEnvironment::get();
> + my $user = $rpcenv->get_user();
> + if ($add_storages) {
> + $rpcenv->check($user, '/storage', ['Datastore.Allocate']);
> + die "namespace name contains characters which are illegal for storage naming\n"
> + if !PVE::JSONSchema::parse_storage_id("${pool}-${namespace}");
> + }
> +
> + my $rados = PVE::RADOS->new();
> + my $apps = $rados->mon_command({ prefix => "osd pool application get", pool => "$pool", });
> + die "the pool does not have application 'rbd' enabled" if !defined($apps->{rbd});
missing a \n at the end
> +
> + my $current_namespaces = { map { $_->{name} => 1 } $get_rbd_namespaces->($pool)->@*};
> + die "namespace already exists" if $current_namespaces->{$namespace};
missing a \n at the end
> +
> + my $worker = sub {
> + run_command(
> + ['/usr/bin/rbd', 'namespace', 'create', "${pool}/${namespace}"],
> + errmsg => "rbd create namespace error",
> + errfunc => sub {},
> + outfunc => sub {},
> + );
> + if ($add_storages) {
> + eval { $add_storage->($pool, "${pool}-${namespace}", 0, $namespace) };
> + die "adding PVE storage for ceph rbd namespace failed: pool: ${pool}, namespace: ${namespace}: $@\n" if $@;
> + }
> + };
> +
> + return $rpcenv->fork_worker('cephcreaterbdnamespace', $pool, $user, $worker);
> + }});
> +
> +
> +__PACKAGE__->register_method ({
> + name => 'destroynamespace',
> + path => '{name}/namespace',
> + method => 'DELETE',
> + permissions => {
> + check => ['perm', '/', [ 'Sys.Modify' ]],
> + },
> + description => "Delete RBD namespace.",
> + proxyto => 'node',
> + protected => 1,
> + parameters => {
> + additionalProperties => 0,
> + properties => {
> + node => get_standard_option('pve-node'),
> + name => {
> + description => 'The name of the pool.',
> + type => 'string',
> + default => 'rbd',
> + },
> + namespace => {
> + description => 'The name of the namespace',
> + type => 'string',
> + },
> + force => {
> + description => 'Force removal of the namespace',
> + type => 'boolean',
> + optional => 1,
> + },
> + },
> + },
> + returns => { type => 'string' },
> + code => sub {
> + my ($param) = @_;
> +
> + my $pool = extract_param($param, 'name') // 'rbd';
> + my $namespace = extract_param($param, 'namespace');
> + my $force = extract_param($param, 'force');
> +
> + if (!$force) {
> + my $storages = $get_storages->($pool);
> + for my $storage (keys $storages->%*) {
> + if (
> + defined($storages->{$storage}->{namespace})
> + && $storages->{$storage}->{namespace} eq $namespace
> + ) {
> + die "namespace '${namespace}' is configured in storage '${storage}', remove it first";
missing a \n at the end
> + }
> + }
> + }
> +
> + my $rpcenv = PVE::RPCEnvironment::get();
> + my $user = $rpcenv->get_user();
> + my $worker = sub {
> + run_command(
> + ['/usr/bin/rbd', 'namespace', 'remove', "${pool}/${namespace}"],
> + errmsg => "rbd create namespace error",
*remove
> + errfunc => sub {},
> + outfunc => sub {},
> + );
> + };
> +
> + return $rpcenv->fork_worker('cephdestroyrbdnamespace', $pool, $user, $worker);
> + }});
> +
> 1;
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
next prev parent reply other threads:[~2025-04-02 14:14 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-12-23 16:00 [pve-devel] [PATCH manager, docs v2 0/6] Ceph: add RBD Namespace management Aaron Lauterer
2024-12-23 16:00 ` [pve-devel] [PATCH manager v2 1/6] api: ceph: add rbd namespace management endpoints Aaron Lauterer
2025-04-02 14:14 ` Friedrich Weber [this message]
2024-12-23 16:00 ` [pve-devel] [PATCH manager v2 2/6] pveceph: add pool namespace subcommands Aaron Lauterer
2024-12-23 16:00 ` [pve-devel] [PATCH manager v2 3/6] ui: ceph pool: add rbd namespace panel Aaron Lauterer
2024-12-23 16:00 ` [pve-devel] [PATCH manager v2 4/6] ui: utils: add ceph rbd namespace task names Aaron Lauterer
2024-12-23 16:00 ` [pve-devel] [PATCH manager v2 5/6] ui: storage rbd: remove hint for manual rbd namespace creation Aaron Lauterer
2024-12-23 16:00 ` [pve-devel] [PATCH docs v2 6/6] pveceph: add section for rbd namespaces Aaron Lauterer
2025-01-02 13:46 ` Alexander Zeidler
2025-01-10 14:26 ` Aaron Lauterer
2025-04-02 14:14 ` [pve-devel] [PATCH manager, docs v2 0/6] Ceph: add RBD Namespace management Friedrich Weber
2025-04-04 14:54 ` Aaron Lauterer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=85eeb1e7-2e78-46a4-81ed-c3ab5f850a36@proxmox.com \
--to=f.weber@proxmox.com \
--cc=a.lauterer@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.