From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <f.ebner@proxmox.com>
Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68])
 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
 key-exchange X25519 server-signature RSA-PSS (2048 bits))
 (No client certificate requested)
 by lists.proxmox.com (Postfix) with ESMTPS id 0CE4BD29F
 for <pbs-devel@lists.proxmox.com>; Wed, 30 Nov 2022 14:13:06 +0100 (CET)
Received: from firstgate.proxmox.com (localhost [127.0.0.1])
 by firstgate.proxmox.com (Proxmox) with ESMTP id DD38E1DEB6
 for <pbs-devel@lists.proxmox.com>; Wed, 30 Nov 2022 14:13:05 +0100 (CET)
Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com
 [94.136.29.106])
 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
 key-exchange X25519 server-signature RSA-PSS (2048 bits))
 (No client certificate requested)
 by firstgate.proxmox.com (Proxmox) with ESMTPS
 for <pbs-devel@lists.proxmox.com>; Wed, 30 Nov 2022 14:13:04 +0100 (CET)
Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1])
 by proxmox-new.maurer-it.com (Proxmox) with ESMTP id ABE0D43455
 for <pbs-devel@lists.proxmox.com>; Wed, 30 Nov 2022 14:13:04 +0100 (CET)
From: Fiona Ebner <f.ebner@proxmox.com>
To: pbs-devel@lists.proxmox.com
Date: Wed, 30 Nov 2022 14:12:30 +0100
Message-Id: <20221130131230.105779-2-f.ebner@proxmox.com>
X-Mailer: git-send-email 2.30.2
In-Reply-To: <20221130131230.105779-1-f.ebner@proxmox.com>
References: <20221130131230.105779-1-f.ebner@proxmox.com>
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-SPAM-LEVEL: Spam detection results:  0
 AWL 0.028 Adjusted score from AWL reputation of From: address
 BAYES_00                 -1.9 Bayes spam probability is 0 to 1%
 KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment
 SPF_HELO_NONE           0.001 SPF: HELO does not publish an SPF Record
 SPF_PASS               -0.001 SPF: sender matches SPF record
Subject: [pbs-devel] [PATCH proxmox 2/2] section config: fix handling array
 schema in unknown sections
X-BeenThere: pbs-devel@lists.proxmox.com
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: Proxmox Backup Server development discussion
 <pbs-devel.lists.proxmox.com>
List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pbs-devel>, 
 <mailto:pbs-devel-request@lists.proxmox.com?subject=unsubscribe>
List-Archive: <http://lists.proxmox.com/pipermail/pbs-devel/>
List-Post: <mailto:pbs-devel@lists.proxmox.com>
List-Help: <mailto:pbs-devel-request@lists.proxmox.com?subject=help>
List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel>, 
 <mailto:pbs-devel-request@lists.proxmox.com?subject=subscribe>
X-List-Received-Date: Wed, 30 Nov 2022 13:13:06 -0000

Mostly relevant when the config is written out again after parsing it
with unknown sections. Previously, with duplicate keys, only the last
value would be saved. Now, duplicate keys are assumed to be part of
an array schema and handled as such.

Because the unknown section parsing does not know if a certain
property does actually have an array schema, it's not possible to
detect duplicate keys for non-array-schema properties, and if a
property with array-schema shows up only once, it will not be saved as
a Value::Array, but a Value::String.

Writing, or to be precise the format_section_content methods, already
handle Value::Array, so don't need to be adapted.

Fixes: 0cd0d16 ("section config: support allowing unknown section types")
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
---
 proxmox-section-config/src/lib.rs | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/proxmox-section-config/src/lib.rs b/proxmox-section-config/src/lib.rs
index 929ab92..66eeacf 100644
--- a/proxmox-section-config/src/lib.rs
+++ b/proxmox-section-config/src/lib.rs
@@ -529,7 +529,14 @@ impl SectionConfig {
                                 continue;
                             }
                             if let Some((key, value)) = (self.parse_section_content)(line) {
-                                config[key] = json!(value);
+                                match &mut config[&key] {
+                                    Value::Null => config[key] = json!(value),
+                                    // Assume it's an array schema in order to handle actual array
+                                    // schemas as good as we can.
+                                    Value::String(current) => config[key] = json!([current, value]),
+                                    Value::Array(array) => array.push(json!(value)),
+                                    other => bail!("got unexpected Value {:?}", other),
+                                }
                             } else {
                                 bail!("syntax error (expected section properties)");
                             }
@@ -1137,6 +1144,8 @@ fn test_section_config_array() {
     let mut config = SectionConfig::new(&ID_SCHEMA);
     config.register_plugin(plugin);
 
+    let config_unknown = SectionConfig::new(&ID_SCHEMA).allow_unknown_sections(true);
+
     let raw = r"
 
 sync: s-4a1011e8-40e2
@@ -1182,6 +1191,15 @@ sync: s-6c32330a-6204
 
     check(res);
 
+    let res_unknown = config_unknown.parse(filename, raw).unwrap();
+    println!("RES (unknown): {:?}", res_unknown);
+    let written_unknown = config_unknown.write(filename, &res_unknown).unwrap();
+    println!("CONFIG (unknown):\n{}", written_unknown);
+
+    check(res_unknown);
+
+    assert_eq!(written, written_unknown);
+
     let raw = r"
 
 sync: fail
-- 
2.30.2