From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: 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 346B779234 for ; Fri, 1 Jul 2022 16:16:45 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 2B0C6A68F for ; Fri, 1 Jul 2022 16:16:45 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (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 firstgate.proxmox.com (Proxmox) with ESMTPS for ; Fri, 1 Jul 2022 16:16:43 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 985B643DB6 for ; Fri, 1 Jul 2022 16:16:43 +0200 (CEST) From: Aaron Lauterer To: pve-devel@lists.proxmox.com Date: Fri, 1 Jul 2022 16:16:40 +0200 Message-Id: <20220701141642.2743824-4-a.lauterer@proxmox.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220701141642.2743824-1-a.lauterer@proxmox.com> References: <20220701141642.2743824-1-a.lauterer@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.018 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% 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 T_SCC_BODY_TEXT_LINE -0.01 - Subject: [pve-devel] [PATCH manager 3/5] api ceph osd: add volume details endpoint 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: , X-List-Received-Date: Fri, 01 Jul 2022 14:16:45 -0000 This endpoint returns the following infos for an volume: * creation time * lv name * lv path * lv size * lv uuid * vg name Possible volumes are: * block (default value if not provided) * db * wal 'ceph-volume' is used to gather the infos, except for the creation time of the LV which is retrieved via 'lvs'. Signed-off-by: Aaron Lauterer --- While Ceph itself does not store any information about the creation time of an OSD, I think we can get close to it by using the information stored in the LVs. PVE/API2/Ceph/OSD.pm | 109 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/PVE/API2/Ceph/OSD.pm b/PVE/API2/Ceph/OSD.pm index 078a8c81..c9ec3222 100644 --- a/PVE/API2/Ceph/OSD.pm +++ b/PVE/API2/Ceph/OSD.pm @@ -5,6 +5,7 @@ use warnings; use Cwd qw(abs_path); use IO::File; +use JSON; use UUID; use PVE::Ceph::Tools; @@ -697,6 +698,114 @@ __PACKAGE__->register_method ({ return $data; }}); +__PACKAGE__->register_method ({ + name => 'osdvolume', + path => '{osdid}/volume', + method => 'GET', + description => "Get OSD volume details", + proxyto => 'node', + protected => 1, + permissions => { + check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1], + }, + parameters => { + additionalProperties => 0, + properties => { + node => get_standard_option('pve-node'), + osdid => { + description => 'OSD ID', + type => 'integer', + }, + type => { + description => 'OSD device type', + type => 'string', + enum => ['block', 'db', 'wal'], + default => 'block', + optional => 1, + }, + }, + }, + returns => { + type => 'object', + properties => { + creation_time => { + type => 'string', + description => "Creation time as reported by 'lvs'.", + }, + lv_name => { + type => 'string', + description => 'Name of the logical volume (LV).', + }, + lv_path => { + type => 'string', + description => 'Path to the logical volume (LV).', + }, + lv_size => { + type => 'integer', + description => 'Size of the logical volume (LV).', + }, + lv_uuid => { + type => 'string', + description => 'UUID of the logical volume (LV).', + }, + vg_name => { + type => 'string', + description => 'Name of the volume group (VG).', + }, + }, + }, + code => sub { + my ($param) = @_; + + PVE::Ceph::Tools::check_ceph_inited(); + + my $osdid = $param->{osdid}; + my $type = $param->{type} // 'block'; + + my $raw = ''; + my $parser = sub { $raw .= shift }; + my $cmd = ['/usr/sbin/ceph-volume', 'lvm', 'list', '--format', 'json']; + eval { run_command($cmd, errmsg => 'ceph volume error', outfunc => $parser) }; + die $@ if $@; + + my $result; + if ($raw =~ m/^(\{.*\})$/s) { #untaint + $result = JSON::decode_json($1); + } else { + die "got unexpected data from ceph-volume: '${raw}'\n"; + } + die "OSD '${osdid}' not found in 'ceph-volume lvm list' on node '${nodename}'\n" + if !$result->{$osdid}; + + my $volume_data = {}; + %{$volume_data} = map { $_->{type} => $_ } @{$result->{$osdid}}; + die "volume type '${type}' not found for OSD ${osdid}\n" if !$volume_data->{$type}; + + my $volume = $volume_data->{$type}; + + $raw = ''; + $cmd = ['/sbin/lvs', $volume->{lv_path}, '--reportformat', 'json', '-o', 'lv_time']; + eval { run_command($cmd, errmsg => 'lvs error', outfunc => $parser) }; + die $@ if $@; + + if ($raw =~ m/(\{.*\})$/s) { #untaint, lvs has whitespace at beginning + $result = JSON::decode_json($1); + } else { + die "got unexpected data from lvs: '${raw}'\n"; + } + my $data = {}; + + my $keys = [ 'lv_name', 'lv_path', 'lv_uuid', 'vg_name' ]; + for my $key (@$keys) { + $data->{$key} = $volume->{$key}; + } + $data->{lv_size} = int($volume->{lv_size}); + + $data->{creation_time} = @{$result->{report}}[0]->{lv}[0]->{lv_time}; + + return $data; + }}); + # Check if $osdid belongs to $nodename # $tree ... rados osd tree (passing the tree makes it easy to test) sub osd_belongs_to_node { -- 2.30.2