use JSON;
use File::Path;
+use constant SERVICE_REGEX => '[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?';
+
# checks /etc/systemd/system/ceph-* to list all services, even if not running
# also checks /var/lib/ceph/$type
sub get_local_services {
}
}
+sub broadcast_ceph_versions {
+ my ($version, $buildcommit, $vers_parts) = PVE::Ceph::Tools::get_local_version(1);
+
+ if ($version) {
+ my $nodename = PVE::INotify::nodename();
+ my $old = PVE::Cluster::get_node_kv("ceph-versions", $nodename);
+ if (defined($old->{$nodename})) {
+ $old = eval { decode_json($old->{$nodename}) };
+ warn $@ if $@; # should not happen
+ if (defined($old) && $old->{buildcommit} eq $buildcommit && $old->{version}->{str} eq $version) {
+ return; # up to date, nothing to do so avoid (not exactly cheap) broadcast
+ }
+ }
+ # FIXME: remove with 8.0 (or 7.2, its not _that_ bad) - for backward compat only
+ PVE::Cluster::broadcast_node_kv("ceph-version", $version);
+
+ my $node_versions = {
+ version => {
+ str => $version,
+ parts => $vers_parts,
+ },
+ buildcommit => $buildcommit,
+ };
+ PVE::Cluster::broadcast_node_kv("ceph-versions", encode_json($node_versions));
+ }
+}
+
+sub get_ceph_versions {
+ my $res;
+
+ if (defined(my $versions = PVE::Cluster::get_node_kv("ceph-versions"))) {
+ $res = {
+ map { eval { $_ => decode_json($versions->{$_}) } } keys %$versions
+ };
+ }
+
+ return $res;
+}
+
sub get_cluster_service {
my ($type) = @_;
my $raw = PVE::Cluster::get_node_kv("ceph-$type");
- my $res = {};
-
- for my $host (keys %$raw) {
- $res->{$host} = eval { decode_json($raw->{$host}) };
- }
+ my $res = {
+ map { $_ => eval { decode_json($raw->{$_}) } } keys $raw->%*
+ };
return $res;
}
sub ceph_service_cmd {
my ($action, $service) = @_;
- my $pve_ceph_cfgpath = PVE::Ceph::Tools::get_config('pve_ceph_cfgpath');
- if ($service && $service =~ m/^(mon|osd|mds|mgr|radosgw)(\.([A-Za-z0-9\-]{1,32}))?$/) {
+ if ($service && $service =~ m/^(mon|osd|mds|mgr|radosgw)(\.(${\SERVICE_REGEX}))?$/) {
$service = defined($3) ? "ceph-$1\@$3" : "ceph-$1.target";
} else {
$service = "ceph.target";
}
my $add_state = sub {
- my ($mds) = @_;
+ my ($mds, $fsname) = @_;
my $state = {};
$state->{addr} = $mds->{addr};
$state->{rank} = $mds->{rank};
$state->{standby_replay} = $mds->{standby_replay} ? 1 : 0;
$state->{state} = $mds->{state};
+ $state->{fs_name} = $fsname;
$mds_state->{$mds->{name}} = $state;
};
$add_state->($mds);
}
- my $fs_info = $fsmap->{filesystems}->[0];
- my $active_mds = $fs_info->{mdsmap}->{info};
+ for my $fs_info (@{$fsmap->{filesystems}}) {
+ my $active_mds = $fs_info->{mdsmap}->{info};
- # normally there's only one active MDS, but we can have multiple active for
- # different ranks (e.g., different cephs path hierarchy). So just add all.
- foreach my $mds (values %$active_mds) {
- $add_state->($mds);
+ # normally there's only one active MDS, but we can have multiple active for
+ # different ranks (e.g., different cephs path hierarchy). So just add all.
+ foreach my $mds (values %$active_mds) {
+ $add_state->($mds, $fs_info->{mdsmap}->{fs_name});
+ }
}
return $mds_state;
}
-sub is_any_mds_active {
- my ($rados) = @_;
+sub is_mds_active {
+ my ($rados, $fs_name) = @_;
if (!defined($rados)) {
$rados = PVE::RADOS->new();
}
my $mds_dump = $rados->mon_command({ prefix => 'mds stat' });
- my $fs = $mds_dump->{fsmap}->{filesystems};
+ my $fsmap = $mds_dump->{fsmap}->{filesystems};
- if (!($fs && scalar(@$fs) > 0)) {
+ if (!($fsmap && scalar(@$fsmap) > 0)) {
return undef;
}
- my $active_mds = $fs->[0]->{mdsmap}->{info};
+ for my $fs (@$fsmap) {
+ next if defined($fs_name) && $fs->{mdsmap}->{fs_name} ne $fs_name;
- for my $mds (values %$active_mds) {
- return 1 if $mds->{state} eq 'up:active';
+ my $active_mds = $fs->{mdsmap}->{info};
+ for my $mds (values %$active_mds) {
+ return 1 if $mds->{state} eq 'up:active';
+ }
}
return 0;
my $mgrkeyring = "$mgrdir/keyring";
my $mgrname = "mgr.$id";
- die "ceph manager directory '$mgrdir' already exists\n"
- if -d $mgrdir;
+ die "ceph manager directory '$mgrdir' already exists\n" if -d $mgrdir;
print "creating manager directory '$mgrdir'\n";
mkdir $mgrdir;
print "creating keys for '$mgrname'\n";
- my $output = $rados->mon_command({ prefix => 'auth get-or-create',
- entity => $mgrname,
- caps => [
- mon => 'allow profile mgr',
- osd => 'allow *',
- mds => 'allow *',
- ],
- format => 'plain'});
+ my $output = $rados->mon_command({
+ prefix => 'auth get-or-create',
+ entity => $mgrname,
+ caps => [
+ mon => 'allow profile mgr',
+ osd => 'allow *',
+ mds => 'allow *',
+ ],
+ format => 'plain'
+ });
PVE::Tools::file_set_contents($mgrkeyring, $output);
print "setting owner for directory\n";