[pve-devel] [PATCH manager 7/7] ceph: move Monitor API calls to API2/Ceph/MON.pm

Dominik Csapak d.csapak at proxmox.com
Wed Dec 19 11:24:47 CET 2018


and adapt the paths

Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
 PVE/API2/Ceph.pm       | 354 +----------------------------------------------
 PVE/API2/Ceph/MON.pm   | 369 +++++++++++++++++++++++++++++++++++++++++++++++++
 PVE/API2/Ceph/Makefile |   1 +
 PVE/CLI/pveceph.pm     |   5 +-
 4 files changed, 379 insertions(+), 350 deletions(-)
 create mode 100644 PVE/API2/Ceph/MON.pm

diff --git a/PVE/API2/Ceph.pm b/PVE/API2/Ceph.pm
index 60988996..8304f4d0 100644
--- a/PVE/API2/Ceph.pm
+++ b/PVE/API2/Ceph.pm
@@ -22,6 +22,7 @@ use PVE::API2::Ceph::OSD;
 use PVE::API2::Ceph::FS;
 use PVE::API2::Ceph::MDS;
 use PVE::API2::Ceph::MGR;
+use PVE::API2::Ceph::MON;
 use PVE::API2::Storage::Config;
 
 use base qw(PVE::RESTHandler);
@@ -44,6 +45,11 @@ __PACKAGE__->register_method ({
 });
 
 __PACKAGE__->register_method ({
+    subclass => "PVE::API2::Ceph::MON",
+    path => 'mon',
+});
+
+__PACKAGE__->register_method ({
     subclass => "PVE::API2::Ceph::FS",
     path => 'fs',
 });
@@ -218,75 +224,6 @@ my $get_storages = sub {
 };
 
 __PACKAGE__->register_method ({
-    name => 'listmon',
-    path => 'mon',
-    method => 'GET',
-    description => "Get Ceph monitor list.",
-    proxyto => 'node',
-    protected => 1,
-    permissions => {
-	check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1],
-    },
-    parameters => {
-	additionalProperties => 0,
-	properties => {
-	    node => get_standard_option('pve-node'),
-	},
-    },
-    returns => {
-	type => 'array',
-	items => {
-	    type => "object",
-	    properties => {
-		name => { type => 'string' },
-		addr => { type => 'string' },
-	    },
-	},
-	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 $monhash = {};
-	foreach my $section (keys %$cfg) {
-	    my $d = $cfg->{$section};
-	    if ($section =~ m/^mon\.(\S+)$/) {
-		my $monid = $1;
-		if ($d->{'mon addr'} && $d->{'host'}) {
-		    $monhash->{$monid} = {
-			addr => $d->{'mon addr'},
-			host => $d->{'host'},
-			name => $monid,
-		    }
-		}
-	    }
-	}
-
-	eval {
-	    my $rados = PVE::RADOS->new();
-	    my $monstat = $rados->mon_command({ prefix => 'mon_status' });
-	    my $mons = $monstat->{monmap}->{mons};
-	    foreach my $d (@$mons) {
-		next if !defined($d->{name});
-		$monhash->{$d->{name}}->{rank} = $d->{rank};
-		$monhash->{$d->{name}}->{addr} = $d->{addr};
-		if (grep { $_ eq $d->{rank} } @{$monstat->{quorum}}) {
-		    $monhash->{$d->{name}}->{quorum} = 1;
-		}
-	    }
-	};
-	warn $@ if $@;
-
-	return PVE::RESTHandler::hash_to_array($monhash, 'name');
-    }});
-
-__PACKAGE__->register_method ({
     name => 'init',
     path => 'init',
     method => 'POST',
@@ -416,285 +353,6 @@ __PACKAGE__->register_method ({
 	return undef;
     }});
 
-my $find_mon_ip = sub {
-    my ($pubnet, $node, $overwrite_ip) = @_;
-
-    if (!$pubnet) {
-	return $overwrite_ip // PVE::Cluster::remote_node_ip($node);
-    }
-
-    my $allowed_ips = PVE::Network::get_local_ip_from_cidr($pubnet);
-    die "No IP configured and up from ceph public network '$pubnet'\n"
-	if scalar(@$allowed_ips) < 1;
-
-    if (!$overwrite_ip) {
-	if (scalar(@$allowed_ips) == 1) {
-	    return $allowed_ips->[0];
-	}
-	die "Multiple IPs for ceph public network '$pubnet' detected on $node:\n".
-	    join("\n", @$allowed_ips) ."\nuse 'mon-address' to specify one of them.\n";
-    } else {
-	if (grep { $_ eq $overwrite_ip } @$allowed_ips) {
-	    return $overwrite_ip;
-	}
-	die "Monitor IP '$overwrite_ip' not in ceph public network '$pubnet'\n"
-	    if !PVE::Network::is_ip_in_cidr($overwrite_ip, $pubnet);
-
-	die "Specified monitor IP '$overwrite_ip' not configured or up on $node!\n";
-    }
-};
-
-__PACKAGE__->register_method ({
-    name => 'createmon',
-    path => 'mon',
-    method => 'POST',
-    description => "Create Ceph Monitor and Manager",
-    proxyto => 'node',
-    protected => 1,
-    permissions => {
-	check => ['perm', '/', [ 'Sys.Modify' ]],
-    },
-    parameters => {
-	additionalProperties => 0,
-	properties => {
-	    node => get_standard_option('pve-node'),
-	    id => {
-		type => 'string',
-		optional => 1,
-		pattern => '[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?',
-		description => "The ID for the monitor, when omitted the same as the nodename",
-	    },
-	    'exclude-manager' => {
-		type => 'boolean',
-		optional => 1,
-		default => 0,
-		description => "When set, only a monitor will be created.",
-	    },
-	    'mon-address' => {
-		description => 'Overwrites autodetected monitor IP address. ' .
-		               'Must be in the public network of ceph.',
-		type => 'string', format => 'ip',
-		optional => 1,
-	    },
-	},
-    },
-    returns => { type => 'string' },
-    code => sub {
-	my ($param) = @_;
-
-	PVE::Ceph::Tools::check_ceph_installed('ceph_mon');
-
-	PVE::Ceph::Tools::check_ceph_installed('ceph_mgr')
-	    if (!$param->{'exclude-manager'});
-
-	PVE::Ceph::Tools::check_ceph_inited();
-
-	PVE::Ceph::Tools::setup_pve_symlinks();
-
-	my $rpcenv = PVE::RPCEnvironment::get();
-
-	my $authuser = $rpcenv->get_user();
-
-	my $cfg = cfs_read_file('ceph.conf');
-
-	my $moncount = 0;
-
-	my $monaddrhash = {};
-
-	my $systemd_managed = PVE::Ceph::Tools::systemd_managed();
-
-	foreach my $section (keys %$cfg) {
-	    next if $section eq 'global';
-	    my $d = $cfg->{$section};
-	    if ($section =~ m/^mon\./) {
-		$moncount++;
-		if ($d->{'mon addr'}) {
-		    $monaddrhash->{$d->{'mon addr'}} = $section;
-		}
-	    }
-	}
-
-	my $monid = $param->{id} // $param->{node};
-
-	my $monsection = "mon.$monid";
-	my $pubnet = $cfg->{global}->{'public network'};
-	my $ip = $find_mon_ip->($pubnet, $param->{node}, $param->{'mon-address'});
-
-	my $monaddr = Net::IP::ip_is_ipv6($ip) ? "[$ip]:6789" : "$ip:6789";
-	my $monname = $param->{node};
-
-	die "monitor '$monsection' already exists\n" if $cfg->{$monsection};
-	die "monitor address '$monaddr' already in use by '$monaddrhash->{$monaddr}'\n"
-	    if $monaddrhash->{$monaddr};
-
-	my $worker = sub  {
-	    my $upid = shift;
-
-	    my $pve_ckeyring_path = PVE::Ceph::Tools::get_config('pve_ckeyring_path');
-
-	    if (! -f $pve_ckeyring_path) {
-		run_command("ceph-authtool $pve_ckeyring_path --create-keyring " .
-			    "--gen-key -n client.admin");
-	    }
-
-	    my $pve_mon_key_path = PVE::Ceph::Tools::get_config('pve_mon_key_path');
-	    if (! -f $pve_mon_key_path) {
-		run_command("cp $pve_ckeyring_path $pve_mon_key_path.tmp");
-		run_command("ceph-authtool $pve_mon_key_path.tmp -n client.admin --set-uid=0 " .
-			    "--cap mds 'allow' " .
-			    "--cap osd 'allow *' " .
-			    "--cap mgr 'allow *' " .
-			    "--cap mon 'allow *'");
-		run_command("cp $pve_mon_key_path.tmp /etc/ceph/ceph.client.admin.keyring") if $systemd_managed;
-		run_command("chown ceph:ceph /etc/ceph/ceph.client.admin.keyring") if $systemd_managed;
-		run_command("ceph-authtool $pve_mon_key_path.tmp --gen-key -n mon. --cap mon 'allow *'");
-		run_command("mv $pve_mon_key_path.tmp $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";
-
-	    my $monmap = "/tmp/monmap";
-
-	    eval {
-		mkdir $mondir;
-
-		run_command("chown ceph:ceph $mondir") if $systemd_managed;
-
-		if ($moncount > 0) {
-		    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 {
-		    run_command("monmaptool --create --clobber --add $monid $monaddr --print $monmap");
-		}
-
-		run_command("ceph-mon --mkfs -i $monid --monmap $monmap --keyring $pve_mon_key_path");
-		run_command("chown ceph:ceph -R $mondir") if $systemd_managed;
-	    };
-	    my $err = $@;
-	    unlink $monmap;
-	    if ($err) {
-		File::Path::remove_tree($mondir);
-		die $err;
-	    }
-
-	    $cfg->{$monsection} = {
-		'host' => $monname,
-		'mon addr' => $monaddr,
-	    };
-
-	    cfs_write_file('ceph.conf', $cfg);
-
-	    my $create_keys_pid = fork();
-	    if (!defined($create_keys_pid)) {
-		die "Could not spawn ceph-create-keys to create bootstrap keys\n";
-	    } elsif ($create_keys_pid == 0) {
-		exit PVE::Tools::run_command(['ceph-create-keys', '-i', $monid]);
-	    } else {
-		PVE::Ceph::Services::ceph_service_cmd('start', $monsection);
-
-		if ($systemd_managed) {
-		    #to ensure we have the correct startup order.
-		    eval { PVE::Tools::run_command(['/bin/systemctl', 'enable', "ceph-mon\@${monid}.service"]); };
-		    warn "Enable ceph-mon\@${monid}.service manually"if $@;
-		}
-		waitpid($create_keys_pid, 0);
-	    }
-
-	    # create manager
-	    if (!$param->{'exclude-manager'}) {
-		my $rados = PVE::RADOS->new(timeout => PVE::Ceph::Tools::get_config('long_rados_timeout'));
-		PVE::Ceph::Services::create_mgr($monid, $rados);
-	    }
-	};
-
-	return $rpcenv->fork_worker('cephcreatemon', $monsection, $authuser, $worker);
-    }});
-
-__PACKAGE__->register_method ({
-    name => 'destroymon',
-    path => 'mon/{monid}',
-    method => 'DELETE',
-    description => "Destroy Ceph Monitor and Manager.",
-    proxyto => 'node',
-    protected => 1,
-    permissions => {
-	check => ['perm', '/', [ 'Sys.Modify' ]],
-    },
-    parameters => {
-	additionalProperties => 0,
-	properties => {
-	    node => get_standard_option('pve-node'),
-	    monid => {
-		description => 'Monitor ID',
-		type => 'string',
-		pattern => '[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?',
-	    },
-	    'exclude-manager' => {
-		type => 'boolean',
-		default => 0,
-		optional => 1,
-		description => "When set, removes only the monitor, not the manager"
-	    }
-	},
-    },
-    returns => { type => 'string' },
-    code => sub {
-	my ($param) = @_;
-
-	my $rpcenv = PVE::RPCEnvironment::get();
-
-	my $authuser = $rpcenv->get_user();
-
-	PVE::Ceph::Tools::check_ceph_inited();
-
-	my $cfg = cfs_read_file('ceph.conf');
-
-	my $monid = $param->{monid};
-	my $monsection = "mon.$monid";
-
-	my $rados = PVE::RADOS->new();
-	my $monstat = $rados->mon_command({ prefix => 'mon_status' });
-	my $monlist = $monstat->{monmap}->{mons};
-
-	die "no such monitor id '$monid'\n"
-	    if !defined($cfg->{$monsection});
-
-	my $ccname = PVE::Ceph::Tools::get_config('ccname');
-
-	my $mondir =  "/var/lib/ceph/mon/$ccname-$monid";
-	-d $mondir || die "monitor filesystem '$mondir' does not exist on this node\n";
-
-	die "can't remove last monitor\n" if scalar(@$monlist) <= 1;
-
-	my $worker = sub {
-	    my $upid = shift;
-
-	    # reopen with longer timeout
-	    $rados = PVE::RADOS->new(timeout => PVE::Ceph::Tools::get_config('long_rados_timeout'));
-
-	    $rados->mon_command({ prefix => "mon remove", name => $monid, format => 'plain' });
-
-	    eval { PVE::Ceph::Services::ceph_service_cmd('stop', $monsection); };
-	    warn $@ if $@;
-
-	    delete $cfg->{$monsection};
-	    cfs_write_file('ceph.conf', $cfg);
-	    File::Path::remove_tree($mondir);
-
-	    # remove manager
-	    if (!$param->{'exclude-manager'}) {
-		eval { PVE::Ceph::Services::destroy_mgr($mgrid) };
-		warn $@ if $@;
-	    }
-	};
-
-	return $rpcenv->fork_worker('cephdestroymon', $monsection,  $authuser, $worker);
-    }});
-
 __PACKAGE__->register_method ({
     name => 'stop',
     path => 'stop',
diff --git a/PVE/API2/Ceph/MON.pm b/PVE/API2/Ceph/MON.pm
new file mode 100644
index 00000000..ff7db73b
--- /dev/null
+++ b/PVE/API2/Ceph/MON.pm
@@ -0,0 +1,369 @@
+package PVE::API2::Ceph::MON;
+
+use strict;
+use warnings;
+
+use Net::IP;
+use File::Path;
+
+use PVE::Ceph::Tools;
+use PVE::Ceph::Services;
+use PVE::Cluster qw(cfs_read_file cfs_write_file);
+use PVE::JSONSchema qw(get_standard_option);
+use PVE::Network;
+use PVE::RADOS;
+use PVE::RESTHandler;
+use PVE::RPCEnvironment;
+use PVE::Tools qw(run_command file_set_contents);
+
+use base qw(PVE::RESTHandler);
+
+my $find_mon_ip = sub {
+    my ($pubnet, $node, $overwrite_ip) = @_;
+
+    if (!$pubnet) {
+	return $overwrite_ip // PVE::Cluster::remote_node_ip($node);
+    }
+
+    my $allowed_ips = PVE::Network::get_local_ip_from_cidr($pubnet);
+    die "No IP configured and up from ceph public network '$pubnet'\n"
+	if scalar(@$allowed_ips) < 1;
+
+    if (!$overwrite_ip) {
+	if (scalar(@$allowed_ips) == 1) {
+	    return $allowed_ips->[0];
+	}
+	die "Multiple IPs for ceph public network '$pubnet' detected on $node:\n".
+	    join("\n", @$allowed_ips) ."\nuse 'mon-address' to specify one of them.\n";
+    } else {
+	if (grep { $_ eq $overwrite_ip } @$allowed_ips) {
+	    return $overwrite_ip;
+	}
+	die "Monitor IP '$overwrite_ip' not in ceph public network '$pubnet'\n"
+	    if !PVE::Network::is_ip_in_cidr($overwrite_ip, $pubnet);
+
+	die "Specified monitor IP '$overwrite_ip' not configured or up on $node!\n";
+    }
+};
+
+__PACKAGE__->register_method ({
+    name => 'listmon',
+    path => '',
+    method => 'GET',
+    description => "Get Ceph monitor list.",
+    proxyto => 'node',
+    protected => 1,
+    permissions => {
+	check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1],
+    },
+    parameters => {
+	additionalProperties => 0,
+	properties => {
+	    node => get_standard_option('pve-node'),
+	},
+    },
+    returns => {
+	type => 'array',
+	items => {
+	    type => "object",
+	    properties => {
+		name => { type => 'string' },
+		addr => { type => 'string' },
+	    },
+	},
+	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 $monhash = {};
+	foreach my $section (keys %$cfg) {
+	    my $d = $cfg->{$section};
+	    if ($section =~ m/^mon\.(\S+)$/) {
+		my $monid = $1;
+		if ($d->{'mon addr'} && $d->{'host'}) {
+		    $monhash->{$monid} = {
+			addr => $d->{'mon addr'},
+			host => $d->{'host'},
+			name => $monid,
+		    }
+		}
+	    }
+	}
+
+	eval {
+	    my $rados = PVE::RADOS->new();
+	    my $monstat = $rados->mon_command({ prefix => 'mon_status' });
+	    my $mons = $monstat->{monmap}->{mons};
+	    foreach my $d (@$mons) {
+		next if !defined($d->{name});
+		$monhash->{$d->{name}}->{rank} = $d->{rank};
+		$monhash->{$d->{name}}->{addr} = $d->{addr};
+		if (grep { $_ eq $d->{rank} } @{$monstat->{quorum}}) {
+		    $monhash->{$d->{name}}->{quorum} = 1;
+		}
+	    }
+	};
+	warn $@ if $@;
+
+	return PVE::RESTHandler::hash_to_array($monhash, 'name');
+    }});
+
+__PACKAGE__->register_method ({
+    name => 'createmon',
+    path => '',
+    method => 'POST',
+    description => "Create Ceph Monitor and Manager",
+    proxyto => 'node',
+    protected => 1,
+    permissions => {
+	check => ['perm', '/', [ 'Sys.Modify' ]],
+    },
+    parameters => {
+	additionalProperties => 0,
+	properties => {
+	    node => get_standard_option('pve-node'),
+	    id => {
+		type => 'string',
+		optional => 1,
+		pattern => '[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?',
+		description => "The ID for the monitor, when omitted the same as the nodename",
+	    },
+	    'exclude-manager' => {
+		type => 'boolean',
+		optional => 1,
+		default => 0,
+		description => "When set, only a monitor will be created.",
+	    },
+	    'mon-address' => {
+		description => 'Overwrites autodetected monitor IP address. ' .
+		               'Must be in the public network of ceph.',
+		type => 'string', format => 'ip',
+		optional => 1,
+	    },
+	},
+    },
+    returns => { type => 'string' },
+    code => sub {
+	my ($param) = @_;
+
+	PVE::Ceph::Tools::check_ceph_installed('ceph_mon');
+
+	PVE::Ceph::Tools::check_ceph_installed('ceph_mgr')
+	    if (!$param->{'exclude-manager'});
+
+	PVE::Ceph::Tools::check_ceph_inited();
+
+	PVE::Ceph::Tools::setup_pve_symlinks();
+
+	my $rpcenv = PVE::RPCEnvironment::get();
+
+	my $authuser = $rpcenv->get_user();
+
+	my $cfg = cfs_read_file('ceph.conf');
+
+	my $moncount = 0;
+
+	my $monaddrhash = {};
+
+	my $systemd_managed = PVE::Ceph::Tools::systemd_managed();
+
+	foreach my $section (keys %$cfg) {
+	    next if $section eq 'global';
+	    my $d = $cfg->{$section};
+	    if ($section =~ m/^mon\./) {
+		$moncount++;
+		if ($d->{'mon addr'}) {
+		    $monaddrhash->{$d->{'mon addr'}} = $section;
+		}
+	    }
+	}
+
+	my $monid = $param->{id} // $param->{node};
+
+	my $monsection = "mon.$monid";
+	my $pubnet = $cfg->{global}->{'public network'};
+	my $ip = $find_mon_ip->($pubnet, $param->{node}, $param->{'mon-address'});
+
+	my $monaddr = Net::IP::ip_is_ipv6($ip) ? "[$ip]:6789" : "$ip:6789";
+	my $monname = $param->{node};
+
+	die "monitor '$monsection' already exists\n" if $cfg->{$monsection};
+	die "monitor address '$monaddr' already in use by '$monaddrhash->{$monaddr}'\n"
+	    if $monaddrhash->{$monaddr};
+
+	my $worker = sub  {
+	    my $upid = shift;
+
+	    my $pve_ckeyring_path = PVE::Ceph::Tools::get_config('pve_ckeyring_path');
+
+	    if (! -f $pve_ckeyring_path) {
+		run_command("ceph-authtool $pve_ckeyring_path --create-keyring " .
+			    "--gen-key -n client.admin");
+	    }
+
+	    my $pve_mon_key_path = PVE::Ceph::Tools::get_config('pve_mon_key_path');
+	    if (! -f $pve_mon_key_path) {
+		run_command("cp $pve_ckeyring_path $pve_mon_key_path.tmp");
+		run_command("ceph-authtool $pve_mon_key_path.tmp -n client.admin --set-uid=0 " .
+			    "--cap mds 'allow' " .
+			    "--cap osd 'allow *' " .
+			    "--cap mgr 'allow *' " .
+			    "--cap mon 'allow *'");
+		run_command("cp $pve_mon_key_path.tmp /etc/ceph/ceph.client.admin.keyring") if $systemd_managed;
+		run_command("chown ceph:ceph /etc/ceph/ceph.client.admin.keyring") if $systemd_managed;
+		run_command("ceph-authtool $pve_mon_key_path.tmp --gen-key -n mon. --cap mon 'allow *'");
+		run_command("mv $pve_mon_key_path.tmp $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";
+
+	    my $monmap = "/tmp/monmap";
+
+	    eval {
+		mkdir $mondir;
+
+		run_command("chown ceph:ceph $mondir") if $systemd_managed;
+
+		if ($moncount > 0) {
+		    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 {
+		    run_command("monmaptool --create --clobber --add $monid $monaddr --print $monmap");
+		}
+
+		run_command("ceph-mon --mkfs -i $monid --monmap $monmap --keyring $pve_mon_key_path");
+		run_command("chown ceph:ceph -R $mondir") if $systemd_managed;
+	    };
+	    my $err = $@;
+	    unlink $monmap;
+	    if ($err) {
+		File::Path::remove_tree($mondir);
+		die $err;
+	    }
+
+	    $cfg->{$monsection} = {
+		'host' => $monname,
+		'mon addr' => $monaddr,
+	    };
+
+	    cfs_write_file('ceph.conf', $cfg);
+
+	    my $create_keys_pid = fork();
+	    if (!defined($create_keys_pid)) {
+		die "Could not spawn ceph-create-keys to create bootstrap keys\n";
+	    } elsif ($create_keys_pid == 0) {
+		exit PVE::Tools::run_command(['ceph-create-keys', '-i', $monid]);
+	    } else {
+		PVE::Ceph::Services::ceph_service_cmd('start', $monsection);
+
+		if ($systemd_managed) {
+		    #to ensure we have the correct startup order.
+		    eval { PVE::Tools::run_command(['/bin/systemctl', 'enable', "ceph-mon\@${monid}.service"]); };
+		    warn "Enable ceph-mon\@${monid}.service manually"if $@;
+		}
+		waitpid($create_keys_pid, 0);
+	    }
+
+	    # create manager
+	    if (!$param->{'exclude-manager'}) {
+		my $rados = PVE::RADOS->new(timeout => PVE::Ceph::Tools::get_config('long_rados_timeout'));
+		PVE::Ceph::Services::create_mgr($monid, $rados);
+	    }
+	};
+
+	return $rpcenv->fork_worker('cephcreatemon', $monsection, $authuser, $worker);
+    }});
+
+__PACKAGE__->register_method ({
+    name => 'destroymon',
+    path => '{monid}',
+    method => 'DELETE',
+    description => "Destroy Ceph Monitor and Manager.",
+    proxyto => 'node',
+    protected => 1,
+    permissions => {
+	check => ['perm', '/', [ 'Sys.Modify' ]],
+    },
+    parameters => {
+	additionalProperties => 0,
+	properties => {
+	    node => get_standard_option('pve-node'),
+	    monid => {
+		description => 'Monitor ID',
+		type => 'string',
+		pattern => '[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?',
+	    },
+	    'exclude-manager' => {
+		type => 'boolean',
+		default => 0,
+		optional => 1,
+		description => "When set, removes only the monitor, not the manager"
+	    }
+	},
+    },
+    returns => { type => 'string' },
+    code => sub {
+	my ($param) = @_;
+
+	my $rpcenv = PVE::RPCEnvironment::get();
+
+	my $authuser = $rpcenv->get_user();
+
+	PVE::Ceph::Tools::check_ceph_inited();
+
+	my $cfg = cfs_read_file('ceph.conf');
+
+	my $monid = $param->{monid};
+	my $monsection = "mon.$monid";
+
+	my $rados = PVE::RADOS->new();
+	my $monstat = $rados->mon_command({ prefix => 'mon_status' });
+	my $monlist = $monstat->{monmap}->{mons};
+
+	die "no such monitor id '$monid'\n"
+	    if !defined($cfg->{$monsection});
+
+	my $ccname = PVE::Ceph::Tools::get_config('ccname');
+
+	my $mondir =  "/var/lib/ceph/mon/$ccname-$monid";
+	-d $mondir || die "monitor filesystem '$mondir' does not exist on this node\n";
+
+	die "can't remove last monitor\n" if scalar(@$monlist) <= 1;
+
+	my $worker = sub {
+	    my $upid = shift;
+
+	    # reopen with longer timeout
+	    $rados = PVE::RADOS->new(timeout => PVE::Ceph::Tools::get_config('long_rados_timeout'));
+
+	    $rados->mon_command({ prefix => "mon remove", name => $monid, format => 'plain' });
+
+	    eval { PVE::Ceph::Services::ceph_service_cmd('stop', $monsection); };
+	    warn $@ if $@;
+
+	    delete $cfg->{$monsection};
+	    cfs_write_file('ceph.conf', $cfg);
+	    File::Path::remove_tree($mondir);
+
+	    # remove manager
+	    if (!$param->{'exclude-manager'}) {
+		eval { PVE::Ceph::Services::destroy_mgr($monid) };
+		warn $@ if $@;
+	    }
+	};
+
+	return $rpcenv->fork_worker('cephdestroymon', $monsection,  $authuser, $worker);
+    }});
+
+1;
diff --git a/PVE/API2/Ceph/Makefile b/PVE/API2/Ceph/Makefile
index 99566cfd..5b6493d5 100644
--- a/PVE/API2/Ceph/Makefile
+++ b/PVE/API2/Ceph/Makefile
@@ -2,6 +2,7 @@ include ../../../defines.mk
 
 PERLSOURCE= 			\
 	MGR.pm			\
+	MON.pm			\
 	OSD.pm			\
 	FS.pm			\
 	MDS.pm
diff --git a/PVE/CLI/pveceph.pm b/PVE/CLI/pveceph.pm
index 294b1b82..71a5a2f0 100755
--- a/PVE/CLI/pveceph.pm
+++ b/PVE/CLI/pveceph.pm
@@ -22,6 +22,7 @@ use PVE::API2::Ceph;
 use PVE::API2::Ceph::FS;
 use PVE::API2::Ceph::MDS;
 use PVE::API2::Ceph::MGR;
+use PVE::API2::Ceph::MON;
 use PVE::API2::Ceph::OSD;
 
 use PVE::CLIHandler;
@@ -188,8 +189,8 @@ our $cmddef = {
     createosd => { alias => 'osd create' },
     destroyosd => { alias => 'osd destroy' },
     mon => {
-	create => [ 'PVE::API2::Ceph', 'createmon', [], { node => $nodename }, $upid_exit],
-	destroy => [ 'PVE::API2::Ceph', 'destroymon', ['monid'], { node => $nodename }, $upid_exit],
+	create => [ 'PVE::API2::Ceph::MON', 'createmon', [], { node => $nodename }, $upid_exit],
+	destroy => [ 'PVE::API2::Ceph::MON', 'destroymon', ['monid'], { node => $nodename }, $upid_exit],
     },
     createmon => { alias => 'mon create' },
     destroymon => { alias => 'mon destroy' },
-- 
2.11.0





More information about the pve-devel mailing list