#!/usr/bin/perl use strict; use warnings; use List::Util qw(first); use PVE::Ceph::Tools; use PVE::Cluster; use PVE::RADOS; use PVE::RPCEnvironment; my $ceph_cfg_file = 'ceph.conf'; my $keyring_value = '/etc/pve/ceph/$cluster.$name.keyring'; sub try_adapt_cfg { my ($cfg) = @_; my $entity = 'client.crash'; my $removed_key = 0; print("Checking whether the configuration for '$entity' needs to be updated.\n"); my $add_keyring = sub { print("Setting keyring path to '$keyring_value'.\n"); $cfg->{$entity}->{keyring} = $keyring_value; }; if (!exists($cfg->{$entity})) { print("Adding missing section for '$entity'.\n"); $add_keyring->(); return 1; } if (exists($cfg->{$entity}->{key})) { print("Removing existing usage of key.\n"); delete($cfg->{$entity}->{key}); $removed_key = 1; } if (!exists($cfg->{$entity}->{keyring})) { print("Keyring path is missing from configuration.\n"); $add_keyring->(); return 1; } my $current_keyring_value = $cfg->{$entity}->{keyring}; if ($current_keyring_value ne $keyring_value) { print("Current keyring path differs from expected path.\n"); $add_keyring->(); return 1; } return $removed_key; } sub main { # PVE::RADOS expects an active RPC Environment because it forks itself # and may want to clean up after my $rpcenv = PVE::RPCEnvironment->setup_default_cli_env(); if (!PVE::Ceph::Tools::check_ceph_installed('ceph_bin', 1)) { print("Ceph is not installed. No action required.\n"); exit 0; } my $ceph_cfg_path = PVE::Ceph::Tools::get_config('pve_ceph_cfgpath'); if (PVE::Ceph::Tools::check_ceph_installed('ceph_mon', 1) && -f $ceph_cfg_path) { my $pve_ceph_cfgdir = PVE::Ceph::Tools::get_config('pve_ceph_cfgdir'); if (! -d $pve_ceph_cfgdir) { File::Path::make_path($pve_ceph_cfgdir); } } eval { PVE::Ceph::Tools::check_ceph_inited(); }; if ($@) { print("Ceph is not initialized. No action required.\n"); exit 0; } my $rados = eval { PVE::RADOS->new() }; my $ceph_crash_key_path = PVE::Ceph::Tools::get_config('pve_ceph_crash_key_path'); my $inner_err = ''; my $rval = PVE::Cluster::cfs_lock_file($ceph_cfg_file, undef, sub { eval { my $cfg = PVE::Cluster::cfs_read_file($ceph_cfg_file); if (!defined($rados)) { my $has_mon_host = defined($cfg->{global}) && defined($cfg->{global}->{mon_host}); if ($has_mon_host && $cfg->{global}->{mon_host} ne '') { die "Connection to RADOS failed even though a monitor is configured.\n" . "Please verify whether your configuration in '$ceph_cfg_file' is correct.\n" } print( "Connection to RADOS failed and no monitor is configured in '$ceph_cfg_file'.\n". "Assuming that things are fine. No action required.\n" ); return; } my $updated_keyring = PVE::Ceph::Tools::create_or_update_crash_keyring_file($rados); if ($updated_keyring) { print("Keyring file '$ceph_crash_key_path' was updated.\n"); } my $changed = try_adapt_cfg($cfg); if ($changed) { print("Committing updated configuration to '$ceph_cfg_file'.\n"); PVE::Cluster::cfs_write_file($ceph_cfg_file, $cfg); print("Successfully updated configuration for 'ceph-crash.service'.\n"); } else { print("Configuration in '$ceph_cfg_file' does not need to be updated.\n"); } }; $inner_err = $@; return 1; }); # cfs_lock_file sets $@ explicitly to undef my $err = $@ // ''; my $has_err = !defined($rval) || $inner_err || $err; if ($has_err) { $err =~ s/\n*$//; $inner_err =~ s/\n*$//; if (!defined($rval)) { warn("Error while acquiring or releasing lock for '$ceph_cfg_file'.\n"); warn("Error: $err\n") if $err ne ''; } warn("Failed to configure keyring for 'ceph-crash.service'.\nError: $inner_err\n") if $inner_err ne ''; exit 1; } } main();