package PVE::API2::Ceph::MDS; use strict; use warnings; use PVE::Ceph::Tools; use PVE::Ceph::Services; use PVE::Cluster qw(cfs_read_file cfs_write_file); use PVE::INotify; use PVE::JSONSchema qw(get_standard_option); use PVE::RADOS; use PVE::RESTHandler; use PVE::RPCEnvironment; use base qw(PVE::RESTHandler); __PACKAGE__->register_method ({ name => 'index', path => '', method => 'GET', description => "MDS directory index.", permissions => { check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1], }, proxyto => 'node', protected => 1, parameters => { additionalProperties => 0, properties => { node => get_standard_option('pve-node'), }, }, returns => { type => 'array', items => { type => "object", properties => { name => { description => "The name (ID) for the MDS", }, addr => { type => 'string', optional => 1, }, host => { type => 'string', optional => 1, }, state => { type => 'string', description => 'State of the MDS', }, standby_replay => { type => 'boolean', optional => 1, description => 'If true, the standby MDS is polling the active MDS for faster recovery (hot standby).', }, rank => { type => 'integer', optional => 1, }, }, }, links => [ { rel => 'child', href => "{name}" } ], }, code => sub { my ($param) = @_; PVE::Ceph::Tools::check_ceph_inited(); my $res = []; my $cfg = cfs_read_file('ceph.conf'); my $rados = PVE::RADOS->new(); my $mds_hash = PVE::Ceph::Services::get_services_info("mds", $cfg, $rados); my $mds_state = PVE::Ceph::Services::get_cluster_mds_state($rados); foreach my $name (keys %$mds_state) { my $d = $mds_state->{$name}; # just overwrite, this always provides more info $mds_hash->{$name}->{$_} = $d->{$_} for keys %$d; } return PVE::RESTHandler::hash_to_array($mds_hash, 'name'); } }); __PACKAGE__->register_method ({ name => 'createmds', path => '{name}', method => 'POST', description => "Create Ceph Metadata Server (MDS)", proxyto => 'node', protected => 1, permissions => { check => ['perm', '/', [ 'Sys.Modify' ]], }, parameters => { additionalProperties => 0, properties => { node => get_standard_option('pve-node'), name => { type => 'string', optional => 1, default => 'nodename', pattern => PVE::Ceph::Services::SERVICE_REGEX, maxLength => 200, description => "The ID for the mds, when omitted the same as the nodename", }, hotstandby => { type => 'boolean', optional => 1, default => '0', description => "Determines whether a ceph-mds daemon should poll and replay the log of an active MDS. ". "Faster switch on MDS failure, but needs more idle resources.", }, }, }, returns => { type => 'string' }, code => sub { my ($param) = @_; PVE::Ceph::Tools::check_ceph_installed('ceph_mds'); PVE::Ceph::Tools::check_ceph_inited(); my $rpcenv = PVE::RPCEnvironment::get(); my $authuser = $rpcenv->get_user(); my $nodename = $param->{node}; $nodename = INotify::nodename() if $nodename eq 'localhost'; my $mds_id = $param->{name} // $nodename; my $worker = sub { my $timeout = PVE::Ceph::Tools::get_config('long_rados_timeout'); my $rados = PVE::RADOS->new(timeout => $timeout); my $cfg = cfs_read_file('ceph.conf'); my $section = "mds.$mds_id"; if (defined($cfg->{$section})) { die "MDS '$mds_id' already referenced in ceph config, abort!\n" } if (!defined($cfg->{mds}->{keyring})) { # $id isn't a perl variable but a ceph metavariable my $keyring = '/var/lib/ceph/mds/ceph-$id/keyring'; $cfg->{mds}->{keyring} = $keyring; } $cfg->{$section}->{host} = $nodename; $cfg->{$section}->{"mds standby for name"} = 'pve'; if ($param->{hotstandby}) { $cfg->{$section}->{"mds standby replay"} = 'true'; } cfs_write_file('ceph.conf', $cfg); eval { PVE::Ceph::Services::create_mds($mds_id, $rados) }; if (my $err = $@) { # we abort early if the section is defined, so we know that we # wrote it at this point. Do not auto remove the service, could # do real harm for previously manual setup MDS warn "Encountered error, remove '$section' from ceph.conf\n"; my $cfg = cfs_read_file('ceph.conf'); delete $cfg->{$section}; cfs_write_file('ceph.conf', $cfg); die "$err\n"; } }; return $rpcenv->fork_worker('cephcreatemds', "mds.$mds_id", $authuser, $worker); } }); __PACKAGE__->register_method ({ name => 'destroymds', path => '{name}', method => 'DELETE', description => "Destroy Ceph Metadata Server", proxyto => 'node', protected => 1, permissions => { check => ['perm', '/', [ 'Sys.Modify' ]], }, parameters => { additionalProperties => 0, properties => { node => get_standard_option('pve-node'), name => { description => 'The name (ID) of the mds', type => 'string', pattern => PVE::Ceph::Services::SERVICE_REGEX, }, }, }, returns => { type => 'string' }, code => sub { my ($param) = @_; my $rpcenv = PVE::RPCEnvironment::get(); my $authuser = $rpcenv->get_user(); PVE::Ceph::Tools::check_ceph_inited(); my $mds_id = $param->{name}; my $worker = sub { my $timeout = PVE::Ceph::Tools::get_config('long_rados_timeout'); my $rados = PVE::RADOS->new(timeout => $timeout); my $cfg = cfs_read_file('ceph.conf'); if (defined($cfg->{"mds.$mds_id"})) { delete $cfg->{"mds.$mds_id"}; cfs_write_file('ceph.conf', $cfg); } PVE::Ceph::Services::destroy_mds($mds_id, $rados); }; return $rpcenv->fork_worker('cephdestroymds', "mds.$mds_id", $authuser, $worker); } }); 1;