public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pve-devel] [PATCH manager, docs 0/7] Ceph: add RBD Namespace management
@ 2024-12-06 13:55 Aaron Lauterer
  2024-12-06 13:55 ` [pve-devel] [PATCH manager 1/7] ui: ceph pool: add columns for application Aaron Lauterer
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: Aaron Lauterer @ 2024-12-06 13:55 UTC (permalink / raw)
  To: pve-devel

The first patch in this series is not related, but adds a new column to
the ceph pool panel to also display the application data of the pool.

The rest of the series adds the necessary API endpoints and GUI to
manage RBD namespaces in a HCI cluster. The Ceph Pool panel in the UI
needed a bit more work to fit in a new grid for the namespaces. More in
the actual patch (4/7).

Additional future work can be made, for example to add a new scan option
for the RBD storage backend that scans for namespaces. But that only has
a tangential relationship to this series.

manager: Aaron Lauterer (6):
  ui: ceph pool: add columns for application
  api: ceph: add rbd namespace management endpoints
  pveceph: add pool namespace subcommands
  ui: ceph pool: add rbd namespace panel
  ui: utils: add ceph rbd namespace task names
  ui: storage rbd: remove hint for manual rbd namespace creation

 PVE/API2/Ceph/Pool.pm           | 182 ++++++++++++++++++++++++-
 PVE/CLI/pveceph.pm              |   9 ++
 www/manager6/Utils.js           |   2 +
 www/manager6/ceph/Pool.js       | 230 +++++++++++++++++++++++++++++++-
 www/manager6/node/Config.js     |   3 +-
 www/manager6/storage/RBDEdit.js |  21 ---
 6 files changed, 422 insertions(+), 25 deletions(-)

docs: Aaron Lauterer (1):
  pveceph: add section for rbd namespaces

 pveceph.adoc | 41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

-- 
2.39.5



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


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pve-devel] [PATCH manager 1/7] ui: ceph pool: add columns for application
  2024-12-06 13:55 [pve-devel] [PATCH manager, docs 0/7] Ceph: add RBD Namespace management Aaron Lauterer
@ 2024-12-06 13:55 ` Aaron Lauterer
  2024-12-10 18:56   ` [pve-devel] applied: " Thomas Lamprecht
  2024-12-06 13:55 ` [pve-devel] [PATCH manager 2/7] api: ceph: add rbd namespace management endpoints Aaron Lauterer
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 10+ messages in thread
From: Aaron Lauterer @ 2024-12-06 13:55 UTC (permalink / raw)
  To: pve-devel

Since we already have the information from the API call, why not add it
as a (hidden) column. It can be useful to quickly see which ceph
applications are enabled for a pool in some situations.

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
---
as mentioned in the cover letter, this patch has nothing directly to do
with the series, but since I rely on the application info of the pool to
enable/disable the namespace grid, why not make it possible to see that
info of the pools as well in the pool grid if wanted.

 www/manager6/ceph/Pool.js | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/www/manager6/ceph/Pool.js b/www/manager6/ceph/Pool.js
index 16479fee..9346c939 100644
--- a/www/manager6/ceph/Pool.js
+++ b/www/manager6/ceph/Pool.js
@@ -307,6 +307,14 @@ Ext.define('PVE.node.Ceph.PoolList', {
 	    dataIndex: 'type',
 	    hidden: true,
 	},
+	{
+	    text: gettext('Application'),
+	    minWidth: 100,
+	    flex: 1,
+	    dataIndex: 'application_metadata',
+	    hidden: true,
+	    renderer: (v, _meta, _rec) => Object.keys(v).toString(),
+	},
 	{
 	    text: gettext('Size') + '/min',
 	    minWidth: 100,
-- 
2.39.5



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


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pve-devel] [PATCH manager 2/7] api: ceph: add rbd namespace management endpoints
  2024-12-06 13:55 [pve-devel] [PATCH manager, docs 0/7] Ceph: add RBD Namespace management Aaron Lauterer
  2024-12-06 13:55 ` [pve-devel] [PATCH manager 1/7] ui: ceph pool: add columns for application Aaron Lauterer
@ 2024-12-06 13:55 ` Aaron Lauterer
  2024-12-10 18:52   ` Thomas Lamprecht
  2024-12-06 13:55 ` [pve-devel] [PATCH manager 3/7] pveceph: add pool namespace subcommands Aaron Lauterer
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 10+ messages in thread
From: Aaron Lauterer @ 2024-12-06 13:55 UTC (permalink / raw)
  To: 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 <a.lauterer@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


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pve-devel] [PATCH manager 3/7] pveceph: add pool namespace subcommands
  2024-12-06 13:55 [pve-devel] [PATCH manager, docs 0/7] Ceph: add RBD Namespace management Aaron Lauterer
  2024-12-06 13:55 ` [pve-devel] [PATCH manager 1/7] ui: ceph pool: add columns for application Aaron Lauterer
  2024-12-06 13:55 ` [pve-devel] [PATCH manager 2/7] api: ceph: add rbd namespace management endpoints Aaron Lauterer
@ 2024-12-06 13:55 ` Aaron Lauterer
  2024-12-06 13:55 ` [pve-devel] [PATCH manager 4/7] ui: ceph pool: add rbd namespace panel Aaron Lauterer
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Aaron Lauterer @ 2024-12-06 13:55 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
---
 PVE/CLI/pveceph.pm | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/PVE/CLI/pveceph.pm b/PVE/CLI/pveceph.pm
index 488aea04..3a2bb890 100755
--- a/PVE/CLI/pveceph.pm
+++ b/PVE/CLI/pveceph.pm
@@ -482,6 +482,15 @@ our $cmddef = {
 	    my ($data, $schema, $options) = @_;
 	    PVE::CLIFormatter::print_api_result($data, $schema, undef, $options);
 	}, $PVE::RESTHandler::standard_output_options],
+	namespace => {
+	    ls => [ 'PVE::API2::Ceph::Pool', 'listnamespaces', ['name'], { node => $nodename}, sub {
+		my ($data, $schema, $options) = @_;
+		PVE::CLIFormatter::print_api_result($data, $schema, undef, $options);
+	    }, $PVE::RESTHandler::standard_output_options],
+	    list => { alias => 'namespace ls' },
+	    create => [ 'PVE::API2::Ceph::Pool', 'createnamespace', ['name', 'namespace', 'add-storage'], { node => $nodename}],
+	    destroy => [ 'PVE::API2::Ceph::Pool', 'destroynamespace', ['name', 'namespace'], { node => $nodename }],
+	},
     },
     lspools => { alias => 'pool ls' },
     createpool => { alias => 'pool create' },
-- 
2.39.5



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


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pve-devel] [PATCH manager 4/7] ui: ceph pool: add rbd namespace panel
  2024-12-06 13:55 [pve-devel] [PATCH manager, docs 0/7] Ceph: add RBD Namespace management Aaron Lauterer
                   ` (2 preceding siblings ...)
  2024-12-06 13:55 ` [pve-devel] [PATCH manager 3/7] pveceph: add pool namespace subcommands Aaron Lauterer
@ 2024-12-06 13:55 ` Aaron Lauterer
  2024-12-06 13:55 ` [pve-devel] [PATCH manager 5/7] ui: utils: add ceph rbd namespace task names Aaron Lauterer
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Aaron Lauterer @ 2024-12-06 13:55 UTC (permalink / raw)
  To: pve-devel

This needs a bit of a rework of the Ceph Pool panel because we want to
have it right next/below to the pool grid. Additionally we want to
en-/disable it if the select pool has RBD as application enabled.

Therefore we introduce a new small panel (Ceph.PoolView) that holds the
pool and namespace grid. By passing a reference of the namespace grid
into the pool grid, we can control the namespace grid directly from the
pool grid.

This also means that we need to redirect the submenu in Config.js to use
the new intermediate Ceph.PoolView panel instead of the pool grid
directly.

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
---
the overall idea on how to handle the relationship between the two grid
panels was taken from the vnet firewall panel.

 www/manager6/ceph/Pool.js   | 222 +++++++++++++++++++++++++++++++++++-
 www/manager6/node/Config.js |   3 +-
 2 files changed, 223 insertions(+), 2 deletions(-)

diff --git a/www/manager6/ceph/Pool.js b/www/manager6/ceph/Pool.js
index 9346c939..a4ae4c71 100644
--- a/www/manager6/ceph/Pool.js
+++ b/www/manager6/ceph/Pool.js
@@ -1,3 +1,38 @@
+Ext.define('PVE.node.Ceph.PoolView', {
+    extend: 'Ext.panel.Panel',
+    alias: 'widget.pveNodeCephPoolView',
+
+    onlineHelp: 'pve_ceph_pools',
+    scrollable: 'y',
+
+    initComponent: function() {
+	let me = this;
+
+	let RbdNamespacePanel = Ext.createWidget('pveNodeCephRbdNamespacelist', {
+	    region: 'south',
+	    height: '50%',
+	    border: false,
+	    disabled: true,
+	    xtype: 'pveNodeCephRbdNamespacelist',
+	    nodename: me.nodename,
+	});
+	let poolPanel = Ext.createWidget('pveNodeCephPoolList', {
+	    region: 'center',
+	    border: 'false',
+	    xtype: 'pveNodeCephPoolList',
+	    nodename: me.nodename,
+	    RbdNamespacePanel,
+	});
+
+	Ext.apply(me, {
+	    layout: 'border',
+	    items: [poolPanel, RbdNamespacePanel],
+	});
+
+	me.callParent();
+    },
+});
+
 Ext.define('PVE.CephPoolInputPanel', {
     extend: 'Proxmox.panel.InputPanel',
     xtype: 'pveCephPoolInputPanel',
@@ -278,9 +313,12 @@ Ext.define('PVE.node.Ceph.PoolList', {
 
     onlineHelp: 'chapter_pveceph',
 
+    title: gettext('Ceph Pools'),
+
     stateful: true,
     stateId: 'grid-ceph-pools',
     bufferedRenderer: false,
+    RbdNamespacePanel: undefined,
 
     features: [{ ftype: 'summary' }],
 
@@ -411,11 +449,12 @@ Ext.define('PVE.node.Ceph.PoolList', {
     initComponent: function() {
         var me = this;
 
-	var nodename = me.pveSelNode.data.node;
+	var nodename = me.nodename;
 	if (!nodename) {
 	    throw "no node name specified";
 	}
 
+
 	var sm = Ext.create('Ext.selection.RowModel', {});
 
 	var rstore = Ext.create('Proxmox.data.UpdateStore', {
@@ -449,6 +488,25 @@ Ext.define('PVE.node.Ceph.PoolList', {
 	    });
 	};
 
+	let item_selected = function(record, item, index) {
+	    if ('rbd' in item.data.application_metadata) {
+		let poolname = item.id;
+
+		me.RbdNamespacePanel.poolname = poolname;
+		let ns_store = me.RbdNamespacePanel.getStore();
+		ns_store.setData([]);
+		ns_store.setProxy({
+		    type: 'proxmox',
+		    url: `/api2/json/nodes/${nodename}/ceph/pool/${poolname}/namespace`,
+		});
+		ns_store.load();
+		me.RbdNamespacePanel.setDisabled(false);
+	    } else {
+		me.RbdNamespacePanel.getStore().setData([]);
+		me.RbdNamespacePanel.setDisabled(true);
+	    }
+	};
+
 	Ext.apply(me, {
 	    store: store,
 	    selModel: sm,
@@ -532,10 +590,12 @@ Ext.define('PVE.node.Ceph.PoolList', {
 		activate: () => rstore.startUpdate(),
 		destroy: () => rstore.stopUpdate(),
 		itemdblclick: run_editor,
+		select: item_selected,
 	    },
 	});
 
 	me.callParent();
+	me.store.rstore.load();
     },
 }, function() {
     Ext.define('ceph-pool-list', {
@@ -605,3 +665,163 @@ Ext.define('PVE.form.CephRuleSelector', {
     },
 
 });
+
+
+Ext.define('PVE.node.Ceph.RbdNamespaceList', {
+    extend: 'Ext.grid.GridPanel',
+    alias: 'widget.pveNodeCephRbdNamespacelist',
+
+    onlineHelp: 'chapter_pveceph',
+
+    title: gettext('RBD Namespaces'),
+
+    emptyText: gettext('No RBD namespace configured'),
+
+    stateful: true,
+    stateId: 'grid-ceph-rbd-namespaces',
+    bufferedRenderer: false,
+
+    poolname: undefined,
+    viewConfig: {
+	enableTextSelection: true,
+    },
+
+    columns: [
+	{
+	    text: gettext('Namespace'),
+	    minWidth: 120,
+	    flex: 2,
+	    sortable: true,
+	    dataIndex: 'name',
+	},
+    ],
+    initComponent: function() {
+        var me = this;
+
+	var nodename = me.nodename;
+	if (!nodename) {
+	    throw "no node name specified";
+	}
+
+
+	var sm = Ext.create('Ext.selection.RowModel', {});
+
+	var rstore = Ext.create('Proxmox.data.UpdateStore', {
+	    interval: 3000,
+	    storeid: 'ceph-rbd-namespace-list' + nodename,
+	    model: 'ceph-rbd-namespace-list',
+	    proxy: {
+		type: 'proxmox',
+		url: `/api2/json/nodes/${nodename}/ceph/pool/rbd/namespace`,
+	    },
+	});
+	let store = Ext.create('Proxmox.data.DiffStore', { rstore: rstore });
+
+	// manages the "install ceph?" overlay
+	PVE.Utils.monitor_ceph_installed(me, rstore, nodename);
+
+	var run_editor = function() {
+	    let rec = sm.getSelection()[0];
+	    if (!rec || !rec.data.pool_name) {
+		return;
+	    }
+	    Ext.create('PVE.Ceph.PoolEdit', {
+		title: gettext('Edit') + ': Ceph Pool',
+		nodename: nodename,
+		pool_name: rec.data.pool_name,
+		isErasure: rec.data.type === 'erasure',
+		autoShow: true,
+		listeners: {
+		    destroy: () => rstore.load(),
+		},
+	    });
+	};
+
+	Ext.apply(me, {
+	    store: store,
+	    selModel: sm,
+	    tbar: [
+		{
+		    text: gettext('Create'),
+		    handler: function() {
+			Ext.create('Proxmox.window.Edit', {
+			    title: gettext('Create') + ': Ceph RBD Namespace',
+			    isCreate: true,
+			    nodename: nodename,
+			    url: `/nodes/${nodename}/ceph/pool/${me.poolname}/namespace`,
+			    method: 'POST',
+			    autoShow: true,
+			    listeners: {
+				destroy: () => rstore.load(),
+			    },
+			    items: [
+				{
+				    xtype: 'textfield',
+				    fieldLabel: gettext('Namespace'),
+				    name: 'namespace',
+				    emptyText: gettext('Namespace'),
+				},
+				{
+				    xtype: 'proxmoxcheckbox',
+				    fieldLabel: gettext('Add as Storage'),
+				    value: true,
+				    name: 'add-storage',
+				    autoEl: {
+					tag: 'div',
+					 'data-qtip': gettext('Add the new RBD namespace to the cluster storage configuration.'),
+				    },
+				},
+			    ],
+			});
+		    },
+		},
+		{
+		    xtype: 'proxmoxButton',
+		    text: gettext('Destroy'),
+		    selModel: sm,
+		    disabled: true,
+		    handler: function() {
+			let rec = sm.getSelection()[0];
+			if (!rec || !rec.data.name) {
+			    return;
+			}
+			let poolName = me.poolname;
+			let namespace = rec.data.name;
+			Ext.create('Proxmox.window.SafeDestroy', {
+			    showProgress: true,
+			    url: `/nodes/${nodename}/ceph/pool/${poolName}/namespace`,
+			    params: {
+				namespace: namespace,
+			    },
+			    item: {
+				type: 'RbdNamespace',
+				id: namespace,
+			    },
+			    taskName: 'cephdestroyrbdnamespace',
+			    autoShow: true,
+			    listeners: {
+				destroy: () => rstore.load(),
+			    },
+			});
+		    },
+		},
+	    ],
+	    listeners: {
+		activate: () => rstore.startUpdate(),
+		destroy: () => rstore.stopUpdate(),
+		itemdblclick: run_editor,
+	    },
+	});
+
+	me.callParent();
+    },
+}, function() {
+    Ext.define('ceph-rbd-namespace-list', {
+	extend: 'Ext.data.Model',
+	fields: ['name',
+		  { name: 'name', type: 'string' },
+		],
+	idProperty: 'name',
+    });
+});
+
diff --git a/www/manager6/node/Config.js b/www/manager6/node/Config.js
index f4d3ff8a..db9368ad 100644
--- a/www/manager6/node/Config.js
+++ b/www/manager6/node/Config.js
@@ -391,10 +391,11 @@ Ext.define('PVE.node.Config', {
 		    itemId: 'ceph-cephfspanel',
 		},
 		{
-		    xtype: 'pveNodeCephPoolList',
+		    xtype: 'pveNodeCephPoolView',
 		    title: gettext('Pools'),
 		    iconCls: 'fa fa-sitemap',
 		    groups: ['ceph'],
+		    nodename: nodename,
 		    itemId: 'ceph-pools',
 		},
 		{
-- 
2.39.5



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


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pve-devel] [PATCH manager 5/7] ui: utils: add ceph rbd namespace task names
  2024-12-06 13:55 [pve-devel] [PATCH manager, docs 0/7] Ceph: add RBD Namespace management Aaron Lauterer
                   ` (3 preceding siblings ...)
  2024-12-06 13:55 ` [pve-devel] [PATCH manager 4/7] ui: ceph pool: add rbd namespace panel Aaron Lauterer
@ 2024-12-06 13:55 ` Aaron Lauterer
  2024-12-06 13:55 ` [pve-devel] [PATCH manager 6/7] ui: storage rbd: remove hint for manual rbd namespace creation Aaron Lauterer
  2024-12-06 13:55 ` [pve-devel] [PATCH docs 7/7] pveceph: add section for rbd namespaces Aaron Lauterer
  6 siblings, 0 replies; 10+ messages in thread
From: Aaron Lauterer @ 2024-12-06 13:55 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
---
 www/manager6/Utils.js | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/www/manager6/Utils.js b/www/manager6/Utils.js
index 97dbbae2..d3b978e8 100644
--- a/www/manager6/Utils.js
+++ b/www/manager6/Utils.js
@@ -1993,11 +1993,13 @@ Ext.define('PVE.Utils', {
 	    cephcreatemon: ['Ceph Monitor', gettext('Create')],
 	    cephcreateosd: ['Ceph OSD', gettext('Create')],
 	    cephcreatepool: ['Ceph Pool', gettext('Create')],
+	    cephcreaterbdnamespace: ['Ceph RBD Namespace', gettext('Create')],
 	    cephdestroymds: ['Ceph Metadata Server', gettext('Destroy')],
 	    cephdestroymgr: ['Ceph Manager', gettext('Destroy')],
 	    cephdestroymon: ['Ceph Monitor', gettext('Destroy')],
 	    cephdestroyosd: ['Ceph OSD', gettext('Destroy')],
 	    cephdestroypool: ['Ceph Pool', gettext('Destroy')],
+	    cephdestroyrbdnamespace: ['Ceph RBD Namespace', gettext('Destroy')],
 	    cephdestroyfs: ['CephFS', gettext('Destroy')],
 	    cephfscreate: ['CephFS', gettext('Create')],
 	    cephsetpool: ['Ceph Pool', gettext('Edit')],
-- 
2.39.5



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


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pve-devel] [PATCH manager 6/7] ui: storage rbd: remove hint for manual rbd namespace creation
  2024-12-06 13:55 [pve-devel] [PATCH manager, docs 0/7] Ceph: add RBD Namespace management Aaron Lauterer
                   ` (4 preceding siblings ...)
  2024-12-06 13:55 ` [pve-devel] [PATCH manager 5/7] ui: utils: add ceph rbd namespace task names Aaron Lauterer
@ 2024-12-06 13:55 ` Aaron Lauterer
  2024-12-06 13:55 ` [pve-devel] [PATCH docs 7/7] pveceph: add section for rbd namespaces Aaron Lauterer
  6 siblings, 0 replies; 10+ messages in thread
From: Aaron Lauterer @ 2024-12-06 13:55 UTC (permalink / raw)
  To: pve-devel

they can now be created with proxmox ve tooling directly

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
---
 www/manager6/storage/RBDEdit.js | 21 ---------------------
 1 file changed, 21 deletions(-)

diff --git a/www/manager6/storage/RBDEdit.js b/www/manager6/storage/RBDEdit.js
index 15fc1304..e41da1e1 100644
--- a/www/manager6/storage/RBDEdit.js
+++ b/www/manager6/storage/RBDEdit.js
@@ -5,7 +5,6 @@ Ext.define('PVE.storage.Ceph.Model', {
     data: {
 	pveceph: true,
 	pvecephPossible: true,
-	namespacePresent: false,
     },
 });
 
@@ -27,16 +26,10 @@ Ext.define('PVE.storage.Ceph.Controller', {
 	    disable: 'resetField',
 	    enable: 'resetField',
 	},
-	'textfield[name=namespace]': {
-	    change: 'updateNamespaceHint',
-	},
     },
     resetField: function(field) {
 	field.reset();
     },
-    updateNamespaceHint: function(field, newVal, oldVal) {
-	this.getViewModel().set('namespacePresent', newVal);
-    },
     queryMonitors: function(field, newVal, oldVal) {
 	// we get called with two signatures, the above one for a field
 	// change event and the afterrender from the view, this check only
@@ -95,9 +88,6 @@ Ext.define('PVE.storage.RBDInputPanel', {
 	    this.lookupReference('pvecephRef').setValue(false);
 	    this.lookupReference('pvecephRef').resetOriginalValue();
 	}
-	if (values.namespace) {
-	    this.getViewModel().set('namespacePresent', true);
-	}
 	this.callParent([values]);
     },
 
@@ -238,17 +228,6 @@ Ext.define('PVE.storage.RBDInputPanel', {
 		allowBlank: true,
 	    },
 	];
-	me.advancedColumn2 = [
-	    {
-		xtype: 'displayfield',
-		name: 'namespace-hint',
-		userCls: 'pmx-hint',
-		value: gettext('RBD namespaces must be created manually!'),
-		bind: {
-		    hidden: '{!namespacePresent}',
-		},
-	    },
-	];
 
 	me.callParent();
     },
-- 
2.39.5



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


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pve-devel] [PATCH docs 7/7] pveceph: add section for rbd namespaces
  2024-12-06 13:55 [pve-devel] [PATCH manager, docs 0/7] Ceph: add RBD Namespace management Aaron Lauterer
                   ` (5 preceding siblings ...)
  2024-12-06 13:55 ` [pve-devel] [PATCH manager 6/7] ui: storage rbd: remove hint for manual rbd namespace creation Aaron Lauterer
@ 2024-12-06 13:55 ` Aaron Lauterer
  6 siblings, 0 replies; 10+ messages in thread
From: Aaron Lauterer @ 2024-12-06 13:55 UTC (permalink / raw)
  To: pve-devel

and a few basic examples on how to manage them.

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
---
 pveceph.adoc | 41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/pveceph.adoc b/pveceph.adoc
index da39e7f..a90a6e1 100644
--- a/pveceph.adoc
+++ b/pveceph.adoc
@@ -760,6 +760,47 @@ You can find a more in-depth introduction to the PG autoscaler on Ceph's Blog -
 https://ceph.io/rados/new-in-nautilus-pg-merging-and-autotuning/[New in
 Nautilus: PG merging and autotuning].
 
+[[pve_ceph_rbd_namespaces]]
+RBD Namespaces
+~~~~~~~~~~~~~~
+
+Namespaces in the rados block device (RBD) layer can be used to have multiple
+Proxmox VE clusters using the same pool, but still be logically separated.
+Namespaces can be managed in the web UI in the 'Node -> Ceph -> Pools' panel.
+
+Alternatively, the `pveceph` or Ceph's `rbd` footnote:[https://docs.ceph.com/en/latest/man/8/rbd/]
+utility can be used too. To list all RBD namespaces of the pool `vmstore`, run the
+following command:
+[source, bash]
+----
+pveceph pool namespace ls vmstore
+----
+The result will be for example:
+[source, bash]
+----
+┌───────────┐
+│ Namespace │
+╞═══════════╡
+│ bar       │
+├───────────┤
+│ foo       │
+└───────────┘
+----
+
+To create a new RBD namespace `baz` in the pool `vmstore`, run:
+[source, bash]
+----
+pveceph pool namespace create vmstore baz --add-storage 1
+----
+The `--add-storage` parameter is optional an when set, will create a new
+storage configuration with the new namespace.
+
+To delete the `baz` RBD namespace in pool `vmstore`:
+[source, bash]
+----
+pveceph pool namespace destroy vmstore baz
+----
+
 
 [[pve_ceph_device_classes]]
 Ceph CRUSH & device classes
-- 
2.39.5



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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [pve-devel] [PATCH manager 2/7] api: ceph: add rbd namespace management endpoints
  2024-12-06 13:55 ` [pve-devel] [PATCH manager 2/7] api: ceph: add rbd namespace management endpoints Aaron Lauterer
@ 2024-12-10 18:52   ` Thomas Lamprecht
  0 siblings, 0 replies; 10+ messages in thread
From: Thomas Lamprecht @ 2024-12-10 18:52 UTC (permalink / raw)
  To: Proxmox VE development discussion, Aaron Lauterer

Am 06.12.24 um 14:55 schrieb Aaron Lauterer:
> 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>
> ---
>  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;

The JSON module exports quite a few methods by default, so I'd prefer importing
the few required manually, e.g. here:

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;
>  
> @@ -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);

style nit: I'd avoid the intermediate variables, they do not gain much on
readability or the like here IMO, so maybe do something like:

run_command(
    ['/usr/bin/rbd', 'namespace', 'list', $pool, '--format', 'json'],
    outfunc => sub { $raw .= shift },
    errmsg => "rbd error",
    errfunc => sub {},
);


> +    return [] if $raw eq '[]';
> +
> +    my $decoded;
> +    if ($raw =~ m/^(\[\{.*\}\])$/s) { #untaint

tiny nit: missing whitespace in comment

Besides that, feels a bit rigid, as any whitespace separator between the braces would
cause a false positive here. Maybe do a very generous /(.+)/ untaint and instead wrap
the decode_json inside an eval and throw a telling error there? E.g.:

my ($untainted_raw) = $raw =~ /^(.+)$/;

my $namespaces = eval { decode_json($untainted_raw) };
die "failed to parse as JSON - $@\n" if $@;

> +	$decoded = JSON::decode_json($1);

It would be great if decode_json acts as untaint, but one can only wish.

> +    } else {
> +	die "got unexpected data from rbd namespace list: '${raw}'\n";
> +    }
> +
> +    my $result = [];
> +    for my $val (@$decoded) {
> +	    push @$result, { name => $val->{name} };
> +    }

FWIW, could be shortened using map [0]:

return [
    map { { name => $val->{name} } } $namespaces->@*
];

That is normally a bit faster too, but won't matter here, so no hard feelings from
my side.

[0]: https://perldoc.perl.org/functions/map

> +    return $result;
> +};
> +
> +__PACKAGE__->register_method ({
> +    name => 'listnamespaces',
> +    path => '{name}/namespace',
> +    method => 'GET',
> +    permissions => {
> +	check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1],

Hmm, do we already use Datastore.Audit for similar things? As feels a bit odd,
the pool just because a pool is often a PVE storage I'd still see this as system
information. If we already use this check for similar things I'm fine to keep this
consistent, otherwise I'd maybe use only Sys.Audit here, we can still open this up
in the future if it's really a problem.

> +    },
> +    description => "Get pool RBD namespace index.",

this isn't a index in the sense of that there are further API leaf nodes below it,
so maybe just "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',
> +	    },
> +	},
> +    },
> +    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');

This now allows anyone with Sys.Modify to create a datastore, but we should check for
Datastore.Allocate, just like the create pool API endpoint does.

Similarly, we should ensure that the resulting storage name, i.e. something like:

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}");
}

> +
> +	die "specify namespace" if !$namespace;

Is this for an empty string being passed, tbh. I do not know from top of my head.

> +
> +	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 };

Above $raw and $parser are unused here.

> +	    run_command($cmd, errmsg => "rbd create namespace error", errfunc => sub {}, outfunc => $parser);

Might be nicer to read to have the $cmd inlined here in terms of code locality.

> +	    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;

If required you could do 

my $namespace = extract_param($param, 'namespace') or die "...";

But if one cannot already pass an empty string that might not be required.

But w.r.t. error checking: might be good to test if the namespace is in use in any
PVE storage? As in that case, it would be probably better to require that storage
entry being deleted first.

> +
> +	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 };

Above $raw and $parser are unused here.

> +	    run_command($cmd, errmsg => "rbd create namespace error", errfunc => sub {}, outfunc => $parser);

Same w.r.t. inlining $cmd.

> +	};
> +
> +	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


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pve-devel] applied: [PATCH manager 1/7] ui: ceph pool: add columns for application
  2024-12-06 13:55 ` [pve-devel] [PATCH manager 1/7] ui: ceph pool: add columns for application Aaron Lauterer
@ 2024-12-10 18:56   ` Thomas Lamprecht
  0 siblings, 0 replies; 10+ messages in thread
From: Thomas Lamprecht @ 2024-12-10 18:56 UTC (permalink / raw)
  To: Proxmox VE development discussion, Aaron Lauterer

Am 06.12.24 um 14:55 schrieb Aaron Lauterer:
> Since we already have the information from the API call, why not add it
> as a (hidden) column. It can be useful to quickly see which ceph
> applications are enabled for a pool in some situations.
> 
> Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
> ---
> as mentioned in the cover letter, this patch has nothing directly to do
> with the series, but since I rely on the application info of the pool to
> enable/disable the namespace grid, why not make it possible to see that
> info of the pools as well in the pool grid if wanted.
> 
>  www/manager6/ceph/Pool.js | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
>

As it's hidden by default I do not have hard feelings w.r.t. how it's displayed
for now, so applied, thanks!


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


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2024-12-10 18:57 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-12-06 13:55 [pve-devel] [PATCH manager, docs 0/7] Ceph: add RBD Namespace management Aaron Lauterer
2024-12-06 13:55 ` [pve-devel] [PATCH manager 1/7] ui: ceph pool: add columns for application Aaron Lauterer
2024-12-10 18:56   ` [pve-devel] applied: " Thomas Lamprecht
2024-12-06 13:55 ` [pve-devel] [PATCH manager 2/7] api: ceph: add rbd namespace management endpoints Aaron Lauterer
2024-12-10 18:52   ` Thomas Lamprecht
2024-12-06 13:55 ` [pve-devel] [PATCH manager 3/7] pveceph: add pool namespace subcommands Aaron Lauterer
2024-12-06 13:55 ` [pve-devel] [PATCH manager 4/7] ui: ceph pool: add rbd namespace panel Aaron Lauterer
2024-12-06 13:55 ` [pve-devel] [PATCH manager 5/7] ui: utils: add ceph rbd namespace task names Aaron Lauterer
2024-12-06 13:55 ` [pve-devel] [PATCH manager 6/7] ui: storage rbd: remove hint for manual rbd namespace creation Aaron Lauterer
2024-12-06 13:55 ` [pve-devel] [PATCH docs 7/7] pveceph: add section for rbd namespaces Aaron Lauterer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal