From: Stoiko Ivanov <s.ivanov@proxmox.com>
To: Gabriel Goller <g.goller@proxmox.com>
Cc: pve-devel@lists.proxmox.com, Thomas Lamprecht <t.lamprecht@proxmox.com>
Subject: Re: [pve-devel] [PATCH] pve-rs: fabrics: handle missing running-config and no fabrics config
Date: Fri, 14 Nov 2025 11:49:22 +0100 [thread overview]
Message-ID: <20251114114922.41c8886c@rosa.proxmox.com> (raw)
In-Reply-To: <20251114103046.129669-1-g.goller@proxmox.com>
Thanks for tackling this so quickly!
nit: a subject-prefix for the repository is missing.
As I noticed the messages from pvestatd in my journal - I gave this a
quick spin - it does fix the
```
Nov 14 11:36:26 rosa pvestatd[4474]: network status update error: error parsing running-config: missing field `fabrics` at line 1 column 97
```
logspam for me. I quickly looked through the code and to me it looks like
it does what it says on the tin.
consider this:
Tested-by: Stoiko Ivanov <s.ivanov@proxmox.com>
Reviewed-by: Stoiko Ivanov <s.ivanov@proxmox.com>
On Fri, 14 Nov 2025 11:30:09 +0100
Gabriel Goller <g.goller@proxmox.com> wrote:
> Correctly handle if there is a missing `/etc/pve/sdn/.running-config`
> file. This happens, e.g. on a clean installation without any sdn "apply"
> activation. Also handle a config where there is no fabric configured.
> The `status()` functions gets called every few seconds to populate the
> network resources in pve, so don't return an error if there is no
> running-config or no fabric config. The other functions (neighbors,
> interfaces, routes) only get called by the api, so we can return an
> error on those.
>
> Reported-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
> Reported-by: Stoiko Ivanov <s.ivanov@proxmox.com>
> Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
> ---
> pve-rs/src/bindings/sdn/fabrics.rs | 36 ++++++++++++++++++++++++------
> pve-rs/src/sdn/status.rs | 10 ++++++---
> 2 files changed, 36 insertions(+), 10 deletions(-)
>
> diff --git a/pve-rs/src/bindings/sdn/fabrics.rs b/pve-rs/src/bindings/sdn/fabrics.rs
> index c9e5cf526c77..54606e7b6bb9 100644
> --- a/pve-rs/src/bindings/sdn/fabrics.rs
> +++ b/pve-rs/src/bindings/sdn/fabrics.rs
> @@ -595,14 +595,21 @@ pub mod pve_rs_sdn_fabrics {
> /// Read and parse the running-config and get the fabrics section
> ///
> /// This will return a valid FabricConfig. Note that we read the file manually and not through
> - /// the cluster filesystem as with perl, so this will be slower.
> - fn get_fabrics_config() -> Result<Valid<FabricConfig>, anyhow::Error> {
> + /// the cluster filesystem as with perl, so this will be slower. If the running config exists,
> + /// but no fabric is configured, `Ok(None)` is returned.
> + fn get_fabrics_config() -> Result<Option<Valid<FabricConfig>>, anyhow::Error> {
> let raw_config = std::fs::read_to_string("/etc/pve/sdn/.running-config")?;
> let running_config: RunningConfig =
> serde_json::from_str(&raw_config).with_context(|| "error parsing running-config")?;
> - let section_config = SectionConfigData::from_iter(running_config.fabrics.ids);
> - FabricConfig::from_section_config(section_config)
> - .with_context(|| "error converting section config to fabricconfig")
> + let Some(fabrics) = running_config.fabrics else {
> + return Ok(None);
> + };
> + let section_config = SectionConfigData::from_iter(fabrics.ids);
> + Some(
> + FabricConfig::from_section_config(section_config)
> + .with_context(|| "error converting section config to fabricconfig"),
> + )
> + .transpose()
> }
>
> /// Get the routes that have been learned and distributed by this specific fabric on this node.
> @@ -614,6 +621,9 @@ pub mod pve_rs_sdn_fabrics {
> fn routes(fabric_id: FabricId) -> Result<Vec<status::RouteStatus>, Error> {
> // Read fabric config to get protocol of fabric
> let config = get_fabrics_config()?;
> + let Some(config) = config else {
> + anyhow::bail!("no fabrics configured");
> + };
>
> let fabric = config.get_fabric(&fabric_id)?;
> match fabric {
> @@ -679,6 +689,9 @@ pub mod pve_rs_sdn_fabrics {
> fn neighbors(fabric_id: FabricId) -> Result<status::NeighborStatus, Error> {
> // Read fabric config to get protocol of fabric
> let config = get_fabrics_config()?;
> + let Some(config) = config else {
> + anyhow::bail!("no fabrics configured");
> + };
>
> let fabric = config.get_fabric(&fabric_id)?;
>
> @@ -734,6 +747,9 @@ pub mod pve_rs_sdn_fabrics {
> fn interfaces(fabric_id: FabricId) -> Result<status::InterfaceStatus, Error> {
> // Read fabric config to get protocol of fabric
> let config = get_fabrics_config()?;
> + let Some(config) = config else {
> + anyhow::bail!("no fabrics configured");
> + };
>
> let fabric = config.get_fabric(&fabric_id)?;
>
> @@ -789,6 +805,14 @@ pub mod pve_rs_sdn_fabrics {
> /// config. If there are, show "ok" as status, otherwise "not ok".
> #[export]
> fn status() -> Result<HashMap<FabricId, status::Status>, Error> {
> + // This gets called every few seconds from pve to get the status of the fabrics into the
> + // network resources. It is possible that the .running-config doesn't exist or no fabric is
> + // configured -- in that case just return nothing.
> + let config = get_fabrics_config();
> + let Ok(Some(config)) = config else {
> + return Ok(HashMap::new());
> + };
> +
> let openfabric_ipv4_routes_string = String::from_utf8(
> Command::new("sh")
> .args(["-c", "vtysh -c 'show ip route openfabric json'"])
> @@ -831,8 +855,6 @@ pub mod pve_rs_sdn_fabrics {
> .with_context(|| "error parsing ospf routes")?
> };
>
> - let config = get_fabrics_config()?;
> -
> let route_status = status::RoutesParsed {
> openfabric: openfabric_routes,
> ospf: ospf_routes,
> diff --git a/pve-rs/src/sdn/status.rs b/pve-rs/src/sdn/status.rs
> index 78b55502b837..e1e336297ac9 100644
> --- a/pve-rs/src/sdn/status.rs
> +++ b/pve-rs/src/sdn/status.rs
> @@ -178,7 +178,7 @@ pub struct RoutesParsed {
> /// Config used to parse the fabric part of the running-config
> #[derive(Deserialize)]
> pub struct RunningConfig {
> - pub fabrics: FabricsRunningConfig,
> + pub fabrics: Option<FabricsRunningConfig>,
> }
>
> /// Map of ids for all the fabrics in the running-config
> @@ -647,7 +647,9 @@ mod tests {
>
> let running_config: RunningConfig =
> serde_json::from_str(raw_config).expect("error parsing running-config");
> - let section_config = SectionConfigData::from_iter(running_config.fabrics.ids);
> + let section_config = SectionConfigData::from_iter(
> + running_config.fabrics.expect("no fabrics configured").ids,
> + );
> FabricConfig::from_section_config(section_config)
> .expect("error converting section config to fabricconfig")
> }
> @@ -695,7 +697,9 @@ mod tests {
> "#;
> let running_config: RunningConfig =
> serde_json::from_str(raw_config).expect("error parsing running-config");
> - let section_config = SectionConfigData::from_iter(running_config.fabrics.ids);
> + let section_config = SectionConfigData::from_iter(
> + running_config.fabrics.expect("no fabrics configured").ids,
> + );
> FabricConfig::from_section_config(section_config)
> .expect("error converting section config to fabricconfig")
> }
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
next prev parent reply other threads:[~2025-11-14 10:49 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-14 10:30 Gabriel Goller
2025-11-14 10:49 ` Stoiko Ivanov [this message]
2025-11-14 11:02 ` Gabriel Goller
2025-11-14 11:01 ` Thomas Lamprecht
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=20251114114922.41c8886c@rosa.proxmox.com \
--to=s.ivanov@proxmox.com \
--cc=g.goller@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
--cc=t.lamprecht@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox