]> git.proxmox.com Git - pve-manager.git/blob - PVE/API2/Cluster/Ceph.pm
ceph: factor out get/broadcast ceph versions to ceph::services
[pve-manager.git] / PVE / API2 / Cluster / Ceph.pm
1 package PVE::API2::Cluster::Ceph;
2
3 use strict;
4 use warnings;
5
6 use JSON;
7
8 use PVE::Ceph::Services;
9 use PVE::Ceph::Tools;
10 use PVE::Cluster;
11 use PVE::Exception qw(raise_param_exc);
12 use PVE::JSONSchema qw(get_standard_option);
13 use PVE::RADOS;
14 use PVE::RESTHandler;
15 use PVE::SafeSyslog;
16 use PVE::Tools qw(extract_param);
17
18 use base qw(PVE::RESTHandler);
19
20 __PACKAGE__->register_method ({
21 name => 'cephindex',
22 path => '',
23 method => 'GET',
24 description => "Cluster ceph index.",
25 permissions => { user => 'all' },
26 parameters => {
27 additionalProperties => 0,
28 properties => {},
29 },
30 returns => {
31 type => 'array',
32 items => {
33 type => "object",
34 properties => {},
35 },
36 links => [ { rel => 'child', href => "{name}" } ],
37 },
38 code => sub {
39 my ($param) = @_;
40
41 my $result = [
42 { name => 'metadata' },
43 { name => 'status' },
44 { name => 'flags' },
45 ];
46
47 return $result;
48 }
49 });
50
51 __PACKAGE__->register_method ({
52 name => 'metadata',
53 path => 'metadata',
54 method => 'GET',
55 description => "Get ceph metadata.",
56 protected => 1,
57 permissions => {
58 check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1],
59 },
60 parameters => {
61 additionalProperties => 0,
62 properties => {},
63 },
64 returns => { type => 'object' },
65 code => sub {
66 my ($param) = @_;
67
68 PVE::Ceph::Tools::check_ceph_inited();
69
70 my $rados = PVE::RADOS->new();
71
72 my $res = {
73 # FIXME: remove with 7.0 depreacated by structured 'versions'
74 version => PVE::Cluster::get_node_kv("ceph-version"),
75 };
76
77 if (defined(my $vers = PVE::Ceph::Services::get_ceph_versions())) {
78 $res->{node} = $vers;
79 }
80
81 for my $type ( qw(mon mgr mds) ) {
82 my $typedata = PVE::Ceph::Services::get_cluster_service($type);
83 my $data = {};
84 for my $host (sort keys %$typedata) {
85 for my $service (sort keys %{$typedata->{$host}}) {
86 $data->{"$service\@$host"} = $typedata->{$host}->{$service};
87 }
88 }
89
90 # get data from metadata call and merge 'our' data
91 my $services = $rados->mon_command({ prefix => "$type metadata" });
92 for my $service ( @$services ) {
93 my $hostname = $service->{hostname};
94 next if !defined($hostname); # can happen if node is dead
95
96 my $servicename = $service->{name} // $service->{id};
97 my $id = "$servicename\@$hostname";
98
99 if ($data->{$id}) { # copy values over to the metadata hash
100 for my $k (keys %{$data->{$id}}) {
101 $service->{$k} = $data->{$id}->{$k};
102 }
103 }
104 $data->{$id} = $service;
105 }
106
107 $res->{$type} = $data;
108 }
109
110 $res->{osd} = $rados->mon_command({ prefix => "osd metadata" });
111
112 return $res;
113 }
114 });
115
116 __PACKAGE__->register_method ({
117 name => 'status',
118 path => 'status',
119 method => 'GET',
120 description => "Get ceph status.",
121 protected => 1,
122 permissions => {
123 check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1],
124 },
125 parameters => {
126 additionalProperties => 0,
127 properties => { },
128 },
129 returns => { type => 'object' },
130 code => sub {
131 my ($param) = @_;
132
133 PVE::Ceph::Tools::check_ceph_inited();
134
135 my $rados = PVE::RADOS->new();
136 my $status = $rados->mon_command({ prefix => 'status' });
137 $status->{health} = $rados->mon_command({ prefix => 'health', detail => 'detail' });
138 return $status;
139 }
140 });
141
142 my $possible_flags = PVE::Ceph::Tools::get_possible_osd_flags();
143 my $possible_flags_list = [ sort keys %$possible_flags ];
144
145 my $get_current_set_flags = sub {
146 my $rados = shift;
147
148 $rados //= PVE::RADOS->new();
149
150 my $stat = $rados->mon_command({ prefix => 'osd dump' });
151 my $setflags = $stat->{flags} // '';
152 return { map { $_ => 1 } PVE::Tools::split_list($setflags) };
153 };
154
155 __PACKAGE__->register_method ({
156 name => 'get_all_flags',
157 path => 'flags',
158 method => 'GET',
159 description => "get the status of all ceph flags",
160 protected => 1,
161 permissions => {
162 check => ['perm', '/', [ 'Sys.Audit' ]],
163 },
164 parameters => {
165 additionalProperties => 0,
166 properties => {
167 },
168 },
169 returns => {
170 type => 'array',
171 items => {
172 type => "object",
173 additionalProperties => 1,
174 properties => {
175 name => {
176 description => "Flag name.",
177 type => 'string', enum => $possible_flags_list,
178 },
179 },
180 },
181 links => [ { rel => 'child', href => "{name}" } ],
182 },
183 code => sub {
184 my ($param) = @_;
185
186 PVE::Ceph::Tools::check_ceph_configured();
187
188 my $setflags = $get_current_set_flags->();
189
190 my $res = [];
191 foreach my $flag (@$possible_flags_list) {
192 my $el = {
193 name => $flag,
194 description => $possible_flags->{$flag}->{description},
195 value => 0,
196 };
197
198 my $realflag = PVE::Ceph::Tools::get_real_flag_name($flag);
199 if ($setflags->{$realflag}) {
200 $el->{value} = 1;
201 }
202
203 push @$res, $el;
204 }
205
206 return $res;
207 }
208 });
209
210 __PACKAGE__->register_method ({
211 name => 'set_flags',
212 path => 'flags',
213 method => 'PUT',
214 description => "Set/Unset multiple ceph flags at once.",
215 protected => 1,
216 permissions => {
217 check => ['perm', '/', [ 'Sys.Modify' ]],
218 },
219 parameters => {
220 additionalProperties => 0,
221 properties => $possible_flags,
222 },
223 returns => { type => 'string' },
224 code => sub {
225 my ($param) = @_;
226
227 my $rpcenv = PVE::RPCEnvironment::get();
228 my $user = $rpcenv->get_user();
229 PVE::Ceph::Tools::check_ceph_configured();
230
231 my $worker = sub {
232 my $rados = PVE::RADOS->new(); # (re-)open for forked worker
233
234 my $setflags = $get_current_set_flags->($rados);
235
236 my $errors = 0;
237 foreach my $flag (@$possible_flags_list) {
238 next if !defined($param->{$flag});
239 my $val = $param->{$flag};
240 my $realflag = PVE::Ceph::Tools::get_real_flag_name($flag);
241
242 next if !$val == !$setflags->{$realflag}; # we do not set/unset flags to the same state
243
244 my $prefix = $val ? 'set' : 'unset';
245 eval {
246 print "$prefix $flag\n";
247 $rados->mon_command({ prefix => "osd $prefix", key => $flag, });
248 };
249 if (my $err = $@) {
250 warn "error with $flag: '$err'\n";
251 $errors++;
252 }
253 }
254
255 if ($errors) {
256 die "could not set/unset $errors flags\n";
257 }
258 };
259
260 return $rpcenv->fork_worker('cephsetflags', undef, $user, $worker);
261 }});
262
263
264 __PACKAGE__->register_method ({
265 name => 'get_flag',
266 path => 'flags/{flag}',
267 method => 'GET',
268 description => "Get the status of a specific ceph flag.",
269 protected => 1,
270 permissions => {
271 check => ['perm', '/', [ 'Sys.Audit' ]],
272 },
273 parameters => {
274 additionalProperties => 0,
275 properties => {
276 flag => {
277 description => "The name of the flag name to get.",
278 type => 'string', enum => $possible_flags_list,
279 },
280 },
281 },
282 returns => {
283 type => 'boolean',
284 },
285 code => sub {
286 my ($param) = @_;
287
288 PVE::Ceph::Tools::check_ceph_configured();
289
290 my $realflag = PVE::Ceph::Tools::get_real_flag_name($param->{flag});
291
292 my $setflags = $get_current_set_flags->();
293 if ($setflags->{$realflag}) {
294 return 1;
295 }
296
297 return 0;
298 }});
299
300 __PACKAGE__->register_method ({
301 name => 'update_flag',
302 path => 'flags/{flag}',
303 method => 'PUT',
304 description => "Set or clear (unset) a specific ceph flag",
305 protected => 1,
306 permissions => {
307 check => ['perm', '/', [ 'Sys.Modify' ]],
308 },
309 parameters => {
310 additionalProperties => 0,
311 properties => {
312 flag => {
313 description => 'The ceph flag to update',
314 type => 'string',
315 enum => $possible_flags_list,
316 },
317 value => {
318 description => 'The new value of the flag',
319 type => 'boolean',
320 },
321 },
322 },
323 returns => { type => 'null' },
324 code => sub {
325 my ($param) = @_;
326
327 PVE::Ceph::Tools::check_ceph_configured();
328
329 my $cmd = $param->{value} ? 'set' : 'unset';
330
331 my $rados = PVE::RADOS->new();
332 $rados->mon_command({
333 prefix => "osd $cmd",
334 key => $param->{flag},
335 });
336
337 return undef;
338 }});
339
340
341 1;