all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: "Fabian Grünbichler" <f.gruenbichler@proxmox.com>
To: Lucas Barros <lucasbarros.kam@gmail.com>, pve-devel@lists.proxmox.com
Subject: Re: [PATCH qemu-server] fix #7173: config: do not write out an empty tag list
Date: Wed, 11 Nov 2026 10:53:24 +0100	[thread overview]
Message-ID: <1794390075.ol4qipttrq.astroid@yuna.none> (raw)
In-Reply-To: <20261109135613.94692-1-lucasbarros.kam@gmail.com>

On November 9, 2026 2:56 pm, Lucas Barros wrote:
> Removing the last tag of a VM, for example in the web UI, sets 'tags'
> to an empty string, which then ends up as an empty 'tags:' line in the
> VM config and in the output of 'qm config'. This carries no
> information, is inconsistent with how unset options are handled and
> confuses tools that consume the config, as they need to special case
> an empty tag list.

We could consider changing this and rejecting empty `-list` parameters,
and instead require properly deleting? e.g., switch over to use
`--delete tags` if the last to-be-set tag list is empty, make the parser
ignore keys without a value, and then with 10.0 make empty (either by
virtue of being an empty string, or just delimiters) list parameters
invalid?

It seems like these two patches just add a hacky workaround on top (with
rather subtle semantics about adding the invalid value to pending but
not to the `current` config)..

> Drop the key when writing the config if the tag list is empty, which
> also cleans up configs that already contain such a line on the next
> write. The pending section is left alone, as an empty value there is
> still needed to apply the change.
> 
> Signed-off-by: Lucas Barros <lucasbarros.kam@gmail.com>
> ---
> A matching patch for pve-container is sent separately.
> 
> Only the main section is touched. In [PENDING] the empty value is still
> needed so that applying the pending change removes the tags, and it is
> dropped from the main section on the write that follows.
> 
> The new parse-config test input contains the 'tags: ' line with the
> trailing space that the writer produces today, so 'git am' warns about
> trailing whitespace there. Without the trailing space the line would
> not match the config parser at all.
> 
> An alternative would be to turn an empty 'tags' value into a deletion
> in the update API, but that would not cover other paths that end up
> with an empty value (create, clone, restore, 'qm set --tags ""').
> 
> Tested on a PVE 9 node (qemu-server 9.2.15, pve-container 6.1.18),
> adding and then removing the only tag of a VM and of a container:
> 
> without the patches:
>   $ qm set 9901 --tags foo; pvesh set /nodes/<node>/qemu/9901/config --tags ''
>   $ grep -n tags /etc/pve/qemu-server/9901.conf | cat -A
>   6:tags:  $
>   $ pct set 9902 --tags foo; pct set 9902 --tags ''
>   $ grep -n tags /etc/pve/lxc/9902.conf | cat -A
>   7:tags: $
>   $ pvesh get /nodes/<node>/qemu/9901/config --output-format json | jq -c '{tags}'
>   {"tags":" "}
> 
> with the patches:
>   $ grep -c tags /etc/pve/qemu-server/9901.conf /etc/pve/lxc/9902.conf
>   /etc/pve/qemu-server/9901.conf:0
>   /etc/pve/lxc/9902.conf:0
>   $ pvesh get /nodes/<node>/qemu/9901/config --output-format json | jq -c '{tags}'
>   {"tags":null}
> 
> An existing empty 'tags:' line goes away on the next write of the
> config, removing the tag of a running VM leaves no line and no
> [PENDING] entry, and 'tags: a;b' is still written as before.
> 
> 'make test' (run with 16 CPUs in /proc/cpuinfo, the cfg2cmd tests need
> more vCPUs than the test machine has) passes before and after; the
> parse-config tests go from 20 to 22, and the new empty-tags case fails
> without the change to QemuServer.pm. proxmox-perltidy reports no
> changes.
> 
> This patch was prepared with the help of an LLM based coding assistant;
> I reviewed the change and ran the tests mentioned above myself.
> 
>  src/PVE/QemuServer.pm                          |  3 +++
>  src/test/parse-config-expected/empty-tags.conf | 11 +++++++++++
>  src/test/parse-config-input/empty-tags.conf    | 12 ++++++++++++
>  src/test/run_parse_config_tests.pl             |  2 +-
>  4 files changed, 27 insertions(+), 1 deletion(-)
>  create mode 100644 src/test/parse-config-expected/empty-tags.conf
>  create mode 100644 src/test/parse-config-input/empty-tags.conf
> 
> diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm
> index 8045c07e..22621e63 100644
> --- a/src/PVE/QemuServer.pm
> +++ b/src/PVE/QemuServer.pm
> @@ -2067,6 +2067,9 @@ sub write_vm_config {
>          delete $conf->{smp};
>      }
>  
> +    # an empty tag list carries no information, so do not write out the key
> +    delete $conf->{tags} if defined($conf->{tags}) && $conf->{tags} =~ m/^[\s,;]*$/;

nit: if we keep this approach, this should `split_list` and check that
the result is empty, else it risks going out of sync (it already is
w.r.t. \0-delimited lists).

> +
>      my $used_volids = {};
>  
>      my $cleanup_config = sub {
> diff --git a/src/test/parse-config-expected/empty-tags.conf b/src/test/parse-config-expected/empty-tags.conf
> new file mode 100644
> index 00000000..a5b02f2c
> --- /dev/null
> +++ b/src/test/parse-config-expected/empty-tags.conf
> @@ -0,0 +1,11 @@
> +# VM with an empty tag list left behind after removing the last tag
> +bootdisk: scsi0
> +cores: 1
> +memory: 512
> +name: apache
> +ostype: l26
> +scsi0: mydir:142/vm-142-disk-0.qcow2,size=4G
> +scsihw: virtio-scsi-pci
> +smbios1: uuid=ddf91b3f-a597-42be-9a7e-fb6421dcd5cd
> +sockets: 1
> +vmgenid: 0
> diff --git a/src/test/parse-config-input/empty-tags.conf b/src/test/parse-config-input/empty-tags.conf
> new file mode 100644
> index 00000000..a37a9c2d
> --- /dev/null
> +++ b/src/test/parse-config-input/empty-tags.conf
> @@ -0,0 +1,12 @@
> +# VM with an empty tag list left behind after removing the last tag
> +bootdisk: scsi0
> +cores: 1
> +memory: 512
> +name: apache
> +ostype: l26
> +scsi0: mydir:142/vm-142-disk-0.qcow2,size=4G
> +scsihw: virtio-scsi-pci
> +smbios1: uuid=ddf91b3f-a597-42be-9a7e-fb6421dcd5cd
> +sockets: 1
> +tags: 
> +vmgenid: 0
> diff --git a/src/test/run_parse_config_tests.pl b/src/test/run_parse_config_tests.pl
> index f68abc06..c30aad99 100755
> --- a/src/test/run_parse_config_tests.pl
> +++ b/src/test/run_parse_config_tests.pl
> @@ -25,7 +25,7 @@ my $INPUT_DIR = './parse-config-input';
>  my $EXPECTED_DIR = './parse-config-expected';
>  
>  # NOTE update when you add/remove tests
> -plan tests => 2 * 10;
> +plan tests => 2 * 11;
>  
>  sub run_tests {
>      my ($strict) = @_;
> -- 
> 2.47.3
> 
> 
> 
> 
> 




      reply	other threads:[~2026-11-11  9:53 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-09 13:56 [PATCH qemu-server] fix #7173: config: do not write out an empty tag list Lucas Barros
2026-11-11  9:53 ` Fabian Grünbichler [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1794390075.ol4qipttrq.astroid@yuna.none \
    --to=f.gruenbichler@proxmox.com \
    --cc=lucasbarros.kam@gmail.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal