mirror of
https://git.proxmox.com/git/pve-manager
synced 2025-05-05 07:06:01 +00:00

It's a bit more commonly used for such identifier Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
516 lines
12 KiB
Perl
516 lines
12 KiB
Perl
package PVE::API2::Cluster::Ceph;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use JSON;
|
|
|
|
use PVE::Ceph::Services;
|
|
use PVE::Ceph::Tools;
|
|
use PVE::Cluster;
|
|
use PVE::Exception qw(raise_param_exc);
|
|
use PVE::JSONSchema qw(get_standard_option);
|
|
use PVE::RADOS;
|
|
use PVE::RESTHandler;
|
|
use PVE::SafeSyslog;
|
|
use PVE::Tools qw(extract_param);
|
|
|
|
use base qw(PVE::RESTHandler);
|
|
|
|
__PACKAGE__->register_method ({
|
|
name => 'cephindex',
|
|
path => '',
|
|
method => 'GET',
|
|
description => "Cluster ceph index.",
|
|
permissions => { user => 'all' },
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {},
|
|
},
|
|
returns => {
|
|
type => 'array',
|
|
items => {
|
|
type => "object",
|
|
properties => {},
|
|
},
|
|
links => [ { rel => 'child', href => "{name}" } ],
|
|
},
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
my $result = [
|
|
{ name => 'metadata' },
|
|
{ name => 'status' },
|
|
{ name => 'flags' },
|
|
];
|
|
|
|
return $result;
|
|
}
|
|
});
|
|
|
|
my $metadata_common_props = {
|
|
hostname => {
|
|
type => "string",
|
|
description => "Hostname on which the service is running.",
|
|
},
|
|
ceph_release => {
|
|
type => "string",
|
|
description => "Ceph release codename currently used.",
|
|
},
|
|
ceph_version => {
|
|
type => "string",
|
|
description => "Version info currently used by the service.",
|
|
},
|
|
ceph_version_short => {
|
|
type => "string",
|
|
description => "Short version (numerical) info currently used by the service.",
|
|
},
|
|
mem_total_kb => {
|
|
type => "integer",
|
|
description => "Memory consumption of the service.",
|
|
},
|
|
mem_swap_kb => {
|
|
type => "integer",
|
|
description => "Memory of the service currently in swap.",
|
|
},
|
|
};
|
|
|
|
__PACKAGE__->register_method ({
|
|
name => 'metadata',
|
|
path => 'metadata',
|
|
method => 'GET',
|
|
description => "Get ceph metadata.",
|
|
protected => 1,
|
|
permissions => {
|
|
check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1],
|
|
},
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
scope => {
|
|
type => 'string',
|
|
optional => 1,
|
|
default => 'all',
|
|
enum => ['all', 'versions', ],
|
|
},
|
|
},
|
|
},
|
|
returns => {
|
|
type => 'object',
|
|
description => "Items for each type of service containing objects for each instance.",
|
|
properties => {
|
|
mds => {
|
|
type => "object",
|
|
description => "Metadata servers configured in the cluster and their properties.",
|
|
properties => {
|
|
"{id}" => {
|
|
type => "object",
|
|
description => "Useful properties are listed, but not the full list.",
|
|
properties => {
|
|
addr => {
|
|
type => "string",
|
|
description => "Bind addresses and ports.",
|
|
},
|
|
name => {
|
|
type => "string",
|
|
description => "Name of the service instance.",
|
|
},
|
|
%{$metadata_common_props},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
mgr => {
|
|
type => "object",
|
|
description => "Managers configured in the cluster and their properties.",
|
|
properties => {
|
|
"{id}" => {
|
|
type => "object",
|
|
description => "Useful properties are listed, but not the full list.",
|
|
properties => {
|
|
addr => {
|
|
type => "string",
|
|
description => "Bind address",
|
|
},
|
|
name => {
|
|
type => "string",
|
|
description => "Name of the service instance.",
|
|
},
|
|
%{$metadata_common_props},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
mon => {
|
|
type => "object",
|
|
description => "Monitors configured in the cluster and their properties.",
|
|
properties => {
|
|
"{id}" => {
|
|
type => "object",
|
|
description => "Useful properties are listed, but not the full list.",
|
|
properties => {
|
|
addrs => {
|
|
type => "string",
|
|
description => "Bind addresses and ports.",
|
|
},
|
|
name => {
|
|
type => "string",
|
|
description => "Name of the service instance.",
|
|
},
|
|
%{$metadata_common_props},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
node => {
|
|
type => "object",
|
|
description => "Ceph version installed on the nodes.",
|
|
properties => {
|
|
"{node}" => {
|
|
type => "object",
|
|
properties => {
|
|
buildcommit => {
|
|
type => "string",
|
|
description => "GIT commit used for the build.",
|
|
},
|
|
version => {
|
|
type => "object",
|
|
description => "Version info.",
|
|
properties => {
|
|
str => {
|
|
type => "string",
|
|
description => "Version as single string.",
|
|
},
|
|
parts => {
|
|
type => "array",
|
|
description => "major, minor & patch",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
osd => {
|
|
type => "array",
|
|
description => "OSDs configured in the cluster and their properties.",
|
|
properties => {
|
|
"{id}" => {
|
|
type => "object",
|
|
description => "Useful properties are listed, but not the full list.",
|
|
properties => {
|
|
id => {
|
|
type => "integer",
|
|
description => "OSD ID.",
|
|
},
|
|
front_addr => {
|
|
type => "string",
|
|
description => "Bind addresses and ports for frontend traffic to OSDs.",
|
|
},
|
|
back_addr => {
|
|
type => "string",
|
|
description => "Bind addresses and ports for backend inter OSD traffic.",
|
|
},
|
|
device_id => {
|
|
type => "string",
|
|
description => "Devices used by the OSD.",
|
|
},
|
|
osd_data => {
|
|
type => "string",
|
|
description => "Path to the OSD data directory.",
|
|
},
|
|
osd_objectstore => {
|
|
type => "string",
|
|
description => "OSD objectstore type.",
|
|
},
|
|
%{$metadata_common_props},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
my $scope = $param->{scope} // 'all';
|
|
|
|
my $res = {};
|
|
|
|
if (defined(my $versions = PVE::Ceph::Services::get_ceph_versions())) {
|
|
$res->{node} = $versions;
|
|
}
|
|
|
|
return $res if ($scope eq 'versions');
|
|
|
|
# only check now, we want to allow calls with scope 'versions' on non-ceph nodes too!
|
|
PVE::Ceph::Tools::check_ceph_inited();
|
|
my $rados = PVE::RADOS->new();
|
|
|
|
for my $type ( qw(mon mgr mds) ) {
|
|
my $typedata = PVE::Ceph::Services::get_cluster_service($type);
|
|
my $data = {};
|
|
for my $host (sort keys %$typedata) {
|
|
for my $service (sort keys %{$typedata->{$host}}) {
|
|
$data->{"$service\@$host"} = $typedata->{$host}->{$service};
|
|
}
|
|
}
|
|
|
|
# get data from metadata call and merge 'our' data
|
|
my $services = $rados->mon_command({ prefix => "$type metadata" });
|
|
for my $service ( @$services ) {
|
|
my $hostname = $service->{hostname};
|
|
next if !defined($hostname); # can happen if node is dead
|
|
|
|
my $servicename = $service->{name} // $service->{id};
|
|
my $id = "$servicename\@$hostname";
|
|
|
|
if ($data->{$id}) { # copy values over to the metadata hash
|
|
for my $k (keys %{$data->{$id}}) {
|
|
$service->{$k} = $data->{$id}->{$k};
|
|
}
|
|
}
|
|
$data->{$id} = $service;
|
|
}
|
|
|
|
$res->{$type} = $data;
|
|
}
|
|
|
|
$res->{osd} = $rados->mon_command({ prefix => "osd metadata" });
|
|
|
|
return $res;
|
|
}
|
|
});
|
|
|
|
__PACKAGE__->register_method ({
|
|
name => 'status',
|
|
path => 'status',
|
|
method => 'GET',
|
|
description => "Get ceph status.",
|
|
protected => 1,
|
|
permissions => {
|
|
check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1],
|
|
},
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => { },
|
|
},
|
|
returns => { type => 'object' },
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
PVE::Ceph::Tools::check_ceph_inited();
|
|
|
|
return PVE::Ceph::Tools::ceph_cluster_status();
|
|
}
|
|
});
|
|
|
|
my $possible_flags = PVE::Ceph::Tools::get_possible_osd_flags();
|
|
my $possible_flags_list = [ sort keys %$possible_flags ];
|
|
|
|
my $get_current_set_flags = sub {
|
|
my $rados = shift;
|
|
|
|
$rados //= PVE::RADOS->new();
|
|
|
|
my $stat = $rados->mon_command({ prefix => 'osd dump' });
|
|
my $setflags = $stat->{flags} // '';
|
|
return { map { $_ => 1 } PVE::Tools::split_list($setflags) };
|
|
};
|
|
|
|
__PACKAGE__->register_method ({
|
|
name => 'get_all_flags',
|
|
path => 'flags',
|
|
method => 'GET',
|
|
description => "get the status of all ceph flags",
|
|
protected => 1,
|
|
permissions => {
|
|
check => ['perm', '/', [ 'Sys.Audit' ]],
|
|
},
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
},
|
|
},
|
|
returns => {
|
|
type => 'array',
|
|
items => {
|
|
type => "object",
|
|
additionalProperties => 1,
|
|
properties => {
|
|
name => {
|
|
description => "Flag name.",
|
|
type => 'string', enum => $possible_flags_list,
|
|
},
|
|
description => {
|
|
description => "Flag description.",
|
|
type => 'string',
|
|
},
|
|
value => {
|
|
description => "Flag value.",
|
|
type => 'boolean',
|
|
},
|
|
},
|
|
},
|
|
links => [ { rel => 'child', href => "{name}" } ],
|
|
},
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
PVE::Ceph::Tools::check_ceph_configured();
|
|
|
|
my $setflags = $get_current_set_flags->();
|
|
|
|
my $res = [];
|
|
foreach my $flag (@$possible_flags_list) {
|
|
my $el = {
|
|
name => $flag,
|
|
description => $possible_flags->{$flag}->{description},
|
|
value => 0,
|
|
};
|
|
|
|
my $realflag = PVE::Ceph::Tools::get_real_flag_name($flag);
|
|
if ($setflags->{$realflag}) {
|
|
$el->{value} = 1;
|
|
}
|
|
|
|
push @$res, $el;
|
|
}
|
|
|
|
return $res;
|
|
}
|
|
});
|
|
|
|
__PACKAGE__->register_method ({
|
|
name => 'set_flags',
|
|
path => 'flags',
|
|
method => 'PUT',
|
|
description => "Set/Unset multiple ceph flags at once.",
|
|
protected => 1,
|
|
permissions => {
|
|
check => ['perm', '/', [ 'Sys.Modify' ]],
|
|
},
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => $possible_flags,
|
|
},
|
|
returns => { type => 'string' },
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
my $rpcenv = PVE::RPCEnvironment::get();
|
|
my $user = $rpcenv->get_user();
|
|
PVE::Ceph::Tools::check_ceph_configured();
|
|
|
|
my $worker = sub {
|
|
my $rados = PVE::RADOS->new(); # (re-)open for forked worker
|
|
|
|
my $setflags = $get_current_set_flags->($rados);
|
|
|
|
my $errors = 0;
|
|
foreach my $flag (@$possible_flags_list) {
|
|
next if !defined($param->{$flag});
|
|
my $val = $param->{$flag};
|
|
my $realflag = PVE::Ceph::Tools::get_real_flag_name($flag);
|
|
|
|
next if !$val == !$setflags->{$realflag}; # we do not set/unset flags to the same state
|
|
|
|
my $prefix = $val ? 'set' : 'unset';
|
|
eval {
|
|
print "$prefix $flag\n";
|
|
$rados->mon_command({ prefix => "osd $prefix", key => $flag, });
|
|
};
|
|
if (my $err = $@) {
|
|
warn "error with $flag: '$err'\n";
|
|
$errors++;
|
|
}
|
|
}
|
|
|
|
if ($errors) {
|
|
die "could not set/unset $errors flags\n";
|
|
}
|
|
};
|
|
|
|
return $rpcenv->fork_worker('cephsetflags', undef, $user, $worker);
|
|
}});
|
|
|
|
|
|
__PACKAGE__->register_method ({
|
|
name => 'get_flag',
|
|
path => 'flags/{flag}',
|
|
method => 'GET',
|
|
description => "Get the status of a specific ceph flag.",
|
|
protected => 1,
|
|
permissions => {
|
|
check => ['perm', '/', [ 'Sys.Audit' ]],
|
|
},
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
flag => {
|
|
description => "The name of the flag name to get.",
|
|
type => 'string', enum => $possible_flags_list,
|
|
},
|
|
},
|
|
},
|
|
returns => {
|
|
type => 'boolean',
|
|
},
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
PVE::Ceph::Tools::check_ceph_configured();
|
|
|
|
my $realflag = PVE::Ceph::Tools::get_real_flag_name($param->{flag});
|
|
|
|
my $setflags = $get_current_set_flags->();
|
|
if ($setflags->{$realflag}) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}});
|
|
|
|
__PACKAGE__->register_method ({
|
|
name => 'update_flag',
|
|
path => 'flags/{flag}',
|
|
method => 'PUT',
|
|
description => "Set or clear (unset) a specific ceph flag",
|
|
protected => 1,
|
|
permissions => {
|
|
check => ['perm', '/', [ 'Sys.Modify' ]],
|
|
},
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
flag => {
|
|
description => 'The ceph flag to update',
|
|
type => 'string',
|
|
enum => $possible_flags_list,
|
|
},
|
|
value => {
|
|
description => 'The new value of the flag',
|
|
type => 'boolean',
|
|
},
|
|
},
|
|
},
|
|
returns => { type => 'null' },
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
PVE::Ceph::Tools::check_ceph_configured();
|
|
|
|
my $cmd = $param->{value} ? 'set' : 'unset';
|
|
|
|
my $rados = PVE::RADOS->new();
|
|
$rados->mon_command({
|
|
prefix => "osd $cmd",
|
|
key => $param->{flag},
|
|
});
|
|
|
|
return undef;
|
|
}});
|
|
|
|
|
|
1;
|