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.laute...@proxmox.com>
---
 PVE/API2/Ceph/Pool.pm | 182 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 180 insertions(+), 2 deletions(-)

diff --git a/PVE/API2/Ceph/Pool.pm b/PVE/API2/Ceph/Pool.pm
index 5ee982f4..47194245 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;
+
 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;
 
@@ -302,7 +304,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 +314,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 +802,178 @@ __PACKAGE__->register_method ({
     }});
 
 
+my $get_rbd_namespaces = sub {
+    my ($pool) = @_;
+
+    my $cmd = ['/usr/bin/rbd', 'namespace', 'list', $pool, '--format', 'json'];
+    my $raw = '';
+    my $parser = sub { $raw .= shift };
+    run_command($cmd, errmsg => "rbd error", errfunc => sub {}, outfunc => 
$parser);
+    return [] if $raw eq '[]';
+
+    my $decoded;
+    if ($raw =~ m/^(\[\{.*\}\])$/s) { #untaint
+       $decoded = JSON::decode_json($1);
+    } else {
+       die "got unexpected data from rbd namespace list: '${raw}'\n";
+    }
+
+    my $result = [];
+    for my $val (@$decoded) {
+           push @$result, { name => $val->{name} };
+    }
+    return $result;
+};
+
+__PACKAGE__->register_method ({
+    name => 'listnamespaces',
+    path => '{name}/namespace',
+    method => 'GET',
+    permissions => {
+       check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1],
+    },
+    description => "Get pool RBD namespace index.",
+    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',
+           },
+       },
+    },
+    returns => {
+       type => 'array',
+       items => {
+           type => 'object',
+           properties => {
+               name => { type => 'string', title => "Namespace" }
+           },
+       },
+    },
+    code => sub {
+       my ($param) = @_;
+
+       my $pool = extract_param($param, 'name') // 'rbd';
+       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',
+           },
+           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';
+       my $namespace = extract_param($param, 'namespace');
+       my $add_storages = extract_param($param, 'add-storage');
+
+       die "specify namespace" if !$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});
+
+       my $current_namespaces = { map { $_->{name} => 1 } 
$get_rbd_namespaces->($pool)->@*};
+       die "namespace already exists" if $current_namespaces->{$namespace};
+
+       my $cmd = ['/usr/bin/rbd', 'namespace', 'create', 
"${pool}/${namespace}"];
+
+       my $rpcenv = PVE::RPCEnvironment::get();
+       my $user = $rpcenv->get_user();
+       my $worker = sub {
+           my $raw = '';
+           my $parser = sub { $raw .= shift };
+           run_command($cmd, errmsg => "rbd create namespace error", errfunc 
=> sub {}, outfunc => $parser);
+           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 new namespace',
+               type => 'string',
+           },
+       },
+    },
+    returns => { type => 'string' },
+    code => sub {
+       my ($param) = @_;
+
+       my $pool = extract_param($param, 'name') // 'rbd';
+       my $namespace = extract_param($param, 'namespace');
+
+       die "specify namespace" if !$namespace;
+
+       my $cmd = ['/usr/bin/rbd', 'namespace', 'remove', 
"${pool}/${namespace}"];
+
+       my $rpcenv = PVE::RPCEnvironment::get();
+       my $user = $rpcenv->get_user();
+       my $worker = sub {
+           my $raw = '';
+           my $parser = sub { $raw .= shift };
+           run_command($cmd, errmsg => "rbd create namespace error", errfunc 
=> sub {}, outfunc => $parser);
+       };
+
+       return $rpcenv->fork_worker('cephdestroyrbdnamespace', $pool,  $user, 
$worker);
+    }});
+
 1;
-- 
2.39.5



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to