From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <root@dev.dominic.proxmox.com>
Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68])
 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
 key-exchange X25519 server-signature RSA-PSS (2048 bits))
 (No client certificate requested)
 by lists.proxmox.com (Postfix) with ESMTPS id 6AB4566FC6
 for <pve-devel@lists.proxmox.com>; Mon, 11 Jan 2021 12:43:03 +0100 (CET)
Received: from firstgate.proxmox.com (localhost [127.0.0.1])
 by firstgate.proxmox.com (Proxmox) with ESMTP id 5CE4919D41
 for <pve-devel@lists.proxmox.com>; Mon, 11 Jan 2021 12:43:03 +0100 (CET)
Received: from dev.dominic.proxmox.com (212-186-127-178.static.upcbusiness.at
 [212.186.127.178])
 by firstgate.proxmox.com (Proxmox) with ESMTP id D7A1B19D37
 for <pve-devel@lists.proxmox.com>; Mon, 11 Jan 2021 12:43:02 +0100 (CET)
Received: by dev.dominic.proxmox.com (Postfix, from userid 0)
 id ABAEA21608; Mon, 11 Jan 2021 12:43:02 +0100 (CET)
From: =?UTF-8?q?Dominic=20J=C3=A4ger?= <d.jaeger@proxmox.com>
To: pve-devel@lists.proxmox.com
Date: Mon, 11 Jan 2021 12:42:58 +0100
Message-Id: <20210111114259.121999-1-d.jaeger@proxmox.com>
X-Mailer: git-send-email 2.20.1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-SPAM-LEVEL: Spam detection results:  1
 AWL -0.376 Adjusted score from AWL reputation of From: address
 KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment
 KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery
 methods
 KHOP_HELO_FCRDNS        0.398 Relay HELO differs from its IP's reverse DNS
 NO_DNS_FOR_FROM         0.379 Envelope sender has no MX or A DNS records
 SPF_HELO_NONE           0.001 SPF: HELO does not publish an SPF Record
 SPF_NONE                0.001 SPF: sender does not publish an SPF Record
Subject: [pve-devel] [PATCH manager 1/2] Fix #2053: OSD destroy only on
 specified node
X-BeenThere: pve-devel@lists.proxmox.com
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: Proxmox VE development discussion <pve-devel.lists.proxmox.com>
List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pve-devel>, 
 <mailto:pve-devel-request@lists.proxmox.com?subject=unsubscribe>
List-Archive: <http://lists.proxmox.com/pipermail/pve-devel/>
List-Post: <mailto:pve-devel@lists.proxmox.com>
List-Help: <mailto:pve-devel-request@lists.proxmox.com?subject=help>
List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel>, 
 <mailto:pve-devel-request@lists.proxmox.com?subject=subscribe>
X-List-Received-Date: Mon, 11 Jan 2021 11:43:03 -0000

Allow destroying only OSDs that belong to the node that has been specified in
the API path.

So if
 - OSD 1 belongs to node A and
 - OSD 2 belongs to node B
then
 - pvesh delete nodes/A/ceph/osd/1 is allowed but
 - pvesh delete nodes/A/ceph/osd/2 is not

Destroying an OSD via GUI automatically inserts the correct node
into the API path.

pveceph automatically insert the local node into the API call, too.
Consequently, it can now only destroy local OSDs (fix #2053).
 - pveceph osd destroy 1 is allowed on node A but
 - pveceph osd destroy 2 is not

Signed-off-by: Dominic Jäger <d.jaeger@proxmox.com>
---
 PVE/API2/Ceph/OSD.pm | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/PVE/API2/Ceph/OSD.pm b/PVE/API2/Ceph/OSD.pm
index b81a8054..6763e95b 100644
--- a/PVE/API2/Ceph/OSD.pm
+++ b/PVE/API2/Ceph/OSD.pm
@@ -478,6 +478,22 @@ __PACKAGE__->register_method ({
 	return $rpcenv->fork_worker('cephcreateosd', $devname,  $authuser, $worker);
     }});
 
+# Check if $osdid belongs to $nodename
+# $tree ... rados osd tree (passing the tree makes it easy to test)
+sub osd_belongs_to_node {
+    my ($tree, $nodename, $osdid) = @_;
+
+    die "No tree nodes found\n" if !($tree && $tree->{nodes});
+    my $allNodes = $tree->{nodes};
+
+    my @match = grep($_->{name} eq $nodename, @$allNodes);
+    my $node = shift @match; # contains rados information about $nodename
+    die "There must not be more than one such node in the list" if @match;
+
+    my $osds = $node->{children};
+    return grep($_ == $osdid, @$osds);
+}
+
 __PACKAGE__->register_method ({
     name => 'destroyosd',
     path => '{osdid}',
@@ -515,6 +531,15 @@ __PACKAGE__->register_method ({
 	my $cleanup = $param->{cleanup};
 
 	my $rados = PVE::RADOS->new();
+
+	my $osd_belongs_to_node = osd_belongs_to_node(
+	    $rados->mon_command({ prefix => 'osd tree' }),
+	    $param->{node},
+	    $osdid,
+	);
+	die "OSD osd.$osdid does not belong to node $param->{node}!"
+	    if !$osd_belongs_to_node;
+
 	# dies if osdid is unknown
 	my $osdstat = $get_osd_status->($rados, $osdid);
 
-- 
2.20.1