* [pve-devel] [PATCH storage v2 0/3] disks: add checks, allow add_storage on other nodes
@ 2022-07-15 11:58 Aaron Lauterer
2022-07-15 11:58 ` [pve-devel] [PATCH storage v2 1/3] diskmanage: add mounted_paths Aaron Lauterer
` (2 more replies)
0 siblings, 3 replies; 13+ messages in thread
From: Aaron Lauterer @ 2022-07-15 11:58 UTC (permalink / raw)
To: pve-devel
This series deals mainly with 2 things, adding more checks prior to
actually setting up a new local storage to avoid leaving behind half
provisioned disks in case a storage (lvm, zfs, ...) of the same name
already exists.
Secondly, to change the behavior regarding the "Add Storage" flag. It
allows to keep in enabled and will create the local storage and add the
node to the nodes list of the PVE storage config if there already exists
one in the cluster.
The first patch is a prerequisite to be able to check if a mount path
for the Directory storage type is already mounted.
The second patch implements the actual checks.
The third patch adds the changed behavior for the "Add Storage" part.
More in the actual patches.
changes since v1:
- recommended changes by Dominik & Fabian E
- some lines were in the wrong patches due to some mistakes during
reordering the patches
Aaron Lauterer (3):
diskmanage: add mounted_paths
disks: die if storage name is already in use
disks: allow add_storage for already configured local storage
PVE/API2/Disks/Directory.pm | 19 +++++---
PVE/API2/Disks/LVM.pm | 11 +++--
PVE/API2/Disks/LVMThin.pm | 11 +++--
PVE/API2/Disks/ZFS.pm | 86 +++++++++++++++++++++----------------
PVE/API2/Storage/Config.pm | 22 ++++++++++
PVE/Diskmanage.pm | 12 ++++++
PVE/Storage.pm | 27 ++++++++++++
7 files changed, 138 insertions(+), 50 deletions(-)
--
2.30.2
^ permalink raw reply [flat|nested] 13+ messages in thread
* [pve-devel] [PATCH storage v2 1/3] diskmanage: add mounted_paths
2022-07-15 11:58 [pve-devel] [PATCH storage v2 0/3] disks: add checks, allow add_storage on other nodes Aaron Lauterer
@ 2022-07-15 11:58 ` Aaron Lauterer
2022-08-17 11:35 ` Fabian Grünbichler
2022-07-15 11:58 ` [pve-devel] [PATCH storage v2 2/3] disks: die if storage name is already in use Aaron Lauterer
2022-07-15 11:58 ` [pve-devel] [PATCH storage v2 3/3] disks: allow add_storage for already configured local storage Aaron Lauterer
2 siblings, 1 reply; 13+ messages in thread
From: Aaron Lauterer @ 2022-07-15 11:58 UTC (permalink / raw)
To: pve-devel
returns a list of mounted paths with the backing devices
Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
---
changes since v1: dropped limit to /dev path, returning all mounted
paths now
PVE/Diskmanage.pm | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/PVE/Diskmanage.pm b/PVE/Diskmanage.pm
index 8ed7a8b..b149685 100644
--- a/PVE/Diskmanage.pm
+++ b/PVE/Diskmanage.pm
@@ -499,6 +499,18 @@ sub mounted_blockdevs {
return $mounted;
}
+sub mounted_paths {
+ my $mounted = {};
+
+ my $mounts = PVE::ProcFSTools::parse_proc_mounts();
+
+ foreach my $mount (@$mounts) {
+ $mounted->{abs_path($mount->[1])} = $mount->[0];
+ };
+
+ return $mounted;
+}
+
sub get_disks {
my ($disks, $nosmart, $include_partitions) = @_;
my $disklist = {};
--
2.30.2
^ permalink raw reply [flat|nested] 13+ messages in thread
* [pve-devel] [PATCH storage v2 2/3] disks: die if storage name is already in use
2022-07-15 11:58 [pve-devel] [PATCH storage v2 0/3] disks: add checks, allow add_storage on other nodes Aaron Lauterer
2022-07-15 11:58 ` [pve-devel] [PATCH storage v2 1/3] diskmanage: add mounted_paths Aaron Lauterer
@ 2022-07-15 11:58 ` Aaron Lauterer
2022-08-17 11:42 ` Fabian Grünbichler
2022-07-15 11:58 ` [pve-devel] [PATCH storage v2 3/3] disks: allow add_storage for already configured local storage Aaron Lauterer
2 siblings, 1 reply; 13+ messages in thread
From: Aaron Lauterer @ 2022-07-15 11:58 UTC (permalink / raw)
To: pve-devel
If a storage of that type and name already exists (LVM, zpool, ...) but
we do not have a Proxmox VE Storage config for it, it is possible that
the creation will fail midway due to checks done by the underlying
storage layer itself. This in turn can lead to disks that are already
partitioned. Users would need to clean this up themselves.
By adding checks early on, not only checking against the PVE storage
config, but against the actual storage type itself, we can die early
enough, before we touch any disk.
For ZFS, the logic to gather pool data is moved into its own function to
be called from the index API endpoint and the check in the create
endpoint.
Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
---
changes since v1:
- moved zfs pool gathering from index api endpoint into its own function
to easily call it for the check as well
- zfs pool check is now using perl grep
- removed check if mounted path if a /dev one
- added check if a mount unit exists
- moved definitions of $path, $mountunitname and $mountunitpath out
of the worker
PVE/API2/Disks/Directory.pm | 11 ++++--
PVE/API2/Disks/LVM.pm | 3 ++
PVE/API2/Disks/LVMThin.pm | 3 ++
PVE/API2/Disks/ZFS.pm | 77 +++++++++++++++++++++----------------
4 files changed, 56 insertions(+), 38 deletions(-)
diff --git a/PVE/API2/Disks/Directory.pm b/PVE/API2/Disks/Directory.pm
index df63ba9..07190de 100644
--- a/PVE/API2/Disks/Directory.pm
+++ b/PVE/API2/Disks/Directory.pm
@@ -203,16 +203,19 @@ __PACKAGE__->register_method ({
my $dev = $param->{device};
my $node = $param->{node};
my $type = $param->{filesystem} // 'ext4';
+ my $path = "/mnt/pve/$name";
+ my $mountunitname = PVE::Systemd::escape_unit($path, 1) . ".mount";
+ my $mountunitpath = "/etc/systemd/system/$mountunitname";
$dev = PVE::Diskmanage::verify_blockdev_path($dev);
PVE::Diskmanage::assert_disk_unused($dev);
PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
- my $worker = sub {
- my $path = "/mnt/pve/$name";
- my $mountunitname = PVE::Systemd::escape_unit($path, 1) . ".mount";
- my $mountunitpath = "/etc/systemd/system/$mountunitname";
+ my $mounted = PVE::Diskmanage::mounted_paths();
+ die "a mountpoint for '${name}' already exists: ${path} ($1)\n" if $mounted->{$path};
+ die "a systemd mount unit already exists: ${mountunitpath}\n" if -e $mountunitpath;
+ my $worker = sub {
PVE::Diskmanage::locked_disk_action(sub {
PVE::Diskmanage::assert_disk_unused($dev);
diff --git a/PVE/API2/Disks/LVM.pm b/PVE/API2/Disks/LVM.pm
index 6e4331a..a27afe2 100644
--- a/PVE/API2/Disks/LVM.pm
+++ b/PVE/API2/Disks/LVM.pm
@@ -152,6 +152,9 @@ __PACKAGE__->register_method ({
PVE::Diskmanage::assert_disk_unused($dev);
PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
+ die "volume group with name '${name}' already exists\n"
+ if PVE::Storage::LVMPlugin::lvm_vgs()->{$name};
+
my $worker = sub {
PVE::Diskmanage::locked_disk_action(sub {
PVE::Diskmanage::assert_disk_unused($dev);
diff --git a/PVE/API2/Disks/LVMThin.pm b/PVE/API2/Disks/LVMThin.pm
index 58ecb37..690c183 100644
--- a/PVE/API2/Disks/LVMThin.pm
+++ b/PVE/API2/Disks/LVMThin.pm
@@ -110,6 +110,9 @@ __PACKAGE__->register_method ({
PVE::Diskmanage::assert_disk_unused($dev);
PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
+ die "volume group with name '${name}' already exists\n"
+ if PVE::Storage::LVMPlugin::lvm_vgs()->{$name};
+
my $worker = sub {
PVE::Diskmanage::locked_disk_action(sub {
PVE::Diskmanage::assert_disk_unused($dev);
diff --git a/PVE/API2/Disks/ZFS.pm b/PVE/API2/Disks/ZFS.pm
index eeb9f48..51380c4 100644
--- a/PVE/API2/Disks/ZFS.pm
+++ b/PVE/API2/Disks/ZFS.pm
@@ -18,6 +18,43 @@ use base qw(PVE::RESTHandler);
my $ZPOOL = '/sbin/zpool';
my $ZFS = '/sbin/zfs';
+sub get_pool_data {
+ if (!-f $ZPOOL) {
+ die "zfsutils-linux not installed\n";
+ }
+
+ my $propnames = [qw(name size alloc free frag dedup health)];
+ my $numbers = {
+ size => 1,
+ alloc => 1,
+ free => 1,
+ frag => 1,
+ dedup => 1,
+ };
+
+ my $cmd = [$ZPOOL,'list', '-HpPLo', join(',', @$propnames)];
+
+ my $pools = [];
+
+ run_command($cmd, outfunc => sub {
+ my ($line) = @_;
+
+ my @props = split('\s+', trim($line));
+ my $pool = {};
+ for (my $i = 0; $i < scalar(@$propnames); $i++) {
+ if ($numbers->{$propnames->[$i]}) {
+ $pool->{$propnames->[$i]} = $props[$i] + 0;
+ } else {
+ $pool->{$propnames->[$i]} = $props[$i];
+ }
+ }
+
+ push @$pools, $pool;
+ });
+
+ return $pools;
+}
+
__PACKAGE__->register_method ({
name => 'index',
path => '',
@@ -74,40 +111,7 @@ __PACKAGE__->register_method ({
code => sub {
my ($param) = @_;
- if (!-f $ZPOOL) {
- die "zfsutils-linux not installed\n";
- }
-
- my $propnames = [qw(name size alloc free frag dedup health)];
- my $numbers = {
- size => 1,
- alloc => 1,
- free => 1,
- frag => 1,
- dedup => 1,
- };
-
- my $cmd = [$ZPOOL,'list', '-HpPLo', join(',', @$propnames)];
-
- my $pools = [];
-
- run_command($cmd, outfunc => sub {
- my ($line) = @_;
-
- my @props = split('\s+', trim($line));
- my $pool = {};
- for (my $i = 0; $i < scalar(@$propnames); $i++) {
- if ($numbers->{$propnames->[$i]}) {
- $pool->{$propnames->[$i]} = $props[$i] + 0;
- } else {
- $pool->{$propnames->[$i]} = $props[$i];
- }
- }
-
- push @$pools, $pool;
- });
-
- return $pools;
+ return get_pool_data();
}});
sub preparetree {
@@ -336,6 +340,7 @@ __PACKAGE__->register_method ({
my $user = $rpcenv->get_user();
my $name = $param->{name};
+ my $node = $param->{node};
my $devs = [PVE::Tools::split_list($param->{devices})];
my $raidlevel = $param->{raidlevel};
my $compression = $param->{compression} // 'on';
@@ -346,6 +351,10 @@ __PACKAGE__->register_method ({
}
PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
+ my $pools = get_pool_data();
+ die "pool '${name}' already exists on node '$node'\n"
+ if grep { $_->{name} eq $name } @{$pools};
+
my $numdisks = scalar(@$devs);
my $mindisks = {
single => 1,
--
2.30.2
^ permalink raw reply [flat|nested] 13+ messages in thread
* [pve-devel] [PATCH storage v2 3/3] disks: allow add_storage for already configured local storage
2022-07-15 11:58 [pve-devel] [PATCH storage v2 0/3] disks: add checks, allow add_storage on other nodes Aaron Lauterer
2022-07-15 11:58 ` [pve-devel] [PATCH storage v2 1/3] diskmanage: add mounted_paths Aaron Lauterer
2022-07-15 11:58 ` [pve-devel] [PATCH storage v2 2/3] disks: die if storage name is already in use Aaron Lauterer
@ 2022-07-15 11:58 ` Aaron Lauterer
2022-08-17 11:53 ` Fabian Grünbichler
2 siblings, 1 reply; 13+ messages in thread
From: Aaron Lauterer @ 2022-07-15 11:58 UTC (permalink / raw)
To: pve-devel
One of the smaller annoyances, especially for less experienced users, is
the fact, that when creating a local storage (ZFS, LVM (thin), dir) in a
cluster, one can only leave the "Add Storage" option enabled the first
time.
On any following node, this option needed to be disabled and the new
node manually added to the list of nodes for that storage.
This patch changes the behavior. If a storage of the same name already
exists, it will verify that necessary parameters match the already
existing one.
Then, if the 'nodes' parameter is set, it adds the current node and
updates the storage config.
In case there is no nodes list, nothing else needs to be done, and the
GUI will stop showing the question mark for the configured, but until
then, not existing local storage.
Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
---
changes since v1:
- restructured the logic a bit. checks still need to be done the same,
but the create or update logic is in its own
API2::Storage::Config->create_or_update function which then either
calls the create or update API directly. This reduces a lot of code
repition.
- in Storage::assert_sid_usable_on_node additionally checks if the
parameter is configured in the storage and fails if not. We would have
gotten warnings about using and undef in a string concat due to how the
other error was presented.
PVE/API2/Disks/Directory.pm | 8 +++++---
PVE/API2/Disks/LVM.pm | 8 +++++---
PVE/API2/Disks/LVMThin.pm | 8 +++++---
PVE/API2/Disks/ZFS.pm | 9 ++++++---
PVE/API2/Storage/Config.pm | 22 ++++++++++++++++++++++
PVE/Storage.pm | 27 +++++++++++++++++++++++++++
6 files changed, 70 insertions(+), 12 deletions(-)
diff --git a/PVE/API2/Disks/Directory.pm b/PVE/API2/Disks/Directory.pm
index 07190de..581e970 100644
--- a/PVE/API2/Disks/Directory.pm
+++ b/PVE/API2/Disks/Directory.pm
@@ -209,7 +209,10 @@ __PACKAGE__->register_method ({
$dev = PVE::Diskmanage::verify_blockdev_path($dev);
PVE::Diskmanage::assert_disk_unused($dev);
- PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
+
+ my $verify_params = { path => $path };
+ PVE::Storage::assert_sid_usable_on_node($name, $node, 'dir', $verify_params)
+ if $param->{add_storage};
my $mounted = PVE::Diskmanage::mounted_paths();
die "a mountpoint for '${name}' already exists: ${path} ($1)\n" if $mounted->{$path};
@@ -293,8 +296,7 @@ __PACKAGE__->register_method ({
path => $path,
nodes => $node,
};
-
- PVE::API2::Storage::Config->create($storage_params);
+ PVE::API2::Storage::Config->create_or_update($name, $node, $storage_params);
}
});
};
diff --git a/PVE/API2/Disks/LVM.pm b/PVE/API2/Disks/LVM.pm
index a27afe2..e9b3f25 100644
--- a/PVE/API2/Disks/LVM.pm
+++ b/PVE/API2/Disks/LVM.pm
@@ -150,7 +150,10 @@ __PACKAGE__->register_method ({
$dev = PVE::Diskmanage::verify_blockdev_path($dev);
PVE::Diskmanage::assert_disk_unused($dev);
- PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
+
+ my $verify_params = { vgname => $name };
+ PVE::Storage::assert_sid_usable_on_node($name, $node, 'lvm', $verify_params)
+ if $param->{add_storage};
die "volume group with name '${name}' already exists\n"
if PVE::Storage::LVMPlugin::lvm_vgs()->{$name};
@@ -177,8 +180,7 @@ __PACKAGE__->register_method ({
shared => 0,
nodes => $node,
};
-
- PVE::API2::Storage::Config->create($storage_params);
+ PVE::API2::Storage::Config->create_or_update($name, $node, $storage_params);
}
});
};
diff --git a/PVE/API2/Disks/LVMThin.pm b/PVE/API2/Disks/LVMThin.pm
index 690c183..fb61489 100644
--- a/PVE/API2/Disks/LVMThin.pm
+++ b/PVE/API2/Disks/LVMThin.pm
@@ -108,7 +108,10 @@ __PACKAGE__->register_method ({
$dev = PVE::Diskmanage::verify_blockdev_path($dev);
PVE::Diskmanage::assert_disk_unused($dev);
- PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
+
+ my $verify_params = { vgname => $name, thinpool => $name };
+ PVE::Storage::assert_sid_usable_on_node($name, $node, 'lvmthin', $verify_params)
+ if $param->{add_storage};
die "volume group with name '${name}' already exists\n"
if PVE::Storage::LVMPlugin::lvm_vgs()->{$name};
@@ -155,8 +158,7 @@ __PACKAGE__->register_method ({
content => 'rootdir,images',
nodes => $node,
};
-
- PVE::API2::Storage::Config->create($storage_params);
+ PVE::API2::Storage::Config->create_or_update($name, $node, $storage_params);
}
});
};
diff --git a/PVE/API2/Disks/ZFS.pm b/PVE/API2/Disks/ZFS.pm
index 51380c4..e1c4b59 100644
--- a/PVE/API2/Disks/ZFS.pm
+++ b/PVE/API2/Disks/ZFS.pm
@@ -342,6 +342,7 @@ __PACKAGE__->register_method ({
my $name = $param->{name};
my $node = $param->{node};
my $devs = [PVE::Tools::split_list($param->{devices})];
+ my $node = $param->{node};
my $raidlevel = $param->{raidlevel};
my $compression = $param->{compression} // 'on';
@@ -349,7 +350,10 @@ __PACKAGE__->register_method ({
$dev = PVE::Diskmanage::verify_blockdev_path($dev);
PVE::Diskmanage::assert_disk_unused($dev);
}
- PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
+
+ my $verify_params = { pool => $name };
+ PVE::Storage::assert_sid_usable_on_node($name, $node, 'zfspool', $verify_params)
+ if $param->{add_storage};
my $pools = get_pool_data();
die "pool '${name}' already exists on node '$node'\n"
@@ -439,8 +443,7 @@ __PACKAGE__->register_method ({
content => 'rootdir,images',
nodes => $param->{node},
};
-
- PVE::API2::Storage::Config->create($storage_params);
+ PVE::API2::Storage::Config->create_or_update($name, $node, $storage_params);
}
};
diff --git a/PVE/API2/Storage/Config.pm b/PVE/API2/Storage/Config.pm
index 6bd770e..2ea91b7 100755
--- a/PVE/API2/Storage/Config.pm
+++ b/PVE/API2/Storage/Config.pm
@@ -65,6 +65,28 @@ sub cleanup_storages_for_node {
}
}
+# Decides if a storage needs to be created or updated. An update is needed, if
+# the storage has a node list configured, then the current node will be added.
+# Check before if this is a sensible action, e.g. storage type and other params
+# that need to match
+sub create_or_update {
+ my ($self, $sid, $node, $storage_params) = @_;
+
+ my $cfg = PVE::Storage::config();
+ if (my $scfg = PVE::Storage::storage_config($cfg, $sid, 1)) {
+ if ($scfg->{nodes}) {
+ $scfg->{nodes}->{$node} = 1;
+ $self->update({
+ nodes => join(',', sort keys $scfg->{nodes}->%*),
+ storage => $sid,
+ });
+ print "Added '${node}' to nodes for storage '${sid}'\n";
+ }
+ } else {
+ $self->create($storage_params);
+ }
+}
+
__PACKAGE__->register_method ({
name => 'index',
path => '',
diff --git a/PVE/Storage.pm b/PVE/Storage.pm
index b9c53a1..21d575c 100755
--- a/PVE/Storage.pm
+++ b/PVE/Storage.pm
@@ -2127,6 +2127,33 @@ sub assert_sid_unused {
return undef;
}
+# Checks if storage id can be used on the node, intended for local storage types
+# Compares the type and verify_params hash against a potentially configured
+# storage. Use it for storage parameters that need to be the same throughout
+# the cluster. For example, pool for ZFS, vg_name for LVM, ...
+sub assert_sid_usable_on_node {
+ my ($sid, $node, $type, $verify_params) = @_;
+
+ my $cfg = config();
+ if (my $scfg = storage_config($cfg, $sid, 1)) {
+ $node = PVE::INotify::nodename() if !$node || ($node eq 'localhost');
+ die "Storage ID '${sid}' already exists on node ${node}\n"
+ if defined($scfg->{nodes}) && $scfg->{nodes}->{$node};
+
+ $verify_params->{type} = $type;
+ for my $key (keys %$verify_params) {
+ if (!defined($scfg->{$key})) {
+ die "Option '${key}' is not configured for storage '$sid', "
+ ."expected it to be '$verify_params->{$key}'";
+ }
+ if ($verify_params->{$key} ne $scfg->{$key}) {
+ die "Option '${key}' ($verify_params->{$key}) does not match "
+ ."existing storage configuration '$scfg->{$key}'\n";
+ }
+ }
+ }
+}
+
# removes leading/trailing spaces and (back)slashes completely
# substitutes every non-ASCII-alphanumerical char with '_', except '_.-'
sub normalize_content_filename {
--
2.30.2
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [pve-devel] [PATCH storage v2 1/3] diskmanage: add mounted_paths
2022-07-15 11:58 ` [pve-devel] [PATCH storage v2 1/3] diskmanage: add mounted_paths Aaron Lauterer
@ 2022-08-17 11:35 ` Fabian Grünbichler
0 siblings, 0 replies; 13+ messages in thread
From: Fabian Grünbichler @ 2022-08-17 11:35 UTC (permalink / raw)
To: Proxmox VE development discussion
On July 15, 2022 1:58 pm, Aaron Lauterer wrote:
> returns a list of mounted paths with the backing devices
>
> Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
> ---
> changes since v1: dropped limit to /dev path, returning all mounted
> paths now
>
> PVE/Diskmanage.pm | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
> diff --git a/PVE/Diskmanage.pm b/PVE/Diskmanage.pm
> index 8ed7a8b..b149685 100644
> --- a/PVE/Diskmanage.pm
> +++ b/PVE/Diskmanage.pm
> @@ -499,6 +499,18 @@ sub mounted_blockdevs {
> return $mounted;
> }
>
nit: a short comment here telling us about the returned data might be
helpful - else I have to look at parse_proc_mounts or guess what the key
and what the value represent..
> +sub mounted_paths {
> + my $mounted = {};
> +
> + my $mounts = PVE::ProcFSTools::parse_proc_mounts();
> +
> + foreach my $mount (@$mounts) {
> + $mounted->{abs_path($mount->[1])} = $mount->[0];
> + };
> +
> + return $mounted;
> +}
> +
> sub get_disks {
> my ($disks, $nosmart, $include_partitions) = @_;
> my $disklist = {};
> --
> 2.30.2
>
>
>
> _______________________________________________
> pve-devel mailing list
> pve-devel@lists.proxmox.com
> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
>
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [pve-devel] [PATCH storage v2 2/3] disks: die if storage name is already in use
2022-07-15 11:58 ` [pve-devel] [PATCH storage v2 2/3] disks: die if storage name is already in use Aaron Lauterer
@ 2022-08-17 11:42 ` Fabian Grünbichler
2022-08-18 15:22 ` Aaron Lauterer
0 siblings, 1 reply; 13+ messages in thread
From: Fabian Grünbichler @ 2022-08-17 11:42 UTC (permalink / raw)
To: Proxmox VE development discussion
On July 15, 2022 1:58 pm, Aaron Lauterer wrote:
> If a storage of that type and name already exists (LVM, zpool, ...) but
> we do not have a Proxmox VE Storage config for it, it is possible that
> the creation will fail midway due to checks done by the underlying
> storage layer itself. This in turn can lead to disks that are already
> partitioned. Users would need to clean this up themselves.
>
> By adding checks early on, not only checking against the PVE storage
> config, but against the actual storage type itself, we can die early
> enough, before we touch any disk.
>
> For ZFS, the logic to gather pool data is moved into its own function to
> be called from the index API endpoint and the check in the create
> endpoint.
>
> Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
> ---
>
> changes since v1:
> - moved zfs pool gathering from index api endpoint into its own function
> to easily call it for the check as well
> - zfs pool check is now using perl grep
> - removed check if mounted path if a /dev one
> - added check if a mount unit exists
> - moved definitions of $path, $mountunitname and $mountunitpath out
> of the worker
>
> PVE/API2/Disks/Directory.pm | 11 ++++--
> PVE/API2/Disks/LVM.pm | 3 ++
> PVE/API2/Disks/LVMThin.pm | 3 ++
> PVE/API2/Disks/ZFS.pm | 77 +++++++++++++++++++++----------------
> 4 files changed, 56 insertions(+), 38 deletions(-)
>
> diff --git a/PVE/API2/Disks/Directory.pm b/PVE/API2/Disks/Directory.pm
> index df63ba9..07190de 100644
> --- a/PVE/API2/Disks/Directory.pm
> +++ b/PVE/API2/Disks/Directory.pm
> @@ -203,16 +203,19 @@ __PACKAGE__->register_method ({
> my $dev = $param->{device};
> my $node = $param->{node};
> my $type = $param->{filesystem} // 'ext4';
> + my $path = "/mnt/pve/$name";
> + my $mountunitname = PVE::Systemd::escape_unit($path, 1) . ".mount";
> + my $mountunitpath = "/etc/systemd/system/$mountunitname";
>
> $dev = PVE::Diskmanage::verify_blockdev_path($dev);
> PVE::Diskmanage::assert_disk_unused($dev);
> PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
>
> - my $worker = sub {
> - my $path = "/mnt/pve/$name";
> - my $mountunitname = PVE::Systemd::escape_unit($path, 1) . ".mount";
> - my $mountunitpath = "/etc/systemd/system/$mountunitname";
> + my $mounted = PVE::Diskmanage::mounted_paths();
> + die "a mountpoint for '${name}' already exists: ${path} ($1)\n" if $mounted->{$path};
nit: the mountpoint existing is not the issue (something already being
mounted there is!). also, where does the $1 come from?
> + die "a systemd mount unit already exists: ${mountunitpath}\n" if -e $mountunitpath;
could check if it's identical to the one we'd generate (in the spirit of
patch #3 ;))
>
> + my $worker = sub {
> PVE::Diskmanage::locked_disk_action(sub {
> PVE::Diskmanage::assert_disk_unused($dev);
>
> diff --git a/PVE/API2/Disks/LVM.pm b/PVE/API2/Disks/LVM.pm
> index 6e4331a..a27afe2 100644
> --- a/PVE/API2/Disks/LVM.pm
> +++ b/PVE/API2/Disks/LVM.pm
> @@ -152,6 +152,9 @@ __PACKAGE__->register_method ({
> PVE::Diskmanage::assert_disk_unused($dev);
> PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
>
> + die "volume group with name '${name}' already exists\n"
> + if PVE::Storage::LVMPlugin::lvm_vgs()->{$name};
probably better off inside the worker, since `vgs` might take a while
(although we also use it in the index API call in this module..)
> +
> my $worker = sub {
> PVE::Diskmanage::locked_disk_action(sub {
> PVE::Diskmanage::assert_disk_unused($dev);
> diff --git a/PVE/API2/Disks/LVMThin.pm b/PVE/API2/Disks/LVMThin.pm
> index 58ecb37..690c183 100644
> --- a/PVE/API2/Disks/LVMThin.pm
> +++ b/PVE/API2/Disks/LVMThin.pm
> @@ -110,6 +110,9 @@ __PACKAGE__->register_method ({
> PVE::Diskmanage::assert_disk_unused($dev);
> PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
>
> + die "volume group with name '${name}' already exists\n"
> + if PVE::Storage::LVMPlugin::lvm_vgs()->{$name};
> +
same here
> my $worker = sub {
> PVE::Diskmanage::locked_disk_action(sub {
> PVE::Diskmanage::assert_disk_unused($dev);
> diff --git a/PVE/API2/Disks/ZFS.pm b/PVE/API2/Disks/ZFS.pm
> index eeb9f48..51380c4 100644
> --- a/PVE/API2/Disks/ZFS.pm
> +++ b/PVE/API2/Disks/ZFS.pm
> @@ -18,6 +18,43 @@ use base qw(PVE::RESTHandler);
> my $ZPOOL = '/sbin/zpool';
> my $ZFS = '/sbin/zfs';
>
> +sub get_pool_data {
> + if (!-f $ZPOOL) {
> + die "zfsutils-linux not installed\n";
> + }
> +
> + my $propnames = [qw(name size alloc free frag dedup health)];
> + my $numbers = {
> + size => 1,
> + alloc => 1,
> + free => 1,
> + frag => 1,
> + dedup => 1,
> + };
> +
> + my $cmd = [$ZPOOL,'list', '-HpPLo', join(',', @$propnames)];
> +
> + my $pools = [];
> +
> + run_command($cmd, outfunc => sub {
> + my ($line) = @_;
> +
> + my @props = split('\s+', trim($line));
> + my $pool = {};
> + for (my $i = 0; $i < scalar(@$propnames); $i++) {
> + if ($numbers->{$propnames->[$i]}) {
> + $pool->{$propnames->[$i]} = $props[$i] + 0;
> + } else {
> + $pool->{$propnames->[$i]} = $props[$i];
> + }
> + }
> +
> + push @$pools, $pool;
> + });
> +
> + return $pools;
> +}
> +
> __PACKAGE__->register_method ({
> name => 'index',
> path => '',
> @@ -74,40 +111,7 @@ __PACKAGE__->register_method ({
> code => sub {
> my ($param) = @_;
>
> - if (!-f $ZPOOL) {
> - die "zfsutils-linux not installed\n";
> - }
> -
> - my $propnames = [qw(name size alloc free frag dedup health)];
> - my $numbers = {
> - size => 1,
> - alloc => 1,
> - free => 1,
> - frag => 1,
> - dedup => 1,
> - };
> -
> - my $cmd = [$ZPOOL,'list', '-HpPLo', join(',', @$propnames)];
> -
> - my $pools = [];
> -
> - run_command($cmd, outfunc => sub {
> - my ($line) = @_;
> -
> - my @props = split('\s+', trim($line));
> - my $pool = {};
> - for (my $i = 0; $i < scalar(@$propnames); $i++) {
> - if ($numbers->{$propnames->[$i]}) {
> - $pool->{$propnames->[$i]} = $props[$i] + 0;
> - } else {
> - $pool->{$propnames->[$i]} = $props[$i];
> - }
> - }
> -
> - push @$pools, $pool;
> - });
> -
> - return $pools;
> + return get_pool_data();
> }});
>
> sub preparetree {
> @@ -336,6 +340,7 @@ __PACKAGE__->register_method ({
> my $user = $rpcenv->get_user();
>
> my $name = $param->{name};
> + my $node = $param->{node};
nit: please also change the usage further below in this API handler if
you do this
> my $devs = [PVE::Tools::split_list($param->{devices})];
> my $raidlevel = $param->{raidlevel};
> my $compression = $param->{compression} // 'on';
> @@ -346,6 +351,10 @@ __PACKAGE__->register_method ({
> }
> PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
>
> + my $pools = get_pool_data();
and also here
> + die "pool '${name}' already exists on node '$node'\n"
> + if grep { $_->{name} eq $name } @{$pools};
> +
> my $numdisks = scalar(@$devs);
> my $mindisks = {
> single => 1,
> --
> 2.30.2
>
>
>
> _______________________________________________
> pve-devel mailing list
> pve-devel@lists.proxmox.com
> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
>
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [pve-devel] [PATCH storage v2 3/3] disks: allow add_storage for already configured local storage
2022-07-15 11:58 ` [pve-devel] [PATCH storage v2 3/3] disks: allow add_storage for already configured local storage Aaron Lauterer
@ 2022-08-17 11:53 ` Fabian Grünbichler
0 siblings, 0 replies; 13+ messages in thread
From: Fabian Grünbichler @ 2022-08-17 11:53 UTC (permalink / raw)
To: Proxmox VE development discussion
On July 15, 2022 1:58 pm, Aaron Lauterer wrote:
> One of the smaller annoyances, especially for less experienced users, is
> the fact, that when creating a local storage (ZFS, LVM (thin), dir) in a
> cluster, one can only leave the "Add Storage" option enabled the first
> time.
>
> On any following node, this option needed to be disabled and the new
> node manually added to the list of nodes for that storage.
>
> This patch changes the behavior. If a storage of the same name already
> exists, it will verify that necessary parameters match the already
> existing one.
> Then, if the 'nodes' parameter is set, it adds the current node and
> updates the storage config.
> In case there is no nodes list, nothing else needs to be done, and the
> GUI will stop showing the question mark for the configured, but until
> then, not existing local storage.
>
> Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
> ---
> changes since v1:
> - restructured the logic a bit. checks still need to be done the same,
> but the create or update logic is in its own
> API2::Storage::Config->create_or_update function which then either
> calls the create or update API directly. This reduces a lot of code
> repition.
> - in Storage::assert_sid_usable_on_node additionally checks if the
> parameter is configured in the storage and fails if not. We would have
> gotten warnings about using and undef in a string concat due to how the
> other error was presented.
>
> PVE/API2/Disks/Directory.pm | 8 +++++---
> PVE/API2/Disks/LVM.pm | 8 +++++---
> PVE/API2/Disks/LVMThin.pm | 8 +++++---
> PVE/API2/Disks/ZFS.pm | 9 ++++++---
> PVE/API2/Storage/Config.pm | 22 ++++++++++++++++++++++
> PVE/Storage.pm | 27 +++++++++++++++++++++++++++
> 6 files changed, 70 insertions(+), 12 deletions(-)
>
> diff --git a/PVE/API2/Disks/Directory.pm b/PVE/API2/Disks/Directory.pm
> index 07190de..581e970 100644
> --- a/PVE/API2/Disks/Directory.pm
> +++ b/PVE/API2/Disks/Directory.pm
> @@ -209,7 +209,10 @@ __PACKAGE__->register_method ({
>
> $dev = PVE::Diskmanage::verify_blockdev_path($dev);
> PVE::Diskmanage::assert_disk_unused($dev);
> - PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
> +
> + my $verify_params = { path => $path };
> + PVE::Storage::assert_sid_usable_on_node($name, $node, 'dir', $verify_params)
> + if $param->{add_storage};
>
> my $mounted = PVE::Diskmanage::mounted_paths();
> die "a mountpoint for '${name}' already exists: ${path} ($1)\n" if $mounted->{$path};
> @@ -293,8 +296,7 @@ __PACKAGE__->register_method ({
> path => $path,
> nodes => $node,
> };
> -
> - PVE::API2::Storage::Config->create($storage_params);
> + PVE::API2::Storage::Config->create_or_update($name, $node, $storage_params);
> }
> });
> };
> diff --git a/PVE/API2/Disks/LVM.pm b/PVE/API2/Disks/LVM.pm
> index a27afe2..e9b3f25 100644
> --- a/PVE/API2/Disks/LVM.pm
> +++ b/PVE/API2/Disks/LVM.pm
> @@ -150,7 +150,10 @@ __PACKAGE__->register_method ({
>
> $dev = PVE::Diskmanage::verify_blockdev_path($dev);
> PVE::Diskmanage::assert_disk_unused($dev);
> - PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
> +
> + my $verify_params = { vgname => $name };
> + PVE::Storage::assert_sid_usable_on_node($name, $node, 'lvm', $verify_params)
> + if $param->{add_storage};
>
> die "volume group with name '${name}' already exists\n"
> if PVE::Storage::LVMPlugin::lvm_vgs()->{$name};
> @@ -177,8 +180,7 @@ __PACKAGE__->register_method ({
> shared => 0,
> nodes => $node,
> };
> -
> - PVE::API2::Storage::Config->create($storage_params);
> + PVE::API2::Storage::Config->create_or_update($name, $node, $storage_params);
> }
> });
> };
> diff --git a/PVE/API2/Disks/LVMThin.pm b/PVE/API2/Disks/LVMThin.pm
> index 690c183..fb61489 100644
> --- a/PVE/API2/Disks/LVMThin.pm
> +++ b/PVE/API2/Disks/LVMThin.pm
> @@ -108,7 +108,10 @@ __PACKAGE__->register_method ({
>
> $dev = PVE::Diskmanage::verify_blockdev_path($dev);
> PVE::Diskmanage::assert_disk_unused($dev);
> - PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
> +
> + my $verify_params = { vgname => $name, thinpool => $name };
> + PVE::Storage::assert_sid_usable_on_node($name, $node, 'lvmthin', $verify_params)
> + if $param->{add_storage};
>
> die "volume group with name '${name}' already exists\n"
> if PVE::Storage::LVMPlugin::lvm_vgs()->{$name};
> @@ -155,8 +158,7 @@ __PACKAGE__->register_method ({
> content => 'rootdir,images',
> nodes => $node,
> };
> -
> - PVE::API2::Storage::Config->create($storage_params);
> + PVE::API2::Storage::Config->create_or_update($name, $node, $storage_params);
> }
> });
> };
> diff --git a/PVE/API2/Disks/ZFS.pm b/PVE/API2/Disks/ZFS.pm
> index 51380c4..e1c4b59 100644
> --- a/PVE/API2/Disks/ZFS.pm
> +++ b/PVE/API2/Disks/ZFS.pm
> @@ -342,6 +342,7 @@ __PACKAGE__->register_method ({
> my $name = $param->{name};
> my $node = $param->{node};
> my $devs = [PVE::Tools::split_list($param->{devices})];
> + my $node = $param->{node};
> my $raidlevel = $param->{raidlevel};
> my $compression = $param->{compression} // 'on';
>
> @@ -349,7 +350,10 @@ __PACKAGE__->register_method ({
> $dev = PVE::Diskmanage::verify_blockdev_path($dev);
> PVE::Diskmanage::assert_disk_unused($dev);
> }
> - PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
> +
> + my $verify_params = { pool => $name };
> + PVE::Storage::assert_sid_usable_on_node($name, $node, 'zfspool', $verify_params)
> + if $param->{add_storage};
>
> my $pools = get_pool_data();
> die "pool '${name}' already exists on node '$node'\n"
> @@ -439,8 +443,7 @@ __PACKAGE__->register_method ({
> content => 'rootdir,images',
> nodes => $param->{node},
> };
> -
> - PVE::API2::Storage::Config->create($storage_params);
> + PVE::API2::Storage::Config->create_or_update($name, $node, $storage_params);
> }
> };
>
> diff --git a/PVE/API2/Storage/Config.pm b/PVE/API2/Storage/Config.pm
> index 6bd770e..2ea91b7 100755
> --- a/PVE/API2/Storage/Config.pm
> +++ b/PVE/API2/Storage/Config.pm
> @@ -65,6 +65,28 @@ sub cleanup_storages_for_node {
> }
> }
>
> +# Decides if a storage needs to be created or updated. An update is needed, if
> +# the storage has a node list configured, then the current node will be added.
> +# Check before if this is a sensible action, e.g. storage type and other params
> +# that need to match
> +sub create_or_update {
> + my ($self, $sid, $node, $storage_params) = @_;
> +
> + my $cfg = PVE::Storage::config();
> + if (my $scfg = PVE::Storage::storage_config($cfg, $sid, 1)) {
> + if ($scfg->{nodes}) {
> + $scfg->{nodes}->{$node} = 1;
> + $self->update({
> + nodes => join(',', sort keys $scfg->{nodes}->%*),
> + storage => $sid,
> + });
> + print "Added '${node}' to nodes for storage '${sid}'\n";
> + }
> + } else {
> + $self->create($storage_params);
> + }
> +}
> +
> __PACKAGE__->register_method ({
> name => 'index',
> path => '',
> diff --git a/PVE/Storage.pm b/PVE/Storage.pm
> index b9c53a1..21d575c 100755
> --- a/PVE/Storage.pm
> +++ b/PVE/Storage.pm
> @@ -2127,6 +2127,33 @@ sub assert_sid_unused {
> return undef;
> }
>
> +# Checks if storage id can be used on the node, intended for local storage types
> +# Compares the type and verify_params hash against a potentially configured
> +# storage. Use it for storage parameters that need to be the same throughout
> +# the cluster. For example, pool for ZFS, vg_name for LVM, ...
> +sub assert_sid_usable_on_node {
> + my ($sid, $node, $type, $verify_params) = @_;
couldn't this be folded into create_or_update, e.g. by adding a
check/dry_run flag that skips the actual update/creation? then we could
call it once at the beginning (with dry_run set) and once for actual
adding/updating, and we don't risk forgetting about some parameter later
on when changing the code.
$node is always the local node (and passed to create_or_update via
$storage_params->{nodes}), $type is passed to create_or_update (via
$storage_params), and $verify_params is just a subset of $storage_params
(where we actually want to check that everything matches anyway, except
for nodes which already is special-cased for the update part), so we
might as well pass the full thing ;) or am I missing something here?
> +
> + my $cfg = config();
> + if (my $scfg = storage_config($cfg, $sid, 1)) {
> + $node = PVE::INotify::nodename() if !$node || ($node eq 'localhost');
> + die "Storage ID '${sid}' already exists on node ${node}\n"
> + if defined($scfg->{nodes}) && $scfg->{nodes}->{$node};
> +
> + $verify_params->{type} = $type;
> + for my $key (keys %$verify_params) {
> + if (!defined($scfg->{$key})) {
> + die "Option '${key}' is not configured for storage '$sid', "
> + ."expected it to be '$verify_params->{$key}'";
> + }
> + if ($verify_params->{$key} ne $scfg->{$key}) {
> + die "Option '${key}' ($verify_params->{$key}) does not match "
> + ."existing storage configuration '$scfg->{$key}'\n";
> + }
> + }
> + }
> +}
> +
> # removes leading/trailing spaces and (back)slashes completely
> # substitutes every non-ASCII-alphanumerical char with '_', except '_.-'
> sub normalize_content_filename {
> --
> 2.30.2
>
>
>
> _______________________________________________
> pve-devel mailing list
> pve-devel@lists.proxmox.com
> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
>
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [pve-devel] [PATCH storage v2 2/3] disks: die if storage name is already in use
2022-08-17 11:42 ` Fabian Grünbichler
@ 2022-08-18 15:22 ` Aaron Lauterer
2022-08-18 15:31 ` Aaron Lauterer
2022-08-19 8:20 ` Fabian Grünbichler
0 siblings, 2 replies; 13+ messages in thread
From: Aaron Lauterer @ 2022-08-18 15:22 UTC (permalink / raw)
To: Proxmox VE development discussion, Fabian Grünbichler
On 8/17/22 13:42, Fabian Grünbichler wrote:
> On July 15, 2022 1:58 pm, Aaron Lauterer wrote:
[...]
>> - my $worker = sub {
>> - my $path = "/mnt/pve/$name";
>> - my $mountunitname = PVE::Systemd::escape_unit($path, 1) . ".mount";
>> - my $mountunitpath = "/etc/systemd/system/$mountunitname";
>> + my $mounted = PVE::Diskmanage::mounted_paths();
>> + die "a mountpoint for '${name}' already exists: ${path} ($1)\n" if $mounted->{$path};
>
> nit: the mountpoint existing is not the issue (something already being
> mounted there is!). also, where does the $1 come from?
good point and thanks for catching the $1
>
>> + die "a systemd mount unit already exists: ${mountunitpath}\n" if -e $mountunitpath;
>
> could check if it's identical to the one we'd generate (in the spirit of
> patch #3 ;))
I looked into it, depending on how hard we want to match the mount unit, this
could be a bit hard. It contains the /dev/disk/by-uuid/... path which will not
be the same as it changes with each FS creation (IIUC).
>
>>
>> + my $worker = sub {
>> PVE::Diskmanage::locked_disk_action(sub {
>> PVE::Diskmanage::assert_disk_unused($dev);
>>
>> diff --git a/PVE/API2/Disks/LVM.pm b/PVE/API2/Disks/LVM.pm
>> index 6e4331a..a27afe2 100644
>> --- a/PVE/API2/Disks/LVM.pm
>> +++ b/PVE/API2/Disks/LVM.pm
>> @@ -152,6 +152,9 @@ __PACKAGE__->register_method ({
>> PVE::Diskmanage::assert_disk_unused($dev);
>> PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
>>
>> + die "volume group with name '${name}' already exists\n"
>> + if PVE::Storage::LVMPlugin::lvm_vgs()->{$name};
>
> probably better off inside the worker, since `vgs` might take a while
> (although we also use it in the index API call in this module..)
From a GUI perspective: putting it in a worker would result in the user to hit
okay and then will see the failed task right? Keeping it as is will result in an
error popping up when clicking ok/create and the user can edit the name instead
of starting all over again. Though, if `vgs` really needs a bit, that error
popping up could take a moment or two.
[...]
>> sub preparetree {
>> @@ -336,6 +340,7 @@ __PACKAGE__->register_method ({
>> my $user = $rpcenv->get_user();
>>
>> my $name = $param->{name};
>> + my $node = $param->{node};
>
> nit: please also change the usage further below in this API handler if
> you do this
what exactly do you mean? defining local variables for $param->{..} ones?
>
>> my $devs = [PVE::Tools::split_list($param->{devices})];
>> my $raidlevel = $param->{raidlevel};
>> my $compression = $param->{compression} // 'on';
>> @@ -346,6 +351,10 @@ __PACKAGE__->register_method ({
>> }
>> PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
>>
>> + my $pools = get_pool_data();
>
> and also here
>
>> + die "pool '${name}' already exists on node '$node'\n"
>> + if grep { $_->{name} eq $name } @{$pools};
>> +
>> my $numdisks = scalar(@$devs);
>> my $mindisks = {
>> single => 1,
>> --
>> 2.30.2
>>
>>
>>
>> _______________________________________________
>> pve-devel mailing list
>> pve-devel@lists.proxmox.com
>> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
>>
>>
>>
>
>
> _______________________________________________
> pve-devel mailing list
> pve-devel@lists.proxmox.com
> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [pve-devel] [PATCH storage v2 2/3] disks: die if storage name is already in use
2022-08-18 15:22 ` Aaron Lauterer
@ 2022-08-18 15:31 ` Aaron Lauterer
2022-08-19 8:21 ` Fabian Grünbichler
2022-08-19 8:20 ` Fabian Grünbichler
1 sibling, 1 reply; 13+ messages in thread
From: Aaron Lauterer @ 2022-08-18 15:31 UTC (permalink / raw)
To: Proxmox VE development discussion, Fabian Grünbichler
On 8/18/22 17:22, Aaron Lauterer wrote:
>
>
> On 8/17/22 13:42, Fabian Grünbichler wrote:[..]
>>> + die "a systemd mount unit already exists: ${mountunitpath}\n" if -e
>>> $mountunitpath;
>>
>> could check if it's identical to the one we'd generate (in the spirit of
>> patch #3 ;))
>
> I looked into it, depending on how hard we want to match the mount unit, this
> could be a bit hard. It contains the /dev/disk/by-uuid/... path which will not
> be the same as it changes with each FS creation (IIUC).
The question is, if it is a good idea to have the check since there is no easy
way for the user to remedy the problem without doing a manual `rm
/etc/systemd/system/foo.mount`.
Putting more work into improving the whole storage mgmt situation is of course
also something we could do.
[...]
>
>>> sub preparetree {
>>> @@ -336,6 +340,7 @@ __PACKAGE__->register_method ({
>>> my $user = $rpcenv->get_user();
>>> my $name = $param->{name};
>>> + my $node = $param->{node};
>>
>> nit: please also change the usage further below in this API handler if
>> you do this
>
> what exactly do you mean? defining local variables for $param->{..} ones?
>
okay I think I got it. was confused by looking at another part of the code.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [pve-devel] [PATCH storage v2 2/3] disks: die if storage name is already in use
2022-08-18 15:22 ` Aaron Lauterer
2022-08-18 15:31 ` Aaron Lauterer
@ 2022-08-19 8:20 ` Fabian Grünbichler
2022-08-19 9:28 ` Aaron Lauterer
1 sibling, 1 reply; 13+ messages in thread
From: Fabian Grünbichler @ 2022-08-19 8:20 UTC (permalink / raw)
To: Aaron Lauterer, Proxmox VE development discussion
On August 18, 2022 5:22 pm, Aaron Lauterer wrote:
>
>
> On 8/17/22 13:42, Fabian Grünbichler wrote:
>> On July 15, 2022 1:58 pm, Aaron Lauterer wrote:
> [...]
>>> - my $worker = sub {
>>> - my $path = "/mnt/pve/$name";
>>> - my $mountunitname = PVE::Systemd::escape_unit($path, 1) . ".mount";
>>> - my $mountunitpath = "/etc/systemd/system/$mountunitname";
>>> + my $mounted = PVE::Diskmanage::mounted_paths();
>>> + die "a mountpoint for '${name}' already exists: ${path} ($1)\n" if $mounted->{$path};
>>
>> nit: the mountpoint existing is not the issue (something already being
>> mounted there is!). also, where does the $1 come from?
>
> good point and thanks for catching the $1
>>
>>> + die "a systemd mount unit already exists: ${mountunitpath}\n" if -e $mountunitpath;
>>
>> could check if it's identical to the one we'd generate (in the spirit of
>> patch #3 ;))
>
> I looked into it, depending on how hard we want to match the mount unit, this
> could be a bit hard. It contains the /dev/disk/by-uuid/... path which will not
> be the same as it changes with each FS creation (IIUC).
>
makes sense, and no, we definitely don't want any fancy heuristics for
"close enough to ignore it already exists" ;) so this can stay as it is.
>>
>>>
>>> + my $worker = sub {
>>> PVE::Diskmanage::locked_disk_action(sub {
>>> PVE::Diskmanage::assert_disk_unused($dev);
>>>
>>> diff --git a/PVE/API2/Disks/LVM.pm b/PVE/API2/Disks/LVM.pm
>>> index 6e4331a..a27afe2 100644
>>> --- a/PVE/API2/Disks/LVM.pm
>>> +++ b/PVE/API2/Disks/LVM.pm
>>> @@ -152,6 +152,9 @@ __PACKAGE__->register_method ({
>>> PVE::Diskmanage::assert_disk_unused($dev);
>>> PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
>>>
>>> + die "volume group with name '${name}' already exists\n"
>>> + if PVE::Storage::LVMPlugin::lvm_vgs()->{$name};
>>
>> probably better off inside the worker, since `vgs` might take a while
>> (although we also use it in the index API call in this module..)
>
> From a GUI perspective: putting it in a worker would result in the user to hit
> okay and then will see the failed task right? Keeping it as is will result in an
> error popping up when clicking ok/create and the user can edit the name instead
> of starting all over again. Though, if `vgs` really needs a bit, that error
> popping up could take a moment or two.
yes, putting it in the worker means no early-failure. but not putting it
in the worker potentially means this API endpoint cannot be called on
systems with busy LVM at all (30s timeout for API requests!). so
early-failure checks should almost always only do "logical" things that
are cheap (like reading a conf file and checking invariants), and
nothing that can reasonably block for some time (like storage
operations, starting guests, ..). I know we are not 100% consistent
there (the worst offender is probably the storage content API endpoint
;)), but we should try to not introduce more problems of that fashion
but rather work on removing the existing ones.
>
> [...]
>
>>> sub preparetree {
>>> @@ -336,6 +340,7 @@ __PACKAGE__->register_method ({
>>> my $user = $rpcenv->get_user();
>>>
>>> my $name = $param->{name};
>>> + my $node = $param->{node};
>>
>> nit: please also change the usage further below in this API handler if
>> you do this
>
> what exactly do you mean? defining local variables for $param->{..} ones?
the usage of $param->{node} below in this handler should (also) switch
to $node - we don't want two places with the same information, that can
cause subtle breakage in the future when only one of them gets
modified/..
>
>>
>>> my $devs = [PVE::Tools::split_list($param->{devices})];
>>> my $raidlevel = $param->{raidlevel};
>>> my $compression = $param->{compression} // 'on';
>>> @@ -346,6 +351,10 @@ __PACKAGE__->register_method ({
>>> }
>>> PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
>>>
>>> + my $pools = get_pool_data();
>>
>> and also here
>>
>>> + die "pool '${name}' already exists on node '$node'\n"
>>> + if grep { $_->{name} eq $name } @{$pools};
>>> +
>>> my $numdisks = scalar(@$devs);
>>> my $mindisks = {
>>> single => 1,
>>> --
>>> 2.30.2
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [pve-devel] [PATCH storage v2 2/3] disks: die if storage name is already in use
2022-08-18 15:31 ` Aaron Lauterer
@ 2022-08-19 8:21 ` Fabian Grünbichler
2022-08-19 9:29 ` Aaron Lauterer
0 siblings, 1 reply; 13+ messages in thread
From: Fabian Grünbichler @ 2022-08-19 8:21 UTC (permalink / raw)
To: Proxmox VE development discussion
On August 18, 2022 5:31 pm, Aaron Lauterer wrote:
>
>
> On 8/18/22 17:22, Aaron Lauterer wrote:
>>
>>
>> On 8/17/22 13:42, Fabian Grünbichler wrote:[..]
>>>> + die "a systemd mount unit already exists: ${mountunitpath}\n" if -e
>>>> $mountunitpath;
>>>
>>> could check if it's identical to the one we'd generate (in the spirit of
>>> patch #3 ;))
>>
>> I looked into it, depending on how hard we want to match the mount unit, this
>> could be a bit hard. It contains the /dev/disk/by-uuid/... path which will not
>> be the same as it changes with each FS creation (IIUC).
>
> The question is, if it is a good idea to have the check since there is no easy
> way for the user to remedy the problem without doing a manual `rm
> /etc/systemd/system/foo.mount`.
*could* be solved by having a force parameter I guess? not sure that's a
good idea, just throwing it out there ;)
> Putting more work into improving the whole storage mgmt situation is of course
> also something we could do.
>
> [...]
>>
>>>> sub preparetree {
>>>> @@ -336,6 +340,7 @@ __PACKAGE__->register_method ({
>>>> my $user = $rpcenv->get_user();
>>>> my $name = $param->{name};
>>>> + my $node = $param->{node};
>>>
>>> nit: please also change the usage further below in this API handler if
>>> you do this
>>
>> what exactly do you mean? defining local variables for $param->{..} ones?
>>
>
> okay I think I got it. was confused by looking at another part of the code.
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [pve-devel] [PATCH storage v2 2/3] disks: die if storage name is already in use
2022-08-19 8:20 ` Fabian Grünbichler
@ 2022-08-19 9:28 ` Aaron Lauterer
0 siblings, 0 replies; 13+ messages in thread
From: Aaron Lauterer @ 2022-08-19 9:28 UTC (permalink / raw)
To: Fabian Grünbichler, Proxmox VE development discussion
On 8/19/22 10:20, Fabian Grünbichler wrote:
> On August 18, 2022 5:22 pm, Aaron Lauterer wrote:
>>
>>>>
>>>> diff --git a/PVE/API2/Disks/LVM.pm b/PVE/API2/Disks/LVM.pm
>>>> index 6e4331a..a27afe2 100644
>>>> --- a/PVE/API2/Disks/LVM.pm
>>>> +++ b/PVE/API2/Disks/LVM.pm
>>>> @@ -152,6 +152,9 @@ __PACKAGE__->register_method ({
>>>> PVE::Diskmanage::assert_disk_unused($dev);
>>>> PVE::Storage::assert_sid_unused($name) if $param->{add_storage};
>>>>
>>>> + die "volume group with name '${name}' already exists\n"
>>>> + if PVE::Storage::LVMPlugin::lvm_vgs()->{$name};
>>>
>>> probably better off inside the worker, since `vgs` might take a while
>>> (although we also use it in the index API call in this module..)
>>
>> From a GUI perspective: putting it in a worker would result in the user to hit
>> okay and then will see the failed task right? Keeping it as is will result in an
>> error popping up when clicking ok/create and the user can edit the name instead
>> of starting all over again. Though, if `vgs` really needs a bit, that error
>> popping up could take a moment or two.
>
> yes, putting it in the worker means no early-failure. but not putting it
> in the worker potentially means this API endpoint cannot be called on
> systems with busy LVM at all (30s timeout for API requests!). so
> early-failure checks should almost always only do "logical" things that
> are cheap (like reading a conf file and checking invariants), and
> nothing that can reasonably block for some time (like storage
> operations, starting guests, ..). I know we are not 100% consistent
> there (the worst offender is probably the storage content API endpoint
> ;)), but we should try to not introduce more problems of that fashion
> but rather work on removing the existing ones.
good point. I'll put the check inside the worker.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [pve-devel] [PATCH storage v2 2/3] disks: die if storage name is already in use
2022-08-19 8:21 ` Fabian Grünbichler
@ 2022-08-19 9:29 ` Aaron Lauterer
0 siblings, 0 replies; 13+ messages in thread
From: Aaron Lauterer @ 2022-08-19 9:29 UTC (permalink / raw)
To: pve-devel
On 8/19/22 10:21, Fabian Grünbichler wrote:
> On August 18, 2022 5:31 pm, Aaron Lauterer wrote:
>>
>>
>> On 8/18/22 17:22, Aaron Lauterer wrote:
>>>
>>>
>>> On 8/17/22 13:42, Fabian Grünbichler wrote:[..]
>>>>> + die "a systemd mount unit already exists: ${mountunitpath}\n" if -e
>>>>> $mountunitpath;
>>>>
>>>> could check if it's identical to the one we'd generate (in the spirit of
>>>> patch #3 ;))
>>>
>>> I looked into it, depending on how hard we want to match the mount unit, this
>>> could be a bit hard. It contains the /dev/disk/by-uuid/... path which will not
>>> be the same as it changes with each FS creation (IIUC).
>>
>> The question is, if it is a good idea to have the check since there is no easy
>> way for the user to remedy the problem without doing a manual `rm
>> /etc/systemd/system/foo.mount`.
>
> *could* be solved by having a force parameter I guess? not sure that's a
> good idea, just throwing it out there ;)
>
a short off list discussion brought up that we indeed can remove dangling mount
units already, so keeping the check is okay since users can quite easily remove it
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2022-08-19 9:29 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-15 11:58 [pve-devel] [PATCH storage v2 0/3] disks: add checks, allow add_storage on other nodes Aaron Lauterer
2022-07-15 11:58 ` [pve-devel] [PATCH storage v2 1/3] diskmanage: add mounted_paths Aaron Lauterer
2022-08-17 11:35 ` Fabian Grünbichler
2022-07-15 11:58 ` [pve-devel] [PATCH storage v2 2/3] disks: die if storage name is already in use Aaron Lauterer
2022-08-17 11:42 ` Fabian Grünbichler
2022-08-18 15:22 ` Aaron Lauterer
2022-08-18 15:31 ` Aaron Lauterer
2022-08-19 8:21 ` Fabian Grünbichler
2022-08-19 9:29 ` Aaron Lauterer
2022-08-19 8:20 ` Fabian Grünbichler
2022-08-19 9:28 ` Aaron Lauterer
2022-07-15 11:58 ` [pve-devel] [PATCH storage v2 3/3] disks: allow add_storage for already configured local storage Aaron Lauterer
2022-08-17 11:53 ` Fabian Grünbichler
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox