[pve-devel] [PATCH manager 10/14] ceph: mon create: lock monitor creation

Thomas Lamprecht t.lamprecht at proxmox.com
Tue Jun 18 17:02:04 CEST 2019


On 6/18/19 3:42 PM, Dominik Csapak wrote:
> otherwise it is possible that multiple users create monitors at the same
> time, resulting in a wrong ceph.conf and probably worse
> 
> Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
> ---
> best viewed with -w
>  PVE/API2/Ceph/MON.pm | 97 +++++++++++++++++++++++++++++-----------------------
>  1 file changed, 54 insertions(+), 43 deletions(-)
> 
> diff --git a/PVE/API2/Ceph/MON.pm b/PVE/API2/Ceph/MON.pm
> index 6cba7f8e..832a275e 100644
> --- a/PVE/API2/Ceph/MON.pm
> +++ b/PVE/API2/Ceph/MON.pm
> @@ -196,62 +196,73 @@ __PACKAGE__->register_method ({
>  	my $worker = sub  {
>  	    my $upid = shift;
>  
> -	    my $client_keyring = PVE::Ceph::Tools::get_or_create_admin_keyring();
> -	    my $mon_keyring = PVE::Ceph::Tools::get_config('pve_mon_key_path');
> +	    PVE::Cluster::cfs_lock_file('ceph.conf', undef, sub {
> +		# update cfg content and reassert prereqs inside the lock
> +		$cfg = cfs_read_file('ceph.conf');
> +		# reopen with longer timeout
> +		if (!$firstmon) {

Even if we'd say it's OK to add the $firstmon variable to encode that
correlation into the variable name I still would like to do:
s/!$firstmon/$rados/
here.. IMO this is independent, if we have a $rados connection we re-open
it with bigger time out, we do not need to care why we have the $rados
connection, just makes things more brittle, IMO..

> +		    $rados = PVE::RADOS->new(timeout => PVE::Ceph::Tools::get_config('long_rados_timeout'));
> +		}
> +		$monhash = PVE::Ceph::Services::get_services_info('mon', $cfg, $rados);
> +		$assert_mon_prerequisites->($cfg, $monhash, $monid, $ip);
>  
> -	    if (! -f $mon_keyring) {
> -		run_command("ceph-authtool --create-keyring $mon_keyring ".
> -		    " --gen-key -n mon. --cap mon 'allow *'");
> -		run_command("ceph-authtool $mon_keyring --import-keyring $client_keyring");
> -	    }
> +		my $client_keyring = PVE::Ceph::Tools::get_or_create_admin_keyring();
> +		my $mon_keyring = PVE::Ceph::Tools::get_config('pve_mon_key_path');
>  
> -	    my $ccname = PVE::Ceph::Tools::get_config('ccname');
> -	    my $mondir =  "/var/lib/ceph/mon/$ccname-$monid";
> -	    -d $mondir && die "monitor filesystem '$mondir' already exist\n";
> +		if (! -f $mon_keyring) {
> +		    run_command("ceph-authtool --create-keyring $mon_keyring ".
> +			" --gen-key -n mon. --cap mon 'allow *'");
> +		    run_command("ceph-authtool $mon_keyring --import-keyring $client_keyring");
> +		}
>  
> -	    my $monmap = "/tmp/monmap";
> +		my $ccname = PVE::Ceph::Tools::get_config('ccname');
> +		my $mondir =  "/var/lib/ceph/mon/$ccname-$monid";
> +		-d $mondir && die "monitor filesystem '$mondir' already exist\n";
>  
> -	    eval {
> -		mkdir $mondir;
> +		my $monmap = "/tmp/monmap";
>  
> -		run_command("chown ceph:ceph $mondir");
> +		eval {
> +		    mkdir $mondir;
>  
> -		if (!$firstmon) {
> -		    my $rados = PVE::RADOS->new(timeout => PVE::Ceph::Tools::get_config('long_rados_timeout'));
> -		    my $mapdata = $rados->mon_command({ prefix => 'mon getmap', format => 'plain' });
> -		    file_set_contents($monmap, $mapdata);
> -		} else {
> -		    my $monaddr = $ip;
> -		    if (Net::IP::ip_is_ipv6($ip)) {
> -			$monaddr = "[$ip]";
> -			$cfg->{global}->{ms_bind_ipv6} = 'true';
> +		    run_command("chown ceph:ceph $mondir");
> +
> +		    if (!$firstmon) {
> +			my $mapdata = $rados->mon_command({ prefix => 'mon getmap', format => 'plain' });
> +			file_set_contents($monmap, $mapdata);
> +		    } else {
> +			my $monaddr = $ip;
> +			if (Net::IP::ip_is_ipv6($ip)) {
> +			    $monaddr = "[$ip]";
> +			    $cfg->{global}->{ms_bind_ipv6} = 'true';
> +			}
> +			run_command("monmaptool --create --clobber --addv $monid '[v2:$monaddr:3300,v1:$monaddr:6789]' --print $monmap");
>  		    }
> -		    run_command("monmaptool --create --clobber --addv $monid '[v2:$monaddr:3300,v1:$monaddr:6789]' --print $monmap");
> +
> +		    run_command("ceph-mon --mkfs -i $monid --monmap $monmap --keyring $mon_keyring --public-addr $ip");
> +		    run_command("chown ceph:ceph -R $mondir");
> +		};
> +		my $err = $@;
> +		unlink $monmap;
> +		if ($err) {
> +		    File::Path::remove_tree($mondir);
> +		    die $err;
>  		}
>  
> -		run_command("ceph-mon --mkfs -i $monid --monmap $monmap --keyring $mon_keyring --public-addr $ip");
> -		run_command("chown ceph:ceph -R $mondir");
> -	    };
> -	    my $err = $@;
> -	    unlink $monmap;
> -	    if ($err) {
> -		File::Path::remove_tree($mondir);
> -		die $err;
> -	    }
> +		# update ceph.conf
> +		my $monhost = $cfg->{global}->{mon_host} // "";
> +		$monhost .= " $ip";
> +		$cfg->{global}->{mon_host} = $monhost;
>  
> -	    # update ceph.conf
> -	    my $monhost = $cfg->{global}->{mon_host} // "";
> -	    $monhost .= " $ip";
> -	    $cfg->{global}->{mon_host} = $monhost;
> +		cfs_write_file('ceph.conf', $cfg);
>  
> -	    cfs_write_file('ceph.conf', $cfg);
> +		PVE::Ceph::Services::ceph_service_cmd('start', $monsection);
>  
> -	    PVE::Ceph::Services::ceph_service_cmd('start', $monsection);
> +		eval { PVE::Ceph::Services::ceph_service_cmd('enable', $monsection) };
> +		warn "Enable ceph-mon\@${monid}.service failed, do manually: $@\n" if $@;
>  
> -	    eval { PVE::Ceph::Services::ceph_service_cmd('enable', $monsection) };
> -	    warn "Enable ceph-mon\@${monid}.service failed, do manually: $@\n" if $@;
> -
> -	    PVE::Ceph::Services::broadcast_ceph_services();
> +		PVE::Ceph::Services::broadcast_ceph_services();
> +	    });
> +	    die $@ if $@;
>  	};
>  
>  	return $rpcenv->fork_worker('cephcreatemon', $monsection, $authuser, $worker);
> 





More information about the pve-devel mailing list