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