pve-manager/PVE/API2/Ceph/FS.pm
Thomas Lamprecht 7ef69f338e ceph tools: factor out frequent keyring and config init check
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2019-07-23 07:48:45 +02:00

224 lines
5.3 KiB
Perl

package PVE::API2::Ceph::FS;
use strict;
use warnings;
use PVE::Ceph::Tools;
use PVE::Ceph::Services;
use PVE::JSONSchema qw(get_standard_option);
use PVE::RADOS;
use PVE::RESTHandler;
use PVE::RPCEnvironment;
use PVE::Storage;
use PVE::API2::Storage::Config;
use base qw(PVE::RESTHandler);
__PACKAGE__->register_method ({
name => 'index',
path => '',
method => 'GET',
proxyto => 'node',
description => "Directory index.",
permissions => {
check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1],
},
protected => 1,
parameters => {
additionalProperties => 0,
properties => {
node => get_standard_option('pve-node'),
},
},
returns => {
type => 'array',
items => {
type => "object",
properties => {
name => {
description => "The ceph filesystem name.",
type => 'string',
},
metadata_pool => {
description => "The name of the metadata pool.",
type => 'string',
},
data_pool => {
description => "The name of the data pool.",
type => 'string',
},
},
},
links => [ { rel => 'child', href => "{name}" } ],
},
code => sub {
my ($param) = @_;
PVE::Ceph::Tools::check_ceph_inited();
my $rados = PVE::RADOS->new();
my $cephfs_list = $rados->mon_command({ prefix => "fs ls" });
# we get something like:
#{
# 'metadata_pool_id' => 2,
# 'data_pool_ids' => [ 1 ],
# 'metadata_pool' => 'cephfs_metadata',
# 'data_pools' => [ 'cephfs_data' ],
# 'name' => 'cephfs',
#}
my $res = [
map {{
name => $_->{name},
metadata_pool => $_->{metadata_pool},
data_pool => $_->{data_pools}->[0],
}} @$cephfs_list
];
return $res;
}
});
__PACKAGE__->register_method ({
name => 'createfs',
path => '{name}',
method => 'POST',
description => "Create a Ceph filesystem",
proxyto => 'node',
protected => 1,
permissions => {
check => ['perm', '/', [ 'Sys.Modify' ]],
},
parameters => {
additionalProperties => 0,
properties => {
node => get_standard_option('pve-node'),
name => {
description => "The ceph filesystem name.",
type => 'string',
default => 'cephfs',
optional => 1,
},
pg_num => {
description => "Number of placement groups for the backing data pool. The metadata pool will use a quarter of this.",
type => 'integer',
default => 128,
optional => 1,
minimum => 8,
maximum => 32768,
},
'add-storage' => {
description => "Configure the created CephFS as storage for this cluster.",
type => 'boolean',
optional => 1,
default => 0,
},
},
},
returns => { type => 'string' },
code => sub {
my ($param) = @_;
PVE::Ceph::Tools::check_ceph_configured();
my $fs_name = $param->{name} // 'cephfs';
my $pg_num = $param->{pg_num} // 128;
my $pool_data = "${fs_name}_data";
my $pool_metadata = "${fs_name}_metadata";
my $rados = PVE::RADOS->new();
my $ls_pools = PVE::Ceph::Tools::ls_pools();
my $existing_pools = { map { $_->{poolname} => 1 } @$ls_pools };
die "ceph pools '$pool_data' and/or '$pool_metadata' already exist\n"
if $existing_pools->{$pool_data} || $existing_pools->{$pool_metadata};
my $running_mds = PVE::Ceph::Services::get_cluster_mds_state($rados);
die "no running Metadata Server (MDS) found!\n" if !scalar(keys %$running_mds);
PVE::Storage::assert_sid_unused($fs_name) if $param->{add_storage};
my $worker = sub {
$rados = PVE::RADOS->new();
my $pool_param = {
application => 'cephfs',
pg_num => $pg_num,
};
my @created_pools = ();
eval {
print "creating data pool '$pool_data'...\n";
PVE::Ceph::Tools::create_pool($pool_data, $pool_param, $rados);
push @created_pools, $pool_data;
print "creating metadata pool '$pool_metadata'...\n";
$pool_param->{pg_num} = $pg_num >= 32 ? $pg_num / 4 : 8;
PVE::Ceph::Tools::create_pool($pool_metadata, $pool_param, $rados);
push @created_pools, $pool_metadata;
print "configuring new CephFS '$fs_name'\n";
$rados->mon_command({
prefix => "fs new",
fs_name => $fs_name,
metadata => $pool_metadata,
data => $pool_data,
format => 'plain',
});
};
if (my $err = $@) {
$@ = undef;
if (@created_pools > 0) {
warn "Encountered error after creating at least one pool\n";
# our old connection is very likely broken now, recreate
$rados = PVE::RADOS->new();
foreach my $pool (@created_pools) {
warn "cleaning up left over pool '$pool'\n";
eval { PVE::Ceph::Tools::destroy_pool($pool, $rados) };
warn "$@\n" if $@;
}
}
die "$err\n";
}
print "Successfully create CephFS '$fs_name'\n";
if ($param->{'add-storage'}) {
print "Adding '$fs_name' to storage configuration...\n";
my $waittime = 0;
while (!PVE::Ceph::Services::is_any_mds_active($rados)) {
if ($waittime >= 10) {
die "Need MDS to add storage, but none got active!\n";
}
print "Waiting for an MDS to become active\n";
sleep(1);
$waittime++;
}
eval {
PVE::API2::Storage::Config->create({
type => 'cephfs',
storage => $fs_name,
content => 'backup,iso,vztmpl',
})
};
die "adding storage for CephFS '$fs_name' failed, check log ".
"and add manually!\n$@\n" if $@;
}
};
my $rpcenv = PVE::RPCEnvironment::get();
my $user = $rpcenv->get_user();
return $rpcenv->fork_worker('cephfscreate', $fs_name, $user, $worker);
}
});
1;