]>
git.proxmox.com Git - pve-manager.git/blob - PVE/Ceph/Services.pm
5340f5fcbb7d54b524eeb392c5866605b6435d3a
1 package PVE
::Ceph
::Services
;
7 use PVE
::Cluster
qw(cfs_read_file);
8 use PVE
::Tools
qw(run_command);
14 use constant SERVICE_REGEX
=> '[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?';
16 # checks /etc/systemd/system/ceph-* to list all services, even if not running
17 # also checks /var/lib/ceph/$type
18 sub get_local_services
{
21 for my $type (qw(mds mgr mon)) {
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 {
28 $res->{$type}->{$id}->{service
} = 1;
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;
41 sub broadcast_ceph_services
{
42 my $services = get_local_services
();
44 for my $type (keys %$services) {
45 my $data = encode_json
($services->{$type});
46 PVE
::Cluster
::broadcast_node_kv
("ceph-$type", $data);
50 sub broadcast_ceph_versions
{
51 my ($version, $buildcommit, $vers_parts) = PVE
::Ceph
::Tools
::get_local_version
(1);
54 if (my $old = PVE
::Cluster
::get_node_kv
("ceph-versions")) {
55 my $nodename = PVE
::INotify
::nodename
();
56 $old = eval { decode_json
($old->{$nodename}) };
57 warn $@ if $@; # should not happen
58 if (defined($old) && $old->{buildcommit
} eq $buildcommit && $old->{version
}->{str
} eq $version) {
59 return; # up to date, nothing to do so avoid (not exactly cheap) broadcast
67 buildcommit
=> $buildcommit,
69 PVE
::Cluster
::broadcast_node_kv
("ceph-versions", encode_json
($node_versions));
73 sub get_ceph_versions
{
76 if (defined(my $versions = PVE
::Cluster
::get_node_kv
("ceph-versions"))) {
78 map { eval { $_ => decode_json
($versions->{$_}) } } keys %$versions
85 sub get_cluster_service
{
88 my $raw = PVE
::Cluster
::get_node_kv
("ceph-$type");
90 map { $_ => eval { decode_json
($raw->{$_}) } } keys $raw->%*
96 sub ceph_service_cmd
{
97 my ($action, $service) = @_;
99 if ($service && $service =~ m/^(mon|osd|mds|mgr|radosgw)(\.(${\SERVICE_REGEX}))?$/) {
100 $service = defined($3) ?
"ceph-$1\@$3" : "ceph-$1.target";
102 $service = "ceph.target";
105 run_command
(['/bin/systemctl', $action, $service]);
108 sub get_services_info
{
109 my ($type, $cfg, $rados) = @_;
112 my $services = get_cluster_service
($type);
114 foreach my $host (sort keys %$services) {
115 foreach my $id (sort keys %{$services->{$host}}) {
116 my $service = $result->{$id} = $services->{$host}->{$id};
117 $service->{host
} = $host;
118 $service->{name
} = $id;
119 $service->{state} = 'unknown';
120 if ($service->{service
}) {
121 $service->{state} = 'stopped';
127 $cfg = cfs_read_file
('ceph.conf');
130 foreach my $section (keys %$cfg) {
131 my $d = $cfg->{$section};
132 if ($section =~ m/^$type\.(\S+)$/) {
134 my $service = $result->{$id};
135 my $addr = $d->{"${type}_addr"} // $d->{public_addr
} // $d->{host
};
136 $service->{name
} //= $id;
137 $service->{addr
} //= $addr;
138 $service->{state} //= 'unknown';
139 $service->{host
} //= $d->{host
};
147 my $metadata = $rados->mon_command({ prefix
=> "$type metadata" });
148 foreach my $info (@$metadata) {
149 my $id = $info->{name
} // $info->{id
};
150 my $service = $result->{$id};
151 $service->{ceph_version_short
} = $info->{ceph_version_short
};
152 $service->{ceph_version
} = $info->{ceph_version
};
153 $service->{host
} //= $info->{hostname
};
154 $service->{addr
} //= $info->{addr
};
162 sub list_local_mds_ids
{
164 my $ceph_mds_data_dir = PVE
::Ceph
::Tools
::get_config
('ceph_mds_data_dir');
165 my $ccname = PVE
::Ceph
::Tools
::get_config
('ccname');
167 PVE
::Tools
::dir_glob_foreach
($ceph_mds_data_dir, qr/$ccname-(\S+)/, sub {
168 my (undef, $mds_id) = @_;
169 push @$mds_list, $mds_id;
175 sub get_cluster_mds_state
{
180 if (!defined($rados)) {
181 $rados = PVE
::RADOS-
>new();
184 my $add_state = sub {
188 $state->{addr
} = $mds->{addr
};
189 $state->{rank
} = $mds->{rank
};
190 $state->{standby_replay
} = $mds->{standby_replay
} ?
1 : 0;
191 $state->{state} = $mds->{state};
193 $mds_state->{$mds->{name
}} = $state;
196 my $mds_dump = $rados->mon_command({ prefix
=> 'mds stat' });
197 my $fsmap = $mds_dump->{fsmap
};
200 foreach my $mds (@{$fsmap->{standbys
}}) {
204 my $fs_info = $fsmap->{filesystems
}->[0];
205 my $active_mds = $fs_info->{mdsmap
}->{info
};
207 # normally there's only one active MDS, but we can have multiple active for
208 # different ranks (e.g., different cephs path hierarchy). So just add all.
209 foreach my $mds (values %$active_mds) {
216 sub is_any_mds_active
{
219 if (!defined($rados)) {
220 $rados = PVE
::RADOS-
>new();
223 my $mds_dump = $rados->mon_command({ prefix
=> 'mds stat' });
224 my $fs = $mds_dump->{fsmap
}->{filesystems
};
226 if (!($fs && scalar(@$fs) > 0)) {
229 my $active_mds = $fs->[0]->{mdsmap
}->{info
};
231 for my $mds (values %$active_mds) {
232 return 1 if $mds->{state} eq 'up:active';
239 my ($id, $rados) = @_;
241 # `ceph fs status` fails with numeric only ID.
242 die "ID: $id, numeric only IDs are not supported\n"
245 if (!defined($rados)) {
246 $rados = PVE
::RADOS-
>new();
249 my $ccname = PVE
::Ceph
::Tools
::get_config
('ccname');
250 my $service_dir = "/var/lib/ceph/mds/$ccname-$id";
251 my $service_keyring = "$service_dir/keyring";
252 my $service_name = "mds.$id";
254 die "ceph MDS directory '$service_dir' already exists\n"
257 print "creating MDS directory '$service_dir'\n";
258 eval { File
::Path
::mkpath
($service_dir) };
260 die "creation MDS directory '$service_dir' failed\n" if $err;
262 # http://docs.ceph.com/docs/luminous/install/manual-deployment/#adding-mds
264 mon
=> 'allow profile mds',
269 print "creating keys for '$service_name'\n";
270 my $output = $rados->mon_command({
271 prefix
=> 'auth get-or-create',
272 entity
=> $service_name,
277 PVE
::Tools
::file_set_contents
($service_keyring, $output);
279 print "setting ceph as owner for service directory\n";
280 run_command
(["chown", 'ceph:ceph', '-R', $service_dir]);
282 print "enabling service 'ceph-mds\@$id.service'\n";
283 ceph_service_cmd
('enable', $service_name);
284 print "starting service 'ceph-mds\@$id.service'\n";
285 ceph_service_cmd
('start', $service_name);
287 broadcast_ceph_services
();
293 my ($id, $rados) = @_;
295 if (!defined($rados)) {
296 $rados = PVE
::RADOS-
>new();
299 my $ccname = PVE
::Ceph
::Tools
::get_config
('ccname');
301 my $service_name = "mds.$id";
302 my $service_dir = "/var/lib/ceph/mds/$ccname-$id";
304 print "disabling service 'ceph-mds\@$id.service'\n";
305 ceph_service_cmd
('disable', $service_name);
306 print "stopping service 'ceph-mds\@$id.service'\n";
307 ceph_service_cmd
('stop', $service_name);
309 if (-d
$service_dir) {
310 print "removing ceph-mds directory '$service_dir'\n";
311 File
::Path
::remove_tree
($service_dir);
313 warn "cannot cleanup MDS $id directory, '$service_dir' not found\n"
316 print "removing ceph auth for '$service_name'\n";
317 $rados->mon_command({
318 prefix
=> 'auth del',
319 entity
=> $service_name,
323 broadcast_ceph_services
();
331 my ($id, $rados) = @_;
333 my $clustername = PVE
::Ceph
::Tools
::get_config
('ccname');
334 my $mgrdir = "/var/lib/ceph/mgr/$clustername-$id";
335 my $mgrkeyring = "$mgrdir/keyring";
336 my $mgrname = "mgr.$id";
338 die "ceph manager directory '$mgrdir' already exists\n" if -d
$mgrdir;
340 print "creating manager directory '$mgrdir'\n";
342 print "creating keys for '$mgrname'\n";
343 my $output = $rados->mon_command({
344 prefix
=> 'auth get-or-create',
347 mon
=> 'allow profile mgr',
353 PVE
::Tools
::file_set_contents
($mgrkeyring, $output);
355 print "setting owner for directory\n";
356 run_command
(["chown", 'ceph:ceph', '-R', $mgrdir]);
358 print "enabling service 'ceph-mgr\@$id.service'\n";
359 ceph_service_cmd
('enable', $mgrname);
360 print "starting service 'ceph-mgr\@$id.service'\n";
361 ceph_service_cmd
('start', $mgrname);
363 broadcast_ceph_services
();
369 my ($mgrid, $rados) = @_;
371 my $clustername = PVE
::Ceph
::Tools
::get_config
('ccname');
372 my $mgrname = "mgr.$mgrid";
373 my $mgrdir = "/var/lib/ceph/mgr/$clustername-$mgrid";
375 die "ceph manager directory '$mgrdir' not found\n"
378 print "disabling service 'ceph-mgr\@$mgrid.service'\n";
379 ceph_service_cmd
('disable', $mgrname);
380 print "stopping service 'ceph-mgr\@$mgrid.service'\n";
381 ceph_service_cmd
('stop', $mgrname);
383 print "removing manager directory '$mgrdir'\n";
384 File
::Path
::remove_tree
($mgrdir);
386 print "removing authkeys for $mgrname\n";
388 $rados = PVE
::RADOS-
>new();
391 $rados->mon_command({ prefix
=> 'auth del', entity
=> "$mgrname" });
393 broadcast_ceph_services
();