public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Arthur Bied-Charreton <a.bied-charreton@proxmox.com>
To: Lukas Wagner <l.wagner@proxmox.com>
Cc: pve-devel@lists.proxmox.com
Subject: Re: [PATCH proxmox 3/5] notify: Update Endpoint trait and Bus to use State
Date: Thu, 12 Feb 2026 09:26:56 +0100	[thread overview]
Message-ID: <2ht7zyrnl6w2ufveidy7wzdxlaqj6jgei3ao2m7rhrxioqavfk@yvochtl365lg> (raw)
In-Reply-To: <DGBEHSEEHUGO.3MSZ0R7IE6P54@proxmox.com>

On Tue, Feb 10, 2026 at 04:52:14PM +0100, Lukas Wagner wrote:
> Hey Arthur,
> 
> some comments inline.
> 
> On Wed Feb 4, 2026 at 5:13 PM CET, Arthur Bied-Charreton wrote:
> > This lays the groundwork for handling OAuth2 state in proxmox-notify by
> > updating the crate's internal API to pass around a mutable State struct.
> >
> > The state can be updated by its consumers and will be persisted
> > afterwards, much like the Config struct, with the difference that it is
> > fully internal to the crate. External consumers of the API do not need
> > to know/care about it.
> >
> > Signed-off-by: Arthur Bied-Charreton <a.bied-charreton@proxmox.com>
> > ---
> >  proxmox-notify/src/api/common.rs         | 70 +++++++++++++++++++++---
> >  proxmox-notify/src/endpoints/gotify.rs   |  4 +-
> >  proxmox-notify/src/endpoints/sendmail.rs |  4 +-
> >  proxmox-notify/src/endpoints/smtp.rs     | 17 +++++-
> >  proxmox-notify/src/endpoints/webhook.rs  |  4 +-
> >  proxmox-notify/src/lib.rs                | 42 +++++++++-----
> >  6 files changed, 113 insertions(+), 28 deletions(-)
> >
> > diff --git a/proxmox-notify/src/api/common.rs b/proxmox-notify/src/api/common.rs
> > index fa2356e2..3483be9a 100644
> > --- a/proxmox-notify/src/api/common.rs
> > +++ b/proxmox-notify/src/api/common.rs
> > @@ -1,7 +1,52 @@
> >  use proxmox_http_error::HttpError;
> >  
> >  use super::http_err;
> > -use crate::{Bus, Config, Notification};
> > +use crate::{context::context, Bus, Config, Notification, State};
> > +
> > +use tracing::error;
> > +
> > +fn get_state() -> State {
> > +    let path_str = context().state_file_path();
> > +    let path = std::path::Path::new(path_str);
> > +
> > +    match path.exists() {
> > +        true => match State::from_path(path) {
> > +            Ok(s) => s,
> > +            Err(e) => {
> > +                // We don't want to block notifications on all endpoints only
> > +                // because the stateful ones are broken.
> > +                error!("could not instantiate state from {path_str}: {e}",);
> > +                State::default()
> > +            }
> > +        },
> > +        false => State::default(),
> > +    }
> > +}
> 
> This is a good example of TOCTOU (time of check, time of use). First you
> check if something exists in the filesystem, and if it does, you read
> the file. In theory, it could happen that the file is removed in between
> these two lines, leading to an error when reading the file. Now, in
> this concrete case here this is not a huge issue, but nevertheless its
> better to avoid it if you can. In this case here you can just read the
> file and then in case of an error check for ENOENT. See [1]
> for a very similar example.
> 
> [1] https://git.proxmox.com/?p=proxmox-datacenter-manager.git;a=blob;f=server/src/remote_updates.rs;h=e772eef510218d8da41fe4a88ee47847b2598045;hb=HEAD#l159
> 
> In proxmox-sys there are also the file_read_optional_string or
> file_get_optional_contents helpers which should do just that.
> 
Makes sense, thanks!
> > +
> > +fn persist_state(state: &State) {
> > +    let path_str = context().state_file_path();
> > +
> > +    if let Err(e) = state.persist(path_str) {
> > +        error!("could not persist state at '{path_str}': {e}");
> > +    }
> > +}
> > +
> 
> `refresh_targets` sounds very generic. How about
> `periodic_maintenance_task` or something alike?
> 
See 
https://lore.proxmox.com/pve-devel/3kqo4fxy4y3lrkhv7exd57ap6llkds2sxrn7gqj6wfxbo5zrvc@pvacwvkdp3zi/
> > +pub fn refresh_targets(config: &Config) -> Result<(), HttpError> {
> > +    let bus = Bus::from_config(config).map_err(|err| {
> > +        http_err!(
> > +            INTERNAL_SERVER_ERROR,
> > +            "Could not instantiate notification bus: {err}"
> > +        )
> > +    })?;
> > +
> > +    let mut state = get_state();
> > +
> > +    bus.refresh_targets(&mut state);
> > +
> > +    persist_state(&state);
> > +
> > +    Ok(())
> > +}
> 
> I wonder, should we attempt to persist the state in case of an error
> here?
Yes we should, I overlooked that, thanks for catching it

> > +#[derive(Serialize, Deserialize, Clone, Debug, Default)]
> > +#[serde(rename_all = "kebab-case")]
> > +pub struct SmtpState {
> > +    #[serde(skip_serializing_if = "Option::is_none")]
> > +    pub oauth2_refresh_token: Option<String>,
> > +    pub last_refreshed: u64,
> > +}
> > +
> > +impl EndpointState for SmtpState {}
> > +
> >  #[api]
> >  #[derive(Serialize, Deserialize, Clone, Updater, Debug)]
> >  #[serde(rename_all = "kebab-case")]
> > @@ -158,7 +169,9 @@ pub struct SmtpEndpoint {
> >  }
> >  
> >  impl Endpoint for SmtpEndpoint {
> > -    fn send(&self, notification: &Notification) -> Result<(), Error> {
> > +    fn send(&self, notification: &Notification, state: &mut State) -> Result<(), Error> {
> > +        let mut endpoint_state = state.get_or_default::<SmtpState>(self.name())?;
> 
> We talked about this off-list already, but it think would be cool if an
> endpoint would not get the entire state container, but only it's *own*
> state. I quickly tried this using an associated type in the trait for
> the state type and making `send` generic, but unfortunately this did not
> really work out - we store all endpoints in a HashMap<String, Box<dyn
> Endpoint>. 
> 
> This could probably be solved with some internal architectural changes,
> removing the Box<dyn ...> and replace it with 'manual' dispatching
> using an enum wrapper and `match`.
> 
> 
I am working on that, using an enum seems like the right choice here, it
feels a lot better (modulo the extra dispatching/variant unwrapping 
boilerplate, but each concrete endpoint having to get its own state from 
a generic pool is not much better).




  reply	other threads:[~2026-02-12  8:26 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-04 16:13 [RFC cluster/docs/manager/proxmox{,-perl-rs,-widget-toolkit} 00/15] fix #7238: Add XOAUTH2 authentication support for SMTP notification targets Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH proxmox 1/5] notify: Introduce xoauth2 module Arthur Bied-Charreton
2026-02-06 15:00   ` Lukas Wagner
2026-02-09  8:34     ` Arthur Bied-Charreton
2026-02-10  8:24       ` Lukas Wagner
2026-02-10 10:23         ` Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH proxmox 2/5] notify: Add state file handling Arthur Bied-Charreton
2026-02-10 15:51   ` Lukas Wagner
2026-02-04 16:13 ` [PATCH proxmox 3/5] notify: Update Endpoint trait and Bus to use State Arthur Bied-Charreton
2026-02-10 15:52   ` Lukas Wagner
2026-02-12  8:26     ` Arthur Bied-Charreton [this message]
2026-02-04 16:13 ` [PATCH proxmox 4/5] notify: smtp: add OAuth2/XOAUTH2 authentication support Arthur Bied-Charreton
2026-02-10 15:52   ` Lukas Wagner
2026-02-11 13:00     ` Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH proxmox 5/5] notify: Add test for State Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH proxmox-perl-rs 1/1] notify: update bindings with new OAuth2 parameters Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH proxmox-widget-toolkit 1/2] utils: Add OAuth2 flow handlers Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH proxmox-widget-toolkit 2/2] notifications: Add opt-in OAuth2 support for SMTP targets Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH pve-manager 1/5] notifications: Add OAuth2 parameters to schema and add/update endpoints Arthur Bied-Charreton
2026-02-11  8:55   ` Lukas Wagner
2026-02-11 12:47     ` Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH pve-manager 2/5] notifications: Add refresh-targets endpoint Arthur Bied-Charreton
2026-02-11  9:49   ` Lukas Wagner
2026-02-11 12:44     ` Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH pve-manager 3/5] notifications: Trigger notification target refresh in pveupdate Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH pve-manager 4/5] notifications: Handle OAuth2 callback in login handler Arthur Bied-Charreton
2026-02-11  9:00   ` Lukas Wagner
2026-02-04 16:13 ` [PATCH pve-manager 5/5] notifications: Opt into OAuth2 authentication Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH pve-cluster 1/1] notifications: Add refresh_targets subroutine to PVE::Notify Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH pve-docs 1/1] notifications: Add section about OAuth2 to SMTP targets docs Arthur Bied-Charreton
2026-02-11 10:06   ` Lukas Wagner
2026-02-11 13:15     ` Arthur Bied-Charreton
2026-02-13 16:06 ` superseded: [RFC cluster/docs/manager/proxmox{,-perl-rs,-widget-toolkit} 00/15] fix #7238: Add XOAUTH2 authentication support for SMTP notification targets Arthur Bied-Charreton

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=2ht7zyrnl6w2ufveidy7wzdxlaqj6jgei3ao2m7rhrxioqavfk@yvochtl365lg \
    --to=a.bied-charreton@proxmox.com \
    --cc=l.wagner@proxmox.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal