From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id E430C1FF184 for ; Thu, 18 Dec 2025 14:02:30 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 84A7C1C2D3; Thu, 18 Dec 2025 14:03:19 +0100 (CET) Mime-Version: 1.0 Date: Thu, 18 Dec 2025 14:02:44 +0100 Message-Id: From: "Lukas Wagner" To: "Dominik Csapak" , "Proxmox Datacenter Manager development discussion" , "Lukas Wagner" X-Mailer: aerc 0.21.0-0-g5549850facc2-dirty References: <20251218095137.83377-1-l.wagner@proxmox.com> <20251218095137.83377-3-l.wagner@proxmox.com> <8a12aa14-4141-4cb1-bb55-9edd1bbbafc5@proxmox.com> In-Reply-To: <8a12aa14-4141-4cb1-bb55-9edd1bbbafc5@proxmox.com> X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1766062953131 X-SPAM-LEVEL: Spam detection results: 0 AWL -0.966 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment KAM_MAILER 2 Automated Mailer Tag Left in Email RCVD_IN_VALIDITY_CERTIFIED_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_RPBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_SAFE_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: Re: [pdm-devel] [PATCH proxmox-yew-comp 2/2] task descriptions: add PBS task descriptions X-BeenThere: pdm-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Datacenter Manager development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox Datacenter Manager development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pdm-devel-bounces@lists.proxmox.com Sender: "pdm-devel" On Thu Dec 18, 2025 at 1:19 PM CET, Dominik Csapak wrote: > Looks mostly good to me, some comments inline > > > On 12/18/25 10:51 AM, Lukas Wagner wrote: >> Tried to make these match the JS ones as closely as possible. Some of >> these could be improved in the future, but this should then be done in >> tandem with the JS definitions. >> >> Signed-off-by: Lukas Wagner >> --- >> src/utils/task_descriptions.rs | 186 +++++++++++++++++++++++++++++++++ >> 1 file changed, 186 insertions(+) >> >> diff --git a/src/utils/task_descriptions.rs b/src/utils/task_descriptions.rs >> index 86525a4..caeb563 100644 >> --- a/src/utils/task_descriptions.rs >> +++ b/src/utils/task_descriptions.rs >> @@ -212,3 +212,189 @@ pub fn register_pve_tasks() { >> register_task_description("zfscreate", (tr!("ZFS Storage"), tr!("Create"))); >> register_task_description("zfsremove", ("ZFS Pool", tr!("Remove"))); >> } >> + >> +/// Register PBS task descriptions. >> +pub fn register_pbs_tasks() { >> + register_task_description("acme-deativate", |_ty, id: Option| { >> + let id = id.unwrap_or_else(|| "default".to_string()); >> + tr!("Deactivate ACME Account - {0}", id) >> + }); >> + register_task_description("acme-register", |_ty, id: Option| { >> + let id = id.unwrap_or_else(|| "default".to_string()); >> + tr!("Register ACME Account - {0}", id) >> + }); >> + register_task_description("acme-update", |_ty, id: Option| { >> + let id = id.unwrap_or_else(|| "default".to_string()); >> + tr!("Update ACME Account - {0}", id) >> + }); >> + register_task_description("acme-new-cert", ("", tr!("Order Certificate"))); >> + register_task_description("acme-renew-cert", ("", tr!("Renew Certificate"))); >> + register_task_description("acme-revoke-cert", ("", tr!("Revoke Certificate"))); >> + register_task_description("backup", |_ty, id: Option| { >> + render_datastore_worker_id(id, &tr!("Backup")) >> + }); >> + register_task_description( >> + "barcode-label-media", >> + (tr!("Drive"), tr!("Barcode-Label Media")), >> + ); >> + register_task_description("catalog-media", (tr!("Drive"), tr!("Catalog Media"))); >> + register_task_description( >> + "create-datastore", >> + (tr!("Datastore"), tr!("Create Datastore")), >> + ); >> + register_task_description( >> + "delete-datastore", >> + (tr!("Datastore"), tr!("Remove Datastore")), >> + ); >> + register_task_description( >> + "delete-namespace", >> + (tr!("Namespace"), tr!("Remove Namespace")), >> + ); >> + register_task_description("dircreate", (tr!("Directory Storage"), tr!("Create"))); >> + register_task_description("dirremove", (tr!("Directory Storage"), tr!("Remove"))); >> + register_task_description("eject-media", (tr!("Drive"), tr!("Eject Media"))); >> + register_task_description("format-media", (tr!("Drive"), tr!("Format Media"))); >> + register_task_description("forget-group", (tr!("Group"), tr!("Remove Group"))); >> + register_task_description( >> + "garbage_collection", >> + (tr!("Datastore"), tr!("Garbage Collect")), >> + ); >> + register_task_description("realm-sync", ("Realm", tr!("User Sync"))); >> + register_task_description("inventory-update", (tr!("Drive"), tr!("Inventory Update"))); >> + register_task_description("label-media", (tr!("Drive"), tr!("Label Media"))); >> + register_task_description("load-media", |_ty, id: Option| { >> + render_drive_load_media_id(&id.unwrap_or_default(), &tr!("Load Media")) >> + }); >> + register_task_description("logrotate", tr!("Log Rotation")); >> + register_task_description("mount-device", (tr!("Datastore"), tr!("Mount Device"))); >> + register_task_description( >> + "mount-sync-jobs", >> + ( >> + tr!("Datastore"), >> + tr!("sync jobs handler triggered by mount"), >> + ), >> + ); >> + register_task_description("prune", |_ty, id: Option| { >> + render_datastore_worker_id(id, &tr!("Prune")) >> + }); >> + register_task_description("prunejob", |_ty, id: Option| { >> + render_prune_job_worker_id(id, &tr!("Prune Job")) >> + }); >> + register_task_description("reader", |_ty, id: Option| { >> + render_datastore_worker_id(id, &tr!("Read Objects")) >> + }); >> + register_task_description("rewind-media", (tr!("Drive"), tr!("Rewind Media"))); >> + register_task_description("s3-refresh", (tr!("Datastore"), tr!("S3 Refresh"))); >> + register_task_description("sync", (tr!("Datastore"), tr!("Remote Sync"))); >> + register_task_description("syncjob", (tr!("Sync Job"), tr!("Remote Sync"))); >> + register_task_description("tape-backup", |_ty, id: Option| { >> + render_tape_backup_id(id, &tr!("Tape Backup")) >> + }); >> + register_task_description("tape-backup-job", |_ty, id: Option| { >> + render_tape_backup_id(id, &tr!("Tape Backup Job")) >> + }); >> + register_task_description("tape-restore", (tr!("Datastore"), tr!("Tape Restore"))); >> + register_task_description("unload-media", (tr!("Drive"), tr!("Unload Media"))); >> + register_task_description("unmount-device", (tr!("Datastore"), tr!("Unmount Device"))); >> + register_task_description( >> + "verificationjob", >> + (tr!("Verify Job"), tr!("Scheduled Verification")), >> + ); >> + register_task_description("verify", (tr!("Datastore"), tr!("Verification"))); >> + register_task_description("verify_group", (tr!("Group"), tr!("Verification"))); >> + register_task_description("verify_snapshot", (tr!("Snapshot"), tr!("Verification"))); >> + register_task_description("wipedisk", (tr!("Device"), tr!("Wipe Disk"))); >> + register_task_description("zfscreate", (tr!("ZFS Storage"), tr!("Create"))); >> +} >> + >> +proxmox_schema::const_regex! { >> + DATASTORE_WORKER_ID_REGEX = r"^(\S+?):(\S+?)/(\S+?)(/(.+))?$"; >> +} >> + >> +fn render_datastore_worker_id(id: Option, what: &str) -> String { >> + let id = id.as_deref().unwrap_or("unknown"); >> + >> + if let Some(cap) = DATASTORE_WORKER_ID_REGEX.captures(id) { >> + let datastore = cap.get(1).map(|m| m.as_str()); >> + let res2 = cap.get(2).map(|m| m.as_str()); >> + let res3 = cap.get(3).map(|m| m.as_str()); >> + let epoch = cap.get(5).map(|m| m.as_str()); >> + >> + if let (Some(datastore), Some(res2), Some(res3), Some(epoch)) = >> + (datastore, res2, res3, epoch) >> + { >> + if let Ok(epoch) = i64::from_str_radix(epoch, 16) { >> + let utctime = proxmox_time::epoch_to_rfc3339_utc(epoch).unwrap_or_default(); >> + return format!( >> + "{} {} {} {}/{} {}", >> + tr!("Datastore"), >> + datastore, >> + what, >> + res2, >> + res3, >> + utctime >> + ); >> + } >> + } >> + } >> + >> + format!("{} {} {}", tr!("Datastore"), id, what) >> +} > > this implementation differs a bit from the js one. > if the regex matches but the epoch is `None` we render > > 'Datastore id what' instead of > 'Datastore id what backupgroup' > > > Ack, thanks! >> + >> +proxmox_schema::const_regex! { >> + PRUNE_JOB_WORKER_ID_REGEX = r"^(\S+?):(\S+)$"; >> +} >> + >> +fn render_prune_job_worker_id(id: Option, what: &str) -> String { >> + let id = id.as_deref().unwrap_or("unknown"); >> + >> + if let Some(cap) = PRUNE_JOB_WORKER_ID_REGEX.captures(id) { >> + let datastore = cap.get(1).map(|m| m.as_str()); >> + let namespace = cap.get(2).map(|m| m.as_str()); >> + >> + if let (Some(datastore), Some(namespace)) = (datastore, namespace) { >> + return format!( >> + "{} on {} {} {} {}", >> + what, >> + tr! {"Datastore"}, >> + datastore, >> + tr!("Namespace"), >> + namespace >> + ); >> + } >> + } >> + return format!("{} on {} {}", what, tr! {"Datastore"}, id); >> +} As a reference for my comment down below, the JS version is render_prune_job_worker_id: function (id, what) { const res = id.match(/^(\S+?):(\S+)$/); if (!res) { return `${what} on Datastore ${id}`; } let datastore = res[1], namespace = res[2]; return `${what} on Datastore ${datastore} Namespace ${namespace}`; }, >> + >> +proxmox_schema::const_regex! { >> + TAPE_WORKER_ID_REGEX = r"^(\S+?):(\S+?):(\S+?)(:(.+))?$"; >> +} >> + >> +fn render_tape_backup_id(id: Option, what: &str) -> String { >> + let id = id.as_deref().unwrap_or("unknown"); >> + >> + if let Some(cap) = TAPE_WORKER_ID_REGEX.captures(id) { >> + let datastore = cap.get(1).map(|m| m.as_str()); >> + let pool = cap.get(2).map(|m| m.as_str()); >> + let drive = cap.get(3).map(|m| m.as_str()); >> + >> + if let (Some(datastore), Some(pool), Some(drive)) = (datastore, pool, drive) { >> + return format!("{} {} (pool {}, drive {})", what, datastore, pool, drive); >> + } >> + } >> + format!("{} {}", what, id) > > > this is also a bit different: > > on pbs we format them as > > '{what} on Datastore {datastore} Namespace {namespace}' > The JS-impl is render_tape_backup_id: function (id, what) { const res = id.match(/^(\S+?):(\S+?):(\S+?)(:(.+))?$/); if (res) { let datastore = res[1]; let pool = res[2]; let drive = res[3]; return `${what} ${datastore} (pool ${pool}, drive ${drive})`; } return `${what} ${id}`; }, so I think my version should be correct? Did you mean the formatting for the prune job? I also double checked this one, seems correct to me. Keep in mind that the logic is inverted in the JS code. But maybe I'm missing something :) >> +} >> + >> +proxmox_schema::const_regex! { >> + DRIVE_LOAD_WORKER_ID_REGEX = r"^(\S+?):(\S+?)$"; >> +} >> + >> +fn render_drive_load_media_id(id: &str, what: &str) -> String { >> + if let Some(caps) = DRIVE_LOAD_WORKER_ID_REGEX.captures(id) { >> + let drive = &caps[1]; >> + let label = &caps[2]; >> + return format!("{} {drive} - {what} '{label}'", tr!("Drive")); >> + } >> + >> + format!("{what} {id}") >> +} _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel