public inbox for pdm-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: "Shan Shaji" <s.shaji@proxmox.com>
To: "Lukas Wagner" <l.wagner@proxmox.com>, <pdm-devel@lists.proxmox.com>
Subject: Re: [PATCH datacenter-manager v2 3/4] fix #7179: cli: admin: expose acme commands
Date: Tue, 10 Feb 2026 11:41:08 +0100	[thread overview]
Message-ID: <DGB7VLCAMTDY.1T5MPKZ7F77RY@proxmox.com> (raw)
In-Reply-To: <DG73J5IF5S12.X4TR856Q2V7P@proxmox.com>

Hi Lukas, thank you so much for the nice improvement feedbacks. 

Some comments inline.

On Thu Feb 5, 2026 at 3:26 PM CET, Lukas Wagner wrote:
> Hi Shan,
>
> thanks for this updated version of your patch series. Looking good from
> what I can, some comments inline.
>
> On Tue Feb 3, 2026 at 6:51 PM CET, Shan Shaji wrote:
>> Previously, ACME commands were not exposed through the admin CLI.
>> Added the necessary functionality to manage ACME settings directly
>> via the command line.
>>
>> Signed-off-by: Shan Shaji <s.shaji@proxmox.com>
>> ---
>>

[...]

>> +///Register an ACME account.
>> +async fn register_account(
>> +    name: AcmeAccountName,
>> +    contact: String,
>> +    directory: Option<String>,
>> +    rpcenv: &mut dyn RpcEnvironment,
>> +) -> Result<(), Error> {
>> +    let (directory_url, custom_directory) = match directory {
>> +        Some(directory) => (directory, true),
>> +        None => {
>> +            println!("Directory endpoints:");
>> +            for (i, dir) in KNOWN_ACME_DIRECTORIES.iter().enumerate() {
>> +                println!("{}) {}", i, dir.url);
>> +            }
>> +
>> +            println!("{}) Custom", KNOWN_ACME_DIRECTORIES.len());
>> +            let mut attempt = 0;
>> +            loop {
>> +                let mut input = read_input("Enter selection")?;
>> +                match input.trim().parse::<usize>() {
>> +                    Ok(n) if n < KNOWN_ACME_DIRECTORIES.len() => {
>> +                        break (KNOWN_ACME_DIRECTORIES[n].url.to_string(), false);
>> +                    }
>> +                    Ok(n) if n == KNOWN_ACME_DIRECTORIES.len() => {
>> +                        input.clear();
>> +                        input = read_input("Enter custom directory URI")?;
>> +                        break (input.trim().to_owned(), true);
>> +                    }
>> +                    _ => eprintln!("Invalid selection."),
>> +                }
>> +
>> +                attempt += 1;
>> +                if attempt >= 3 {
>> +                    bail!("Aborting.");
>> +                }
>> +            }
>> +        }
>> +    };
>> +
>> +    println!("Attempting to fetch Terms of Service from {directory_url:?}");
>> +    let mut client = AcmeClient::new(directory_url.clone());
>> +    let directory = client.directory().await?;
>> +    let tos_agreed = if let Some(tos_url) = directory.terms_of_service_url() {
>> +        println!("Terms of Service: {tos_url}");
>> +        let input = read_input("Do you agree to the above terms? [y|N]")?;
>> +        input.trim().eq_ignore_ascii_case("y")
>> +    } else {
>> +        println!("No Terms of Service found, proceeding.");
>> +        true
>> +    };
>> +
>> +    let mut eab_enabled = directory.external_account_binding_required();
>> +    if !eab_enabled && custom_directory {
>> +        let input = read_input("Do you want to use external account binding? [y|N]")?;
>> +        eab_enabled = input.trim().eq_ignore_ascii_case("y");
>> +    } else if eab_enabled {
>> +        println!("The CA requires external account binding.");
>> +    }
>> +
>> +    let eab_creds = if eab_enabled {
>> +        println!("You should have received a key id and a key from your CA.");
>> +        let eab_kid = read_input("Enter EAB key id")?;
>> +        let eab_hmac_key = read_input("Enter EAB key")?;
>> +        Some((eab_kid.trim().to_owned(), eab_hmac_key.trim().to_owned()))
>> +    } else {
>> +        None
>> +    };
>> +
>> +    let tos_url = tos_agreed
>> +        .then(|| directory.terms_of_service_url().map(str::to_owned))
>> +        .flatten();
>> +
>> +    let (eab_kid, eab_hmac_key) = eab_creds.unzip();
>> +    let parameters = AcmeRegistrationParams {
>> +        name: Some(name),
>> +        contact: contact,
>> +        tos_url: tos_url,
>> +        directory: Some(directory_url),
>> +        eab_kid: eab_kid,
>> +        eab_hmac_key: eab_hmac_key,
>> +    };
>> +    let param = serde_json::to_value(parameters)?;
>> +
>> +    let info = &dc_api::config::acme::API_METHOD_REGISTER_ACCOUNT;
>> +    let result = match info.handler {
>> +        ApiHandler::Sync(handler) => (handler)(param, info, rpcenv)?,
>> +        _ => unreachable!(),
>> +    };
>> +
>> +    wait_for_local_worker(result.as_str().unwrap()).await?;
>> +
>> +    Ok(())
>> +}
>
> Two things came to mind when actually trying out this CLI:
>
>   - The directory selection is a bit odd to use, since it uses 0-based
>     indexing, something like
>        0.) Let's Encrypt
>        1.) Let's Encrypt Staging
>        ....
>
>     1-based indexing probably is a bit nicer for users here.

I will add this in v3. Thanks!

>   - Also, I wonder if there should be non-interactive version of this
>     command as well, one that can be scripted, one where all parameters
>     that are asked as parameters can be provided as flags.
>     People can always use the API for this, but maybe it would still be
>     nice to offer this in the CLI tool as well.
>     Just thinking out loud, I'm aware that you just copied the approach
>     from PBS, if we add something like this, this should be done in a
>     separate series.

This is a nice improvement. We already have an option to provide custom
directory endpoint using --directory option. I will add additional options
to accept the TOS selection and EAB credentials.  

Do we need to provide a flag to choose the Lets encrypt endpoint  
as we already have a --directory option?

>   - Might be worth moving this 'wizard' implementation to some helper
>     module in proxmox-acme-api and then use the same implementation from
>     both PDM and PBS. To avoid scope creep this can always be done in a
>     follow-up series.
>
>     I guess in this case the appropriate place for the new
>     AcmeRegistrationParams is then also proxmox-acme-api, since the this
>     would be the type that is returned from such a shared helper.
>
>     (sorry, some of these I could have noticed in my earlier, less
>     thorough review)
>
> All of these can be done in followup-patches, it's just some ideas for
> improvement over the status quo that we already have in PBS.

Thanks! I will move the  wizard implementation to the proxmox-acme-api
crate and use the same on both PBS and PDM. Will send another series
once this series is applied. 

>> +
>> +#[api(
>> +    input: {
>> +       properties: {
>> +           name: { type: AcmeAccountName },
>> +           contact:  {
>> +               description: "List of email addresses.",
>> +               type: String,
>> +               optional: true,
>> +           }
>> +       }
>> +    }
>> +)]
>> +/// Update an ACME Account.
>> +async fn update_account(param: Value, rpcenv: &mut dyn RpcEnvironment) -> Result<(), Error> {
>> +    let info = &dc_api::config::acme::API_METHOD_UPDATE_ACCOUNT;
>> +    let result = match info.handler {
>> +        ApiHandler::Sync(handler) => (handler)(param, info, rpcenv)?,
>> +        _ => unreachable!(),
>> +    };
>> +
>> +    wait_for_local_worker(result.as_str().unwrap()).await?;
>> +
>> +    Ok(())
>> +}
>> +
>
> [...]
>
>> +
>> +pub fn cert_cli() -> CommandLineInterface {
>> +    let cmd_def = CliCommandMap::new()
>> +        .insert("order", CliCommand::new(&API_METHOD_ORDER_ACME_CERT))
>> +        .insert("revoke", CliCommand::new(&API_METHOD_REVOKE_ACME_CERT));
>> +
>> +    cmd_def.into()
>> +}
>> diff --git a/cli/admin/src/main.rs b/cli/admin/src/main.rs
>> index 02148e3..3fd3c2f 100644
>> --- a/cli/admin/src/main.rs
>> +++ b/cli/admin/src/main.rs
>> @@ -9,6 +9,7 @@ use proxmox_router::RpcEnvironment;
>>  use proxmox_schema::api;
>>  use proxmox_sys::fs::CreateOptions;
>>  
>> +mod acme;
>>  mod remotes;
>>  mod support_status;
>>  
>> @@ -22,7 +23,11 @@ async fn run() -> Result<(), Error> {
>>          pdm_buildcfg::configdir!("/access"),
>>      )
>>      .context("failed to setup access control config")?;
>> +    proxmox_acme_api::init(pdm_buildcfg::configdir!("/acme"), false)
>> +        .context("failed to initialize acme config")?;
>> +
>>      proxmox_log::Logger::from_env("PDM_LOG", proxmox_log::LevelFilter::INFO)
>> +        .tasklog()
>
> I'd use the 'old' tasklog_pbs function here for now, since then we can
> apply these patches without bumping proxmox-log first. Changing this to
> `tasklog` is trivial and can be done in a followup patch.
>
> We should be getting a deprecation warning when building PDM once
> proxmox-log has been bumped, so there should be little chance to forget
> it.
>

Will update it to `tasklog_pbs`. Thank You!

>>          .stderr()
>>          .init()
>>          .context("failed to set-up logger")?;
>> @@ -30,6 +35,7 @@ async fn run() -> Result<(), Error> {
>>      server::context::init().context("could not set-up server context")?;
>>  
>>      let cmd_def = CliCommandMap::new()
>> +        .insert("acme", acme::acme_mgmt_cli())
>>          .insert("remote", remotes::cli())
>>          .insert(
>>              "report",





  reply	other threads:[~2026-02-10 10:40 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-03 17:50 [PATCH datacenter-manager v2 0/4] fix #7179: expose ACME commands inside admin CLI Shan Shaji
2026-02-03 17:50 ` [PATCH datacenter-manager v2 1/4] cli: admin: make cli handling async Shan Shaji
2026-02-05 14:25   ` Lukas Wagner
2026-02-06 12:56     ` Shan Shaji
2026-02-03 17:50 ` [PATCH datacenter-manager v1 2/4] api: acme: define API type for ACME registration parameters Shan Shaji
2026-02-05 14:25   ` Lukas Wagner
2026-02-03 17:51 ` [PATCH datacenter-manager v2 3/4] fix #7179: cli: admin: expose acme commands Shan Shaji
2026-02-05 14:26   ` Lukas Wagner
2026-02-10 10:41     ` Shan Shaji [this message]
2026-02-10 16:36       ` Shan Shaji
2026-02-03 17:51 ` [PATCH datacenter-manager v2 4/4] chore: update proxmox-acme version to 1 Shan Shaji
2026-02-05 14:25 ` [PATCH datacenter-manager v2 0/4] fix #7179: expose ACME commands inside admin CLI Lukas Wagner

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=DGB7VLCAMTDY.1T5MPKZ7F77RY@proxmox.com \
    --to=s.shaji@proxmox.com \
    --cc=l.wagner@proxmox.com \
    --cc=pdm-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