]> git.proxmox.com Git - pve-manager.git/blame - PVE/Ceph/Services.pm
ceph: remove unused variable assignment
[pve-manager.git] / PVE / Ceph / Services.pm
CommitLineData
27439be6
DC
1package PVE::Ceph::Services;
2
3use strict;
4use warnings;
5
6use PVE::Ceph::Tools;
d5373b7d 7use PVE::Cluster qw(cfs_read_file);
27439be6
DC
8use PVE::Tools qw(run_command);
9use PVE::RADOS;
10
4e76dbd7 11use JSON;
27439be6
DC
12use File::Path;
13
7e98f79e
DC
14use constant SERVICE_REGEX => '[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?';
15
ac4f971d 16# checks /etc/systemd/system/ceph-* to list all services, even if not running
74628668 17# also checks /var/lib/ceph/$type
23b20ae4
DC
18sub get_local_services {
19 my $res = {};
ac4f971d 20
23b20ae4
DC
21 for my $type (qw(mds mgr mon)) {
22 $res->{$type} = {};
ac4f971d 23
23b20ae4
DC
24 my $path = "/etc/systemd/system/ceph-$type.target.wants";
25 my $regex = "ceph-$type\@(.*)\.service";
26 PVE::Tools::dir_glob_foreach($path, $regex, sub {
27 my (undef, $id) = @_;
74628668
DC
28 $res->{$type}->{$id}->{service} = 1;
29 });
30
31 $path = "/var/lib/ceph/$type";
32 $regex = "([^-]+)-(.*)";
33 PVE::Tools::dir_glob_foreach($path, $regex, sub {
34 my (undef, $clustername, $id) = @_;
35 $res->{$type}->{$id}->{direxists} = 1;
23b20ae4
DC
36 });
37 }
38 return $res;
39}
40
4e76dbd7
DC
41sub broadcast_ceph_services {
42 my $services = get_local_services();
43
44 for my $type (keys %$services) {
45 my $data = encode_json($services->{$type});
46 PVE::Cluster::broadcast_node_kv("ceph-$type", $data);
47 }
48}
49
0496138e
DC
50sub broadcast_ceph_versions {
51 my ($version, $buildcommit, $vers_parts) = PVE::Ceph::Tools::get_local_version(1);
52
53 if ($version) {
54 # FIXME: remove with 7.0 - for backward compat only
55 PVE::Cluster::broadcast_node_kv("ceph-version", $version);
56
57 my $node_versions = {
58 version => {
59 str => $version,
60 parts => $vers_parts,
61 },
62 buildcommit => $buildcommit,
63 };
64 PVE::Cluster::broadcast_node_kv("ceph-versions", encode_json($node_versions));
65 }
66}
67
68sub get_ceph_versions {
69 my $res;
70
71 if (defined(my $vers = PVE::Cluster::get_node_kv("ceph-versions"))) {
72 $res = {
73 map { eval { $_ => decode_json($vers->{$_}) } } keys %$vers
74 };
75 }
76
77 return $res;
78}
79
4e76dbd7
DC
80sub get_cluster_service {
81 my ($type) = @_;
930c1d6a 82
4e76dbd7
DC
83 my $raw = PVE::Cluster::get_node_kv("ceph-$type");
84 my $res = {};
85
86 for my $host (keys %$raw) {
87 $res->{$host} = eval { decode_json($raw->{$host}) };
88 }
89
90 return $res;
91}
92
27439be6
DC
93sub ceph_service_cmd {
94 my ($action, $service) = @_;
95
7e98f79e 96 if ($service && $service =~ m/^(mon|osd|mds|mgr|radosgw)(\.(${\SERVICE_REGEX}))?$/) {
bba5c712 97 $service = defined($3) ? "ceph-$1\@$3" : "ceph-$1.target";
27439be6 98 } else {
bba5c712 99 $service = "ceph.target";
27439be6 100 }
bba5c712
TL
101
102 run_command(['/bin/systemctl', $action, $service]);
27439be6
DC
103}
104
d5373b7d
DC
105sub get_services_info {
106 my ($type, $cfg, $rados) = @_;
107
108 my $result = {};
109 my $services = get_cluster_service($type);
110
111 foreach my $host (sort keys %$services) {
9ecb3d10
TL
112 foreach my $id (sort keys %{$services->{$host}}) {
113 my $service = $result->{$id} = $services->{$host}->{$id};
114 $service->{host} = $host;
115 $service->{name} = $id;
116 $service->{state} = 'unknown';
117 if ($service->{service}) {
118 $service->{state} = 'stopped';
d5373b7d
DC
119 }
120 }
121 }
122
123 if (!$cfg) {
124 $cfg = cfs_read_file('ceph.conf');
125 }
126
127 foreach my $section (keys %$cfg) {
128 my $d = $cfg->{$section};
129 if ($section =~ m/^$type\.(\S+)$/) {
130 my $id = $1;
9ecb3d10 131 my $service = $result->{$id};
342de4e7 132 my $addr = $d->{"${type}_addr"} // $d->{public_addr} // $d->{host};
9ecb3d10
TL
133 $service->{name} //= $id;
134 $service->{addr} //= $addr;
135 $service->{state} //= 'unknown';
136 $service->{host} //= $d->{host};
d5373b7d
DC
137 }
138 }
139
140 if (!$rados) {
e7e61576 141 return $result;
d5373b7d 142 }
e7e61576 143
d5373b7d 144 my $metadata = $rados->mon_command({ prefix => "$type metadata" });
9ecb3d10 145 foreach my $info (@$metadata) {
46fb9c50
DC
146 my $id = $info->{name} // $info->{id};
147 my $service = $result->{$id};
9ecb3d10
TL
148 $service->{ceph_version_short} = $info->{ceph_version_short};
149 $service->{ceph_version} = $info->{ceph_version};
150 $service->{host} //= $info->{hostname};
151 $service->{addr} //= $info->{addr};
d5373b7d
DC
152 }
153
154 return $result;
155}
156
27439be6
DC
157# MDS
158
159sub list_local_mds_ids {
160 my $mds_list = [];
161 my $ceph_mds_data_dir = PVE::Ceph::Tools::get_config('ceph_mds_data_dir');
162 my $ccname = PVE::Ceph::Tools::get_config('ccname');
163
164 PVE::Tools::dir_glob_foreach($ceph_mds_data_dir, qr/$ccname-(\S+)/, sub {
165 my (undef, $mds_id) = @_;
166 push @$mds_list, $mds_id;
167 });
168
169 return $mds_list;
170}
171
172sub get_cluster_mds_state {
173 my ($rados) = @_;
174
175 my $mds_state = {};
176
177 if (!defined($rados)) {
178 $rados = PVE::RADOS->new();
179 }
180
181 my $add_state = sub {
182 my ($mds) = @_;
183
184 my $state = {};
185 $state->{addr} = $mds->{addr};
186 $state->{rank} = $mds->{rank};
187 $state->{standby_replay} = $mds->{standby_replay} ? 1 : 0;
188 $state->{state} = $mds->{state};
189
190 $mds_state->{$mds->{name}} = $state;
191 };
192
193 my $mds_dump = $rados->mon_command({ prefix => 'mds stat' });
194 my $fsmap = $mds_dump->{fsmap};
195
196
197 foreach my $mds (@{$fsmap->{standbys}}) {
198 $add_state->($mds);
199 }
200
201 my $fs_info = $fsmap->{filesystems}->[0];
202 my $active_mds = $fs_info->{mdsmap}->{info};
203
204 # normally there's only one active MDS, but we can have multiple active for
205 # different ranks (e.g., different cephs path hierarchy). So just add all.
206 foreach my $mds (values %$active_mds) {
207 $add_state->($mds);
208 }
209
210 return $mds_state;
211}
212
213sub is_any_mds_active {
214 my ($rados) = @_;
215
216 if (!defined($rados)) {
217 $rados = PVE::RADOS->new();
218 }
219
220 my $mds_dump = $rados->mon_command({ prefix => 'mds stat' });
221 my $fs = $mds_dump->{fsmap}->{filesystems};
222
223 if (!($fs && scalar(@$fs) > 0)) {
224 return undef;
225 }
226 my $active_mds = $fs->[0]->{mdsmap}->{info};
227
228 for my $mds (values %$active_mds) {
229 return 1 if $mds->{state} eq 'up:active';
230 }
231
232 return 0;
233}
234
235sub create_mds {
236 my ($id, $rados) = @_;
237
238 # `ceph fs status` fails with numeric only ID.
239 die "ID: $id, numeric only IDs are not supported\n"
240 if $id =~ /^\d+$/;
241
242 if (!defined($rados)) {
243 $rados = PVE::RADOS->new();
244 }
245
246 my $ccname = PVE::Ceph::Tools::get_config('ccname');
247 my $service_dir = "/var/lib/ceph/mds/$ccname-$id";
248 my $service_keyring = "$service_dir/keyring";
249 my $service_name = "mds.$id";
250
251 die "ceph MDS directory '$service_dir' already exists\n"
252 if -d $service_dir;
253
254 print "creating MDS directory '$service_dir'\n";
255 eval { File::Path::mkpath($service_dir) };
256 my $err = $@;
257 die "creation MDS directory '$service_dir' failed\n" if $err;
258
259 # http://docs.ceph.com/docs/luminous/install/manual-deployment/#adding-mds
260 my $priv = [
261 mon => 'allow profile mds',
262 osd => 'allow rwx',
263 mds => 'allow *',
264 ];
265
266 print "creating keys for '$service_name'\n";
267 my $output = $rados->mon_command({
268 prefix => 'auth get-or-create',
269 entity => $service_name,
270 caps => $priv,
271 format => 'plain',
272 });
273
274 PVE::Tools::file_set_contents($service_keyring, $output);
275
276 print "setting ceph as owner for service directory\n";
277 run_command(["chown", 'ceph:ceph', '-R', $service_dir]);
278
279 print "enabling service 'ceph-mds\@$id.service'\n";
280 ceph_service_cmd('enable', $service_name);
281 print "starting service 'ceph-mds\@$id.service'\n";
282 ceph_service_cmd('start', $service_name);
283
4e76dbd7
DC
284 broadcast_ceph_services();
285
27439be6
DC
286 return undef;
287};
288
289sub destroy_mds {
290 my ($id, $rados) = @_;
291
292 if (!defined($rados)) {
293 $rados = PVE::RADOS->new();
294 }
295
296 my $ccname = PVE::Ceph::Tools::get_config('ccname');
297
298 my $service_name = "mds.$id";
299 my $service_dir = "/var/lib/ceph/mds/$ccname-$id";
300
301 print "disabling service 'ceph-mds\@$id.service'\n";
302 ceph_service_cmd('disable', $service_name);
303 print "stopping service 'ceph-mds\@$id.service'\n";
304 ceph_service_cmd('stop', $service_name);
305
306 if (-d $service_dir) {
307 print "removing ceph-mds directory '$service_dir'\n";
308 File::Path::remove_tree($service_dir);
309 } else {
310 warn "cannot cleanup MDS $id directory, '$service_dir' not found\n"
311 }
312
313 print "removing ceph auth for '$service_name'\n";
314 $rados->mon_command({
315 prefix => 'auth del',
316 entity => $service_name,
317 format => 'plain'
318 });
319
4e76dbd7
DC
320 broadcast_ceph_services();
321
27439be6
DC
322 return undef;
323};
324
be7edba1
DC
325# MGR
326
327sub create_mgr {
328 my ($id, $rados) = @_;
329
330 my $clustername = PVE::Ceph::Tools::get_config('ccname');
331 my $mgrdir = "/var/lib/ceph/mgr/$clustername-$id";
332 my $mgrkeyring = "$mgrdir/keyring";
333 my $mgrname = "mgr.$id";
334
335 die "ceph manager directory '$mgrdir' already exists\n"
336 if -d $mgrdir;
337
338 print "creating manager directory '$mgrdir'\n";
339 mkdir $mgrdir;
340 print "creating keys for '$mgrname'\n";
341 my $output = $rados->mon_command({ prefix => 'auth get-or-create',
342 entity => $mgrname,
343 caps => [
344 mon => 'allow profile mgr',
345 osd => 'allow *',
346 mds => 'allow *',
347 ],
348 format => 'plain'});
349 PVE::Tools::file_set_contents($mgrkeyring, $output);
350
351 print "setting owner for directory\n";
352 run_command(["chown", 'ceph:ceph', '-R', $mgrdir]);
353
354 print "enabling service 'ceph-mgr\@$id.service'\n";
355 ceph_service_cmd('enable', $mgrname);
356 print "starting service 'ceph-mgr\@$id.service'\n";
357 ceph_service_cmd('start', $mgrname);
4e76dbd7
DC
358
359 broadcast_ceph_services();
360
361 return undef;
be7edba1
DC
362}
363
364sub destroy_mgr {
b5215730 365 my ($mgrid, $rados) = @_;
be7edba1
DC
366
367 my $clustername = PVE::Ceph::Tools::get_config('ccname');
368 my $mgrname = "mgr.$mgrid";
369 my $mgrdir = "/var/lib/ceph/mgr/$clustername-$mgrid";
370
371 die "ceph manager directory '$mgrdir' not found\n"
372 if ! -d $mgrdir;
373
374 print "disabling service 'ceph-mgr\@$mgrid.service'\n";
375 ceph_service_cmd('disable', $mgrname);
376 print "stopping service 'ceph-mgr\@$mgrid.service'\n";
377 ceph_service_cmd('stop', $mgrname);
378
379 print "removing manager directory '$mgrdir'\n";
380 File::Path::remove_tree($mgrdir);
4e76dbd7 381
b5215730
DC
382 print "removing authkeys for $mgrname\n";
383 if (!$rados) {
384 $rados = PVE::RADOS->new();
385 }
386
387 $rados->mon_command({ prefix => 'auth del', entity => "$mgrname" });
388
4e76dbd7
DC
389 broadcast_ceph_services();
390
391 return undef;
be7edba1
DC
392}
393
27439be6 3941;