]>
git.proxmox.com Git - pve-manager.git/blob - PVE/API2/Ceph/MON.pm
59f3019359571dd9d6b8d79e0924c41f990b9214
1 package PVE
::API2
::Ceph
::MON
;
10 use PVE
::Ceph
::Services
;
11 use PVE
::Cluster
qw(cfs_read_file cfs_write_file);
12 use PVE
::JSONSchema
qw(get_standard_option);
16 use PVE
::RPCEnvironment
;
17 use PVE
::Tools
qw(run_command file_set_contents);
19 use base
qw(PVE::RESTHandler);
21 my $find_mon_ip = sub {
22 my ($pubnet, $node, $overwrite_ip) = @_;
25 return $overwrite_ip // PVE
::Cluster
::remote_node_ip
($node);
28 my $allowed_ips = PVE
::Network
::get_local_ip_from_cidr
($pubnet);
29 die "No active IP found for the requested ceph public network '$pubnet' on node '$node'\n"
30 if scalar(@$allowed_ips) < 1;
33 if (scalar(@$allowed_ips) == 1) {
34 return $allowed_ips->[0];
36 die "Multiple IPs for ceph public network '$pubnet' detected on $node:\n".
37 join("\n", @$allowed_ips) ."\nuse 'mon-address' to specify one of them.\n";
39 if (grep { $_ eq $overwrite_ip } @$allowed_ips) {
42 die "Monitor IP '$overwrite_ip' not in ceph public network '$pubnet'\n"
43 if !PVE
::Network
::is_ip_in_cidr
($overwrite_ip, $pubnet);
45 die "Specified monitor IP '$overwrite_ip' not configured or up on $node!\n";
49 __PACKAGE__-
>register_method ({
53 description
=> "Get Ceph monitor list.",
57 check
=> ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any
=> 1],
60 additionalProperties
=> 0,
62 node
=> get_standard_option
('pve-node'),
70 name
=> { type
=> 'string' },
71 addr
=> { type
=> 'string', optional
=> 1 },
72 host
=> { type
=> 'string', optional
=> 1 },
75 links
=> [ { rel
=> 'child', href
=> "{name}" } ],
80 PVE
::Ceph
::Tools
::check_ceph_inited
();
84 my $cfg = cfs_read_file
('ceph.conf');
89 my $rados = PVE
::RADOS-
>new();
90 $monhash = PVE
::Ceph
::Services
::get_services_info
("mon", $cfg, $rados);
91 my $monstat = $rados->mon_command({ prefix
=> 'mon_status' });
93 my $mons = $monstat->{monmap
}->{mons
};
94 foreach my $d (@$mons) {
95 next if !defined($d->{name
});
96 $monhash->{$d->{name
}}->{rank
} = $d->{rank
};
97 $monhash->{$d->{name
}}->{addr
} = $d->{addr
};
98 $monhash->{$d->{name
}}->{state} = 'running';
99 if (grep { $_ eq $d->{rank
} } @{$monstat->{quorum
}}) {
100 $monhash->{$d->{name
}}->{quorum
} = 1;
107 return PVE
::RESTHandler
::hash_to_array
($monhash, 'name');
110 __PACKAGE__-
>register_method ({
114 description
=> "Create Ceph Monitor and Manager",
118 check
=> ['perm', '/', [ 'Sys.Modify' ]],
121 additionalProperties
=> 0,
123 node
=> get_standard_option
('pve-node'),
127 pattern
=> '[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?',
128 description
=> "The ID for the monitor, when omitted the same as the nodename",
130 'exclude-manager' => {
134 description
=> "When set, only a monitor will be created.",
137 description
=> 'Overwrites autodetected monitor IP address. ' .
138 'Must be in the public network of ceph.',
139 type
=> 'string', format
=> 'ip',
144 returns
=> { type
=> 'string' },
148 PVE
::Ceph
::Tools
::check_ceph_installed
('ceph_mon');
150 PVE
::Ceph
::Tools
::check_ceph_installed
('ceph_mgr')
151 if (!$param->{'exclude-manager'});
153 PVE
::Ceph
::Tools
::check_ceph_inited
();
155 PVE
::Ceph
::Tools
::setup_pve_symlinks
();
157 my $rpcenv = PVE
::RPCEnvironment
::get
();
159 my $authuser = $rpcenv->get_user();
161 my $cfg = cfs_read_file
('ceph.conf');
165 my $monaddrhash = {};
167 foreach my $section (keys %$cfg) {
168 next if $section eq 'global';
169 my $d = $cfg->{$section};
170 if ($section =~ m/^mon\./) {
172 if ($d->{'mon addr'}) {
173 $monaddrhash->{$d->{'mon addr'}} = $section;
178 my $monid = $param->{id
} // $param->{node
};
180 my $monsection = "mon.$monid";
181 my $pubnet = $cfg->{global
}->{'public network'};
182 my $ip = $find_mon_ip->($pubnet, $param->{node
}, $param->{'mon-address'});
184 my $monaddr = Net
::IP
::ip_is_ipv6
($ip) ?
"[$ip]:6789" : "$ip:6789";
185 my $monname = $param->{node
};
187 die "monitor '$monsection' already exists\n" if $cfg->{$monsection};
188 die "monitor address '$monaddr' already in use by '$monaddrhash->{$monaddr}'\n"
189 if $monaddrhash->{$monaddr};
194 my $pve_ckeyring_path = PVE
::Ceph
::Tools
::get_config
('pve_ckeyring_path');
196 if (! -f
$pve_ckeyring_path) {
197 run_command
("ceph-authtool $pve_ckeyring_path --create-keyring " .
198 "--gen-key -n client.admin");
201 my $pve_mon_key_path = PVE
::Ceph
::Tools
::get_config
('pve_mon_key_path');
202 if (! -f
$pve_mon_key_path) {
203 run_command
("cp $pve_ckeyring_path $pve_mon_key_path.tmp");
204 run_command
("ceph-authtool $pve_mon_key_path.tmp -n client.admin " .
205 "--cap mds 'allow' " .
206 "--cap osd 'allow *' " .
207 "--cap mgr 'allow *' " .
208 "--cap mon 'allow *'");
209 run_command
("cp $pve_mon_key_path.tmp /etc/ceph/ceph.client.admin.keyring");
210 run_command
("chown ceph:ceph /etc/ceph/ceph.client.admin.keyring");
211 run_command
("ceph-authtool $pve_mon_key_path.tmp --gen-key -n mon. --cap mon 'allow *'");
212 run_command
("mv $pve_mon_key_path.tmp $pve_mon_key_path");
215 my $ccname = PVE
::Ceph
::Tools
::get_config
('ccname');
217 my $mondir = "/var/lib/ceph/mon/$ccname-$monid";
218 -d
$mondir && die "monitor filesystem '$mondir' already exist\n";
220 my $monmap = "/tmp/monmap";
225 run_command
("chown ceph:ceph $mondir");
228 my $rados = PVE
::RADOS-
>new(timeout
=> PVE
::Ceph
::Tools
::get_config
('long_rados_timeout'));
229 my $mapdata = $rados->mon_command({ prefix
=> 'mon getmap', format
=> 'plain' });
230 file_set_contents
($monmap, $mapdata);
232 run_command
("monmaptool --create --clobber --add $monid $monaddr --print $monmap");
235 run_command
("ceph-mon --mkfs -i $monid --monmap $monmap --keyring $pve_mon_key_path");
236 run_command
("chown ceph:ceph -R $mondir");
241 File
::Path
::remove_tree
($mondir);
245 $cfg->{$monsection} = {
247 'mon addr' => $monaddr,
250 cfs_write_file
('ceph.conf', $cfg);
252 my $create_keys_pid = fork();
253 if (!defined($create_keys_pid)) {
254 die "Could not spawn ceph-create-keys to create bootstrap keys\n";
255 } elsif ($create_keys_pid == 0) {
256 exit PVE
::Tools
::run_command
(['ceph-create-keys', '-i', $monid]);
258 PVE
::Ceph
::Services
::ceph_service_cmd
('start', $monsection);
260 # to ensure we have the correct startup order.
261 eval { run_command
(['/bin/systemctl', 'enable', "ceph-mon\@${monid}.service"]) };
262 warn "Enable ceph-mon\@${monid}.service failed, do manually: $@\n" if $@;
263 waitpid($create_keys_pid, 0);
267 if (!$param->{'exclude-manager'}) {
268 my $rados = PVE
::RADOS-
>new(timeout
=> PVE
::Ceph
::Tools
::get_config
('long_rados_timeout'));
269 PVE
::Ceph
::Services
::create_mgr
($monid, $rados);
271 PVE
::Ceph
::Services
::broadcast_ceph_services
();
274 return $rpcenv->fork_worker('cephcreatemon', $monsection, $authuser, $worker);
277 __PACKAGE__-
>register_method ({
278 name
=> 'destroymon',
281 description
=> "Destroy Ceph Monitor and Manager.",
285 check
=> ['perm', '/', [ 'Sys.Modify' ]],
288 additionalProperties
=> 0,
290 node
=> get_standard_option
('pve-node'),
292 description
=> 'Monitor ID',
294 pattern
=> '[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?',
296 'exclude-manager' => {
300 description
=> "When set, removes only the monitor, not the manager"
304 returns
=> { type
=> 'string' },
308 my $rpcenv = PVE
::RPCEnvironment
::get
();
310 my $authuser = $rpcenv->get_user();
312 PVE
::Ceph
::Tools
::check_ceph_inited
();
314 my $cfg = cfs_read_file
('ceph.conf');
316 my $monid = $param->{monid
};
317 my $monsection = "mon.$monid";
319 my $rados = PVE
::RADOS-
>new();
320 my $monstat = $rados->mon_command({ prefix
=> 'mon_status' });
321 my $monlist = $monstat->{monmap
}->{mons
};
323 die "no such monitor id '$monid'\n"
324 if !defined($cfg->{$monsection});
326 my $ccname = PVE
::Ceph
::Tools
::get_config
('ccname');
328 my $mondir = "/var/lib/ceph/mon/$ccname-$monid";
329 -d
$mondir || die "monitor filesystem '$mondir' does not exist on this node\n";
331 die "can't remove last monitor\n" if scalar(@$monlist) <= 1;
336 # reopen with longer timeout
337 $rados = PVE
::RADOS-
>new(timeout
=> PVE
::Ceph
::Tools
::get_config
('long_rados_timeout'));
339 $rados->mon_command({ prefix
=> "mon remove", name
=> $monid, format
=> 'plain' });
341 eval { PVE
::Ceph
::Services
::ceph_service_cmd
('stop', $monsection); };
344 delete $cfg->{$monsection};
345 cfs_write_file
('ceph.conf', $cfg);
346 File
::Path
::remove_tree
($mondir);
349 if (!$param->{'exclude-manager'}) {
350 eval { PVE
::Ceph
::Services
::destroy_mgr
($monid) };
353 PVE
::Ceph
::Services
::broadcast_ceph_services
();
356 return $rpcenv->fork_worker('cephdestroymon', $monsection, $authuser, $worker);