From 02c1e98e833c75008831d861abb162f3966bfcb1 Mon Sep 17 00:00:00 2001 From: Dominik Csapak Date: Mon, 25 Oct 2021 16:01:38 +0200 Subject: [PATCH] pveceph: add 'fs destroy' command with 'remove-storages' and 'remove-pools' as optional parameters Signed-off-by: Dominik Csapak --- PVE/CLI/pveceph.pm | 120 ++++++++++++++++++++++++++++++++++++++++++ PVE/Ceph/Tools.pm | 15 ++++++ www/manager6/Utils.js | 1 + 3 files changed, 136 insertions(+) diff --git a/PVE/CLI/pveceph.pm b/PVE/CLI/pveceph.pm index b04d1346..995cfcd5 100755 --- a/PVE/CLI/pveceph.pm +++ b/PVE/CLI/pveceph.pm @@ -221,6 +221,125 @@ __PACKAGE__->register_method ({ return undef; }}); +my $get_storages = sub { + my ($fs, $is_default) = @_; + + my $cfg = PVE::Storage::config(); + + my $storages = $cfg->{ids}; + my $res = {}; + foreach my $storeid (keys %$storages) { + my $curr = $storages->{$storeid}; + next if $curr->{type} ne 'cephfs'; + my $cur_fs = $curr->{'fs-name'}; + $res->{$storeid} = $storages->{$storeid} + if (!defined($cur_fs) && $is_default) || (defined($cur_fs) && $fs eq $cur_fs); + } + + return $res; +}; + +__PACKAGE__->register_method ({ + name => 'destroyfs', + path => 'destroyfs', + method => 'DELETE', + description => "Destroy a Ceph filesystem", + parameters => { + additionalProperties => 0, + properties => { + node => get_standard_option('pve-node'), + name => { + description => "The ceph filesystem name.", + type => 'string', + }, + 'remove-storages' => { + description => "Remove all pveceph-managed storages configured for this fs.", + type => 'boolean', + optional => 1, + default => 0, + }, + 'remove-pools' => { + description => "Remove data and metadata pools configured for this fs.", + type => 'boolean', + optional => 1, + default => 0, + }, + }, + }, + returns => { type => 'string' }, + code => sub { + my ($param) = @_; + + PVE::Ceph::Tools::check_ceph_inited(); + + my $rpcenv = PVE::RPCEnvironment::get(); + my $user = $rpcenv->get_user(); + + my $fs_name = $param->{name}; + + my $fs; + my $fs_list = PVE::Ceph::Tools::ls_fs(); + for my $entry (@$fs_list) { + next if $entry->{name} ne $fs_name; + $fs = $entry; + last; + } + die "no such cephfs '$fs_name'\n" if !$fs; + + my $worker = sub { + my $rados = PVE::RADOS->new(); + + if ($param->{'remove-storages'}) { + my $defaultfs; + my $fs_dump = $rados->mon_command({ prefix => "fs dump" }); + for my $fs ($fs_dump->{filesystems}->@*) { + next if $fs->{id} != $fs_dump->{default_fscid}; + $defaultfs = $fs->{mdsmap}->{fs_name}; + } + warn "no default fs found, maybe not all relevant storages are removed\n" + if !defined($defaultfs); + + my $storages = $get_storages->($fs_name, $fs_name eq ($defaultfs // '')); + for my $storeid (keys %$storages) { + my $store = $storages->{$storeid}; + if (!$store->{disable}) { + die "storage '$storeid' is not disabled, make sure to disable ". + "and unmount the storage first\n"; + } + } + + my $err; + for my $storeid (keys %$storages) { + # skip external clusters, not managed by pveceph + next if $storages->{$storeid}->{monhost}; + eval { PVE::API2::Storage::Config->delete({storage => $storeid}) }; + if ($@) { + warn "failed to remove storage '$storeid': $@\n"; + $err = 1; + } + } + die "failed to remove (some) storages - check log and remove manually!\n" + if $err; + } + + PVE::Ceph::Tools::destroy_fs($fs_name, $rados); + + if ($param->{'remove-pools'}) { + warn "removing metadata pool '$fs->{metadata_pool}'\n"; + eval { PVE::Ceph::Tools::destroy_pool($fs->{metadata_pool}, $rados) }; + warn "$@\n" if $@; + + foreach my $pool ($fs->{data_pools}->@*) { + warn "removing data pool '$pool'\n"; + eval { PVE::Ceph::Tools::destroy_pool($pool, $rados) }; + warn "$@\n" if $@; + } + } + + }; + return $rpcenv->fork_worker('cephdestroyfs', $fs_name, $user, $worker); + }}); + our $cmddef = { init => [ 'PVE::API2::Ceph', 'init', [], { node => $nodename } ], pool => { @@ -256,6 +375,7 @@ our $cmddef = { destroypool => { alias => 'pool destroy' }, fs => { create => [ 'PVE::API2::Ceph::FS', 'createfs', [], { node => $nodename }], + destroy => [ __PACKAGE__, 'destroyfs', ['name'], { node => $nodename }], }, osd => { create => [ 'PVE::API2::Ceph::OSD', 'createosd', ['dev'], { node => $nodename }, $upid_exit], diff --git a/PVE/Ceph/Tools.pm b/PVE/Ceph/Tools.pm index 2f818276..36d7788a 100644 --- a/PVE/Ceph/Tools.pm +++ b/PVE/Ceph/Tools.pm @@ -340,6 +340,21 @@ sub create_fs { }); } +sub destroy_fs { + my ($fs, $rados) = @_; + + if (!defined($rados)) { + $rados = PVE::RADOS->new(); + } + + $rados->mon_command({ + prefix => "fs rm", + fs_name => $fs, + 'yes_i_really_mean_it' => JSON::true, + format => 'plain', + }); +} + sub setup_pve_symlinks { # fail if we find a real file instead of a link if (-f $ceph_cfgpath) { diff --git a/www/manager6/Utils.js b/www/manager6/Utils.js index bcd6383b..d66d0c86 100644 --- a/www/manager6/Utils.js +++ b/www/manager6/Utils.js @@ -1820,6 +1820,7 @@ Ext.define('PVE.Utils', { cephdestroymon: ['Ceph Monitor', gettext('Destroy')], cephdestroyosd: ['Ceph OSD', gettext('Destroy')], cephdestroypool: ['Ceph Pool', gettext('Destroy')], + cephdestroyfs: ['CephFS', gettext('Destroy')], cephfscreate: ['CephFS', gettext('Create')], cephsetpool: ['Ceph Pool', gettext('Edit')], cephsetflags: ['', gettext('Change global Ceph flags')], -- 2.39.5