]>
Commit | Line | Data |
---|---|---|
7d4fc5ef DM |
1 | package PVE::API2::Ceph; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
0cd34b00 | 5 | |
7d4fc5ef | 6 | use File::Path; |
7d4fc5ef | 7 | use Net::IP; |
0cd34b00 | 8 | use UUID; |
7d4fc5ef | 9 | |
6fb08cb9 | 10 | use PVE::Ceph::Tools; |
27439be6 | 11 | use PVE::Ceph::Services; |
c31f487e | 12 | use PVE::Cluster qw(cfs_read_file cfs_write_file); |
0cd34b00 | 13 | use PVE::JSONSchema qw(get_standard_option); |
9f4ff798 | 14 | use PVE::Network; |
0cd34b00 TL |
15 | use PVE::RADOS; |
16 | use PVE::RESTHandler; | |
17 | use PVE::RPCEnvironment; | |
18 | use PVE::Storage; | |
063b6d5e | 19 | use PVE::Tools qw(run_command file_get_contents file_set_contents extract_param); |
7d4fc5ef | 20 | |
26cf20bc | 21 | use PVE::API2::Ceph::Cfg; |
79fa41a2 | 22 | use PVE::API2::Ceph::OSD; |
7e1a9d25 | 23 | use PVE::API2::Ceph::FS; |
b82649cc | 24 | use PVE::API2::Ceph::MDS; |
4fec2764 | 25 | use PVE::API2::Ceph::MGR; |
98fe93ae | 26 | use PVE::API2::Ceph::MON; |
b2e005d7 | 27 | use PVE::API2::Ceph::Pool; |
0cd34b00 | 28 | use PVE::API2::Storage::Config; |
7d4fc5ef | 29 | |
0cd34b00 | 30 | use base qw(PVE::RESTHandler); |
7d4fc5ef DM |
31 | |
32 | my $pve_osd_default_journal_size = 1024*5; | |
33 | ||
26cf20bc AL |
34 | __PACKAGE__->register_method ({ |
35 | subclass => "PVE::API2::Ceph::Cfg", | |
36 | path => 'cfg', | |
37 | }); | |
38 | ||
7d4fc5ef | 39 | __PACKAGE__->register_method ({ |
79fa41a2 | 40 | subclass => "PVE::API2::Ceph::OSD", |
7d4fc5ef DM |
41 | path => 'osd', |
42 | }); | |
43 | ||
b82649cc TL |
44 | __PACKAGE__->register_method ({ |
45 | subclass => "PVE::API2::Ceph::MDS", | |
46 | path => 'mds', | |
47 | }); | |
48 | ||
4fec2764 DC |
49 | __PACKAGE__->register_method ({ |
50 | subclass => "PVE::API2::Ceph::MGR", | |
51 | path => 'mgr', | |
52 | }); | |
53 | ||
98fe93ae DC |
54 | __PACKAGE__->register_method ({ |
55 | subclass => "PVE::API2::Ceph::MON", | |
56 | path => 'mon', | |
57 | }); | |
58 | ||
7e1a9d25 TL |
59 | __PACKAGE__->register_method ({ |
60 | subclass => "PVE::API2::Ceph::FS", | |
61 | path => 'fs', | |
62 | }); | |
63 | ||
b2e005d7 AL |
64 | __PACKAGE__->register_method ({ |
65 | subclass => "PVE::API2::Ceph::Pool", | |
66 | path => 'pool', | |
67 | }); | |
68 | ||
7d4fc5ef DM |
69 | __PACKAGE__->register_method ({ |
70 | name => 'index', | |
71 | path => '', | |
72 | method => 'GET', | |
73 | description => "Directory index.", | |
74 | permissions => { user => 'all' }, | |
90c75580 TL |
75 | permissions => { |
76 | check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1], | |
77 | }, | |
7d4fc5ef | 78 | parameters => { |
be753927 | 79 | additionalProperties => 0, |
7d4fc5ef DM |
80 | properties => { |
81 | node => get_standard_option('pve-node'), | |
82 | }, | |
83 | }, | |
84 | returns => { | |
85 | type => 'array', | |
86 | items => { | |
87 | type => "object", | |
88 | properties => {}, | |
89 | }, | |
90 | links => [ { rel => 'child', href => "{name}" } ], | |
91 | }, | |
92 | code => sub { | |
93 | my ($param) = @_; | |
94 | ||
95 | my $result = [ | |
56b03211 | 96 | { name => 'cmd-safety' }, |
26cf20bc | 97 | { name => 'cfg' }, |
56b03211 AL |
98 | { name => 'crush' }, |
99 | { name => 'fs' }, | |
7d4fc5ef | 100 | { name => 'init' }, |
56b03211 AL |
101 | { name => 'log' }, |
102 | { name => 'mds' }, | |
103 | { name => 'mgr' }, | |
7d4fc5ef DM |
104 | { name => 'mon' }, |
105 | { name => 'osd' }, | |
f507ec30 | 106 | { name => 'pool' }, |
2d7d6c9a | 107 | { name => 'restart' }, |
d2692b86 | 108 | { name => 'rules' }, |
56b03211 AL |
109 | { name => 'start' }, |
110 | { name => 'status' }, | |
111 | { name => 'stop' }, | |
7d4fc5ef DM |
112 | ]; |
113 | ||
114 | return $result; | |
115 | }}); | |
116 | ||
7d4fc5ef DM |
117 | __PACKAGE__->register_method ({ |
118 | name => 'init', | |
119 | path => 'init', | |
120 | method => 'POST', | |
121 | description => "Create initial ceph default configuration and setup symlinks.", | |
122 | proxyto => 'node', | |
123 | protected => 1, | |
90c75580 TL |
124 | permissions => { |
125 | check => ['perm', '/', [ 'Sys.Modify' ]], | |
126 | }, | |
7d4fc5ef | 127 | parameters => { |
be753927 | 128 | additionalProperties => 0, |
7d4fc5ef DM |
129 | properties => { |
130 | node => get_standard_option('pve-node'), | |
131 | network => { | |
be753927 | 132 | description => "Use specific network for all ceph related traffic", |
7d4fc5ef DM |
133 | type => 'string', format => 'CIDR', |
134 | optional => 1, | |
135 | maxLength => 128, | |
136 | }, | |
7519b848 TL |
137 | 'cluster-network' => { |
138 | description => "Declare a separate cluster network, OSDs will route" . | |
139 | "heartbeat, object replication and recovery traffic over it", | |
140 | type => 'string', format => 'CIDR', | |
141 | requires => 'network', | |
142 | optional => 1, | |
143 | maxLength => 128, | |
144 | }, | |
7d4fc5ef | 145 | size => { |
207f4932 FG |
146 | description => 'Targeted number of replicas per object', |
147 | type => 'integer', | |
148 | default => 3, | |
149 | optional => 1, | |
150 | minimum => 1, | |
151 | maximum => 7, | |
152 | }, | |
153 | min_size => { | |
154 | description => 'Minimum number of available replicas per object to allow I/O', | |
7d4fc5ef DM |
155 | type => 'integer', |
156 | default => 2, | |
157 | optional => 1, | |
158 | minimum => 1, | |
83663637 | 159 | maximum => 7, |
7d4fc5ef DM |
160 | }, |
161 | pg_bits => { | |
3cba09d5 FG |
162 | description => "Placement group bits, used to specify the " . |
163 | "default number of placement groups.\n\nNOTE: 'osd pool " . | |
164 | "default pg num' does not work for default pools.", | |
7d4fc5ef DM |
165 | type => 'integer', |
166 | default => 6, | |
167 | optional => 1, | |
168 | minimum => 6, | |
169 | maximum => 14, | |
170 | }, | |
4280f25c | 171 | disable_cephx => { |
76189130 | 172 | description => "Disable cephx authentication.\n\n" . |
97f050bb FG |
173 | "WARNING: cephx is a security feature protecting against " . |
174 | "man-in-the-middle attacks. Only consider disabling cephx ". | |
175 | "if your network is private!", | |
77bb90b0 AD |
176 | type => 'boolean', |
177 | optional => 1, | |
178 | default => 0, | |
4280f25c | 179 | }, |
7d4fc5ef DM |
180 | }, |
181 | }, | |
182 | returns => { type => 'null' }, | |
183 | code => sub { | |
184 | my ($param) = @_; | |
185 | ||
6fb08cb9 | 186 | my $version = PVE::Ceph::Tools::get_local_version(1); |
c64c04dd | 187 | |
b3d8b5f5 DC |
188 | if (!$version || $version < 14) { |
189 | die "Ceph Nautilus required - please run 'pveceph install'\n"; | |
c64c04dd | 190 | } else { |
6fb08cb9 | 191 | PVE::Ceph::Tools::check_ceph_installed('ceph_bin'); |
c64c04dd | 192 | } |
7d4fc5ef | 193 | |
50d5fd6a FG |
194 | my $auth = $param->{disable_cephx} ? 'none' : 'cephx'; |
195 | ||
7d4fc5ef | 196 | # simply load old config if it already exists |
3e4c0f06 DC |
197 | PVE::Cluster::cfs_lock_file('ceph.conf', undef, sub { |
198 | my $cfg = cfs_read_file('ceph.conf'); | |
7d4fc5ef | 199 | |
3e4c0f06 | 200 | if (!$cfg->{global}) { |
7d4fc5ef | 201 | |
3e4c0f06 DC |
202 | my $fsid; |
203 | my $uuid; | |
7d4fc5ef | 204 | |
3e4c0f06 DC |
205 | UUID::generate($uuid); |
206 | UUID::unparse($uuid, $fsid); | |
7d4fc5ef | 207 | |
3e4c0f06 DC |
208 | $cfg->{global} = { |
209 | 'fsid' => $fsid, | |
210 | 'auth cluster required' => $auth, | |
211 | 'auth service required' => $auth, | |
212 | 'auth client required' => $auth, | |
213 | 'osd pool default size' => $param->{size} // 3, | |
214 | 'osd pool default min size' => $param->{min_size} // 2, | |
215 | 'mon allow pool delete' => 'true', | |
216 | }; | |
7d4fc5ef | 217 | |
3e4c0f06 DC |
218 | # this does not work for default pools |
219 | #'osd pool default pg num' => $pg_num, | |
220 | #'osd pool default pgp num' => $pg_num, | |
221 | } | |
be753927 | 222 | |
d851d63e DC |
223 | if ($auth eq 'cephx') { |
224 | $cfg->{client}->{keyring} = '/etc/pve/priv/$cluster.$name.keyring'; | |
225 | } | |
7d4fc5ef | 226 | |
3e4c0f06 DC |
227 | if ($param->{pg_bits}) { |
228 | $cfg->{global}->{'osd pg bits'} = $param->{pg_bits}; | |
229 | $cfg->{global}->{'osd pgp bits'} = $param->{pg_bits}; | |
230 | } | |
7d4fc5ef | 231 | |
3e4c0f06 DC |
232 | if ($param->{network}) { |
233 | $cfg->{global}->{'public network'} = $param->{network}; | |
234 | $cfg->{global}->{'cluster network'} = $param->{network}; | |
235 | } | |
7d4fc5ef | 236 | |
3e4c0f06 DC |
237 | if ($param->{'cluster-network'}) { |
238 | $cfg->{global}->{'cluster network'} = $param->{'cluster-network'}; | |
239 | } | |
7519b848 | 240 | |
3e4c0f06 | 241 | cfs_write_file('ceph.conf', $cfg); |
7d4fc5ef | 242 | |
d851d63e DC |
243 | if ($auth eq 'cephx') { |
244 | PVE::Ceph::Tools::get_or_create_admin_keyring(); | |
245 | } | |
3e4c0f06 DC |
246 | PVE::Ceph::Tools::setup_pve_symlinks(); |
247 | }); | |
8e2b5110 | 248 | die $@ if $@; |
7d4fc5ef DM |
249 | |
250 | return undef; | |
251 | }}); | |
252 | ||
38db610a DM |
253 | __PACKAGE__->register_method ({ |
254 | name => 'stop', | |
255 | path => 'stop', | |
256 | method => 'POST', | |
257 | description => "Stop ceph services.", | |
258 | proxyto => 'node', | |
259 | protected => 1, | |
90c75580 TL |
260 | permissions => { |
261 | check => ['perm', '/', [ 'Sys.Modify' ]], | |
262 | }, | |
38db610a | 263 | parameters => { |
be753927 | 264 | additionalProperties => 0, |
38db610a DM |
265 | properties => { |
266 | node => get_standard_option('pve-node'), | |
68e0c4bd DM |
267 | service => { |
268 | description => 'Ceph service name.', | |
269 | type => 'string', | |
270 | optional => 1, | |
33a9c70a | 271 | default => 'ceph.target', |
7e98f79e | 272 | pattern => '(ceph|mon|mds|osd|mgr)(\.'.PVE::Ceph::Services::SERVICE_REGEX.')?', |
68e0c4bd | 273 | }, |
38db610a DM |
274 | }, |
275 | }, | |
68e0c4bd | 276 | returns => { type => 'string' }, |
38db610a DM |
277 | code => sub { |
278 | my ($param) = @_; | |
279 | ||
68e0c4bd DM |
280 | my $rpcenv = PVE::RPCEnvironment::get(); |
281 | ||
282 | my $authuser = $rpcenv->get_user(); | |
283 | ||
6fb08cb9 | 284 | PVE::Ceph::Tools::check_ceph_inited(); |
38db610a | 285 | |
c31f487e | 286 | my $cfg = cfs_read_file('ceph.conf'); |
38db610a DM |
287 | scalar(keys %$cfg) || die "no configuration\n"; |
288 | ||
68e0c4bd DM |
289 | my $worker = sub { |
290 | my $upid = shift; | |
38db610a | 291 | |
68e0c4bd DM |
292 | my $cmd = ['stop']; |
293 | if ($param->{service}) { | |
294 | push @$cmd, $param->{service}; | |
295 | } | |
296 | ||
27439be6 | 297 | PVE::Ceph::Services::ceph_service_cmd(@$cmd); |
68e0c4bd DM |
298 | }; |
299 | ||
300 | return $rpcenv->fork_worker('srvstop', $param->{service} || 'ceph', | |
301 | $authuser, $worker); | |
38db610a DM |
302 | }}); |
303 | ||
304 | __PACKAGE__->register_method ({ | |
305 | name => 'start', | |
306 | path => 'start', | |
307 | method => 'POST', | |
308 | description => "Start ceph services.", | |
309 | proxyto => 'node', | |
310 | protected => 1, | |
90c75580 TL |
311 | permissions => { |
312 | check => ['perm', '/', [ 'Sys.Modify' ]], | |
313 | }, | |
38db610a | 314 | parameters => { |
be753927 | 315 | additionalProperties => 0, |
38db610a DM |
316 | properties => { |
317 | node => get_standard_option('pve-node'), | |
68e0c4bd DM |
318 | service => { |
319 | description => 'Ceph service name.', | |
320 | type => 'string', | |
321 | optional => 1, | |
33a9c70a | 322 | default => 'ceph.target', |
7e98f79e | 323 | pattern => '(ceph|mon|mds|osd|mgr)(\.'.PVE::Ceph::Services::SERVICE_REGEX.')?', |
68e0c4bd | 324 | }, |
38db610a DM |
325 | }, |
326 | }, | |
68e0c4bd | 327 | returns => { type => 'string' }, |
38db610a DM |
328 | code => sub { |
329 | my ($param) = @_; | |
330 | ||
68e0c4bd DM |
331 | my $rpcenv = PVE::RPCEnvironment::get(); |
332 | ||
333 | my $authuser = $rpcenv->get_user(); | |
334 | ||
6fb08cb9 | 335 | PVE::Ceph::Tools::check_ceph_inited(); |
38db610a | 336 | |
c31f487e | 337 | my $cfg = cfs_read_file('ceph.conf'); |
38db610a DM |
338 | scalar(keys %$cfg) || die "no configuration\n"; |
339 | ||
68e0c4bd DM |
340 | my $worker = sub { |
341 | my $upid = shift; | |
38db610a | 342 | |
68e0c4bd DM |
343 | my $cmd = ['start']; |
344 | if ($param->{service}) { | |
345 | push @$cmd, $param->{service}; | |
346 | } | |
347 | ||
27439be6 | 348 | PVE::Ceph::Services::ceph_service_cmd(@$cmd); |
68e0c4bd DM |
349 | }; |
350 | ||
351 | return $rpcenv->fork_worker('srvstart', $param->{service} || 'ceph', | |
352 | $authuser, $worker); | |
38db610a DM |
353 | }}); |
354 | ||
342c0830 DC |
355 | __PACKAGE__->register_method ({ |
356 | name => 'restart', | |
357 | path => 'restart', | |
358 | method => 'POST', | |
359 | description => "Restart ceph services.", | |
360 | proxyto => 'node', | |
361 | protected => 1, | |
362 | permissions => { | |
363 | check => ['perm', '/', [ 'Sys.Modify' ]], | |
364 | }, | |
365 | parameters => { | |
366 | additionalProperties => 0, | |
367 | properties => { | |
368 | node => get_standard_option('pve-node'), | |
369 | service => { | |
370 | description => 'Ceph service name.', | |
371 | type => 'string', | |
372 | optional => 1, | |
33a9c70a | 373 | default => 'ceph.target', |
7e98f79e | 374 | pattern => '(mon|mds|osd|mgr)(\.'.PVE::Ceph::Services::SERVICE_REGEX.')?', |
342c0830 DC |
375 | }, |
376 | }, | |
377 | }, | |
378 | returns => { type => 'string' }, | |
379 | code => sub { | |
380 | my ($param) = @_; | |
381 | ||
382 | my $rpcenv = PVE::RPCEnvironment::get(); | |
383 | ||
384 | my $authuser = $rpcenv->get_user(); | |
385 | ||
6fb08cb9 | 386 | PVE::Ceph::Tools::check_ceph_inited(); |
342c0830 | 387 | |
c31f487e | 388 | my $cfg = cfs_read_file('ceph.conf'); |
342c0830 DC |
389 | scalar(keys %$cfg) || die "no configuration\n"; |
390 | ||
391 | my $worker = sub { | |
392 | my $upid = shift; | |
393 | ||
394 | my $cmd = ['restart']; | |
395 | if ($param->{service}) { | |
396 | push @$cmd, $param->{service}; | |
397 | } | |
398 | ||
27439be6 | 399 | PVE::Ceph::Services::ceph_service_cmd(@$cmd); |
342c0830 DC |
400 | }; |
401 | ||
402 | return $rpcenv->fork_worker('srvrestart', $param->{service} || 'ceph', | |
403 | $authuser, $worker); | |
404 | }}); | |
405 | ||
38db610a DM |
406 | __PACKAGE__->register_method ({ |
407 | name => 'status', | |
408 | path => 'status', | |
409 | method => 'GET', | |
410 | description => "Get ceph status.", | |
411 | proxyto => 'node', | |
412 | protected => 1, | |
90c75580 TL |
413 | permissions => { |
414 | check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1], | |
415 | }, | |
38db610a | 416 | parameters => { |
be753927 | 417 | additionalProperties => 0, |
38db610a DM |
418 | properties => { |
419 | node => get_standard_option('pve-node'), | |
420 | }, | |
421 | }, | |
422 | returns => { type => 'object' }, | |
423 | code => sub { | |
424 | my ($param) = @_; | |
425 | ||
0cfc6856 | 426 | PVE::Ceph::Tools::check_ceph_inited(); |
38db610a | 427 | |
e25dda25 | 428 | return PVE::Ceph::Tools::ceph_cluster_status(); |
38db610a DM |
429 | }}); |
430 | ||
38db610a | 431 | |
2f692121 DM |
432 | __PACKAGE__->register_method ({ |
433 | name => 'crush', | |
434 | path => 'crush', | |
435 | method => 'GET', | |
436 | description => "Get OSD crush map", | |
437 | proxyto => 'node', | |
438 | protected => 1, | |
90c75580 TL |
439 | permissions => { |
440 | check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1], | |
441 | }, | |
2f692121 | 442 | parameters => { |
be753927 | 443 | additionalProperties => 0, |
2f692121 DM |
444 | properties => { |
445 | node => get_standard_option('pve-node'), | |
446 | }, | |
447 | }, | |
448 | returns => { type => 'string' }, | |
449 | code => sub { | |
450 | my ($param) = @_; | |
451 | ||
6fb08cb9 | 452 | PVE::Ceph::Tools::check_ceph_inited(); |
2f692121 | 453 | |
8b336060 DM |
454 | # this produces JSON (difficult to read for the user) |
455 | # my $txt = &$run_ceph_cmd_text(['osd', 'crush', 'dump'], quiet => 1); | |
2f692121 | 456 | |
8b336060 DM |
457 | my $txt = ''; |
458 | ||
459 | my $mapfile = "/var/tmp/ceph-crush.map.$$"; | |
460 | my $mapdata = "/var/tmp/ceph-crush.txt.$$"; | |
461 | ||
36fd0190 | 462 | my $rados = PVE::RADOS->new(); |
be753927 | 463 | |
8b336060 | 464 | eval { |
970236b3 | 465 | my $bindata = $rados->mon_command({ prefix => 'osd getcrushmap', format => 'plain' }); |
400742e4 | 466 | file_set_contents($mapfile, $bindata); |
8b336060 | 467 | run_command(['crushtool', '-d', $mapfile, '-o', $mapdata]); |
400742e4 | 468 | $txt = file_get_contents($mapdata); |
8b336060 DM |
469 | }; |
470 | my $err = $@; | |
471 | ||
472 | unlink $mapfile; | |
473 | unlink $mapdata; | |
474 | ||
475 | die $err if $err; | |
be753927 | 476 | |
2f692121 DM |
477 | return $txt; |
478 | }}); | |
479 | ||
570278fa | 480 | __PACKAGE__->register_method({ |
be753927 DC |
481 | name => 'log', |
482 | path => 'log', | |
570278fa DM |
483 | method => 'GET', |
484 | description => "Read ceph log", | |
485 | proxyto => 'node', | |
486 | permissions => { | |
487 | check => ['perm', '/nodes/{node}', [ 'Sys.Syslog' ]], | |
488 | }, | |
489 | protected => 1, | |
490 | parameters => { | |
be753927 | 491 | additionalProperties => 0, |
570278fa DM |
492 | properties => { |
493 | node => get_standard_option('pve-node'), | |
494 | start => { | |
495 | type => 'integer', | |
496 | minimum => 0, | |
497 | optional => 1, | |
498 | }, | |
499 | limit => { | |
500 | type => 'integer', | |
501 | minimum => 0, | |
502 | optional => 1, | |
503 | }, | |
504 | }, | |
505 | }, | |
506 | returns => { | |
507 | type => 'array', | |
be753927 | 508 | items => { |
570278fa DM |
509 | type => "object", |
510 | properties => { | |
511 | n => { | |
512 | description=> "Line number", | |
513 | type=> 'integer', | |
514 | }, | |
515 | t => { | |
516 | description=> "Line text", | |
517 | type => 'string', | |
518 | } | |
519 | } | |
520 | } | |
521 | }, | |
522 | code => sub { | |
523 | my ($param) = @_; | |
c56d75b4 | 524 | |
6fb08cb9 | 525 | PVE::Ceph::Tools::check_ceph_inited(); |
570278fa DM |
526 | |
527 | my $rpcenv = PVE::RPCEnvironment::get(); | |
528 | my $user = $rpcenv->get_user(); | |
529 | my $node = $param->{node}; | |
530 | ||
531 | my $logfile = "/var/log/ceph/ceph.log"; | |
532 | my ($count, $lines) = PVE::Tools::dump_logfile($logfile, $param->{start}, $param->{limit}); | |
533 | ||
534 | $rpcenv->set_result_attrib('total', $count); | |
be753927 DC |
535 | |
536 | return $lines; | |
570278fa DM |
537 | }}); |
538 | ||
d2692b86 DC |
539 | __PACKAGE__->register_method ({ |
540 | name => 'rules', | |
541 | path => 'rules', | |
542 | method => 'GET', | |
543 | description => "List ceph rules.", | |
544 | proxyto => 'node', | |
545 | protected => 1, | |
546 | permissions => { | |
547 | check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1], | |
548 | }, | |
549 | parameters => { | |
550 | additionalProperties => 0, | |
551 | properties => { | |
552 | node => get_standard_option('pve-node'), | |
553 | }, | |
554 | }, | |
555 | returns => { | |
556 | type => 'array', | |
557 | items => { | |
558 | type => "object", | |
b62ba85a AL |
559 | properties => { |
560 | name => { | |
561 | description => "Name of the CRUSH rule.", | |
562 | type => "string", | |
563 | } | |
564 | }, | |
d2692b86 DC |
565 | }, |
566 | links => [ { rel => 'child', href => "{name}" } ], | |
567 | }, | |
568 | code => sub { | |
569 | my ($param) = @_; | |
570 | ||
6fb08cb9 | 571 | PVE::Ceph::Tools::check_ceph_inited(); |
2f692121 | 572 | |
d2692b86 DC |
573 | my $rados = PVE::RADOS->new(); |
574 | ||
575 | my $rules = $rados->mon_command({ prefix => 'osd crush rule ls' }); | |
576 | ||
577 | my $res = []; | |
578 | ||
579 | foreach my $rule (@$rules) { | |
580 | push @$res, { name => $rule }; | |
581 | } | |
582 | ||
583 | return $res; | |
584 | }}); | |
79fa41a2 | 585 | |
ccb281a7 AL |
586 | __PACKAGE__->register_method ({ |
587 | name => 'cmd_safety', | |
588 | path => 'cmd-safety', | |
589 | method => 'GET', | |
590 | description => "Heuristical check if it is safe to perform an action.", | |
591 | proxyto => 'node', | |
592 | protected => 1, | |
593 | permissions => { | |
136f5724 | 594 | check => ['perm', '/', [ 'Sys.Audit' ]], |
ccb281a7 AL |
595 | }, |
596 | parameters => { | |
597 | additionalProperties => 0, | |
598 | properties => { | |
599 | node => get_standard_option('pve-node'), | |
600 | service => { | |
601 | description => 'Service type', | |
602 | type => 'string', | |
603 | enum => ['osd', 'mon', 'mds'], | |
604 | }, | |
605 | id => { | |
606 | description => 'ID of the service', | |
607 | type => 'string', | |
608 | }, | |
609 | action => { | |
610 | description => 'Action to check', | |
611 | type => 'string', | |
612 | enum => ['stop', 'destroy'], | |
613 | }, | |
614 | }, | |
615 | }, | |
616 | returns => { | |
617 | type => 'object', | |
618 | properties => { | |
619 | safe => { | |
620 | type => 'boolean', | |
621 | description => 'If it is safe to run the command.', | |
622 | }, | |
623 | status => { | |
624 | type => 'string', | |
625 | optional => 1, | |
626 | description => 'Status message given by Ceph.' | |
627 | }, | |
628 | }, | |
629 | }, | |
630 | code => sub { | |
631 | my ($param) = @_; | |
632 | ||
633 | PVE::Ceph::Tools::check_ceph_inited(); | |
634 | ||
635 | my $id = $param->{id}; | |
636 | my $service = $param->{service}; | |
637 | my $action = $param->{action}; | |
638 | ||
639 | my $rados = PVE::RADOS->new(); | |
640 | ||
641 | my $supported_actions = { | |
642 | osd => { | |
643 | stop => 'ok-to-stop', | |
644 | destroy => 'safe-to-destroy', | |
645 | }, | |
646 | mon => { | |
647 | stop => 'ok-to-stop', | |
648 | destroy => 'ok-to-rm', | |
649 | }, | |
650 | mds => { | |
651 | stop => 'ok-to-stop', | |
652 | }, | |
653 | }; | |
654 | ||
655 | die "Service does not support this action: ${service}: ${action}\n" | |
656 | if !$supported_actions->{$service}->{$action}; | |
657 | ||
658 | my $result = { | |
659 | safe => 0, | |
660 | status => '', | |
661 | }; | |
662 | ||
663 | my $params = { | |
664 | prefix => "${service} $supported_actions->{$service}->{$action}", | |
665 | format => 'plain', | |
666 | }; | |
667 | if ($service eq 'mon' && $action eq 'destroy') { | |
668 | $params->{id} = $id; | |
669 | } else { | |
670 | $params->{ids} = [ $id ]; | |
671 | } | |
672 | ||
673 | $result = $rados->mon_cmd($params, 1); | |
674 | die $@ if $@; | |
675 | ||
676 | $result->{safe} = $result->{return_code} == 0 ? 1 : 0; | |
677 | $result->{status} = $result->{status_message}; | |
678 | ||
679 | return $result; | |
680 | }}); | |
681 | ||
79fa41a2 | 682 | 1; |