From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id C99921FF164 for ; Fri, 6 Dec 2024 14:55:24 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 8F18572EA; Fri, 6 Dec 2024 14:55:18 +0100 (CET) From: Aaron Lauterer To: pve-devel@lists.proxmox.com Date: Fri, 6 Dec 2024 14:55:09 +0100 Message-Id: <20241206135514.170226-3-a.lauterer@proxmox.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20241206135514.170226-1-a.lauterer@proxmox.com> References: <20241206135514.170226-1-a.lauterer@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL -0.034 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pve-devel] [PATCH manager 2/7] api: ceph: add rbd namespace management endpoints X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox VE development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pve-devel-bounces@lists.proxmox.com Sender: "pve-devel" 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 --- 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