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 703241FF15C for ; Fri, 28 Nov 2025 16:38:43 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 191061E2E7; Fri, 28 Nov 2025 16:39:04 +0100 (CET) From: Shannon Sterz To: pdm-devel@lists.proxmox.com Date: Fri, 28 Nov 2025 16:38:52 +0100 Message-ID: <20251128153855.543210-2-s.sterz@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20251128153855.543210-1-s.sterz@proxmox.com> References: <20251128153855.543210-1-s.sterz@proxmox.com> MIME-Version: 1.0 X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1764344297003 X-SPAM-LEVEL: Spam detection results: 0 AWL -1.064 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 POISEN_SPAM_PILL 0.1 Meta: its spam POISEN_SPAM_PILL_1 0.1 random spam to be learned in bayes POISEN_SPAM_PILL_3 0.1 random spam to be learned in bayes SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pdm-devel] [PATCH datacenter-manager 1/4] tree-wide: add missing `returns` definitions to api macro 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" so this information shows up properly in a potential api viewer Signed-off-by: Shannon Sterz --- server/src/api/access/tfa.rs | 10 ++++++ server/src/api/config/acme.rs | 9 +++++ server/src/api/config/views.rs | 1 + server/src/api/metric_collection.rs | 10 +++++- server/src/api/mod.rs | 22 ++++++++++++ server/src/api/nodes/certificates.rs | 9 +++++ server/src/api/nodes/network.rs | 3 ++ server/src/api/nodes/rrddata.rs | 7 ++++ server/src/api/nodes/tasks.rs | 50 +++++++++++++++++++++++++++- server/src/api/pbs/mod.rs | 7 ++++ server/src/api/pbs/rrddata.rs | 14 ++++++-- server/src/api/pve/mod.rs | 8 +++++ server/src/api/pve/node.rs | 15 +++++++++ server/src/api/pve/qemu.rs | 1 + server/src/api/pve/rrddata.rs | 21 ++++++++++++ server/src/api/remote_tasks.rs | 8 +++++ server/src/api/remote_updates.rs | 3 ++ server/src/api/remotes.rs | 7 ++++ server/src/api/resources.rs | 1 + 19 files changed, 202 insertions(+), 4 deletions(-) diff --git a/server/src/api/access/tfa.rs b/server/src/api/access/tfa.rs index a3bb628..8b1f7c6 100644 --- a/server/src/api/access/tfa.rs +++ b/server/src/api/access/tfa.rs @@ -103,6 +103,13 @@ fn list_tfa(rpcenv: &mut dyn RpcEnvironment) -> Result, Er &Permission::UserParam("userid"), ]), }, + returns: { + type: Array, + description: "A list of TFA entries for a user.", + items: { + type: methods::TypedTfaInfo, + } + } )] /// Add a TOTP secret to the user. fn list_user_tfa(userid: Userid) -> Result, Error> { @@ -125,6 +132,9 @@ fn list_user_tfa(userid: Userid) -> Result, Error> { &Permission::UserParam("userid"), ]), }, + returns: { + type: methods::TypedTfaInfo, + } )] /// Get a single TFA entry. fn get_tfa_entry(userid: Userid, id: String) -> Result { diff --git a/server/src/api/config/acme.rs b/server/src/api/config/acme.rs index 2a5cc9d..0c583c4 100644 --- a/server/src/api/config/acme.rs +++ b/server/src/api/config/acme.rs @@ -111,6 +111,9 @@ pub fn list_accounts() -> Result, Error> { permission: &Permission::Privilege(&["system", "certificates"], PRIV_SYS_MODIFY, false), }, protected: true, + returns: { + schema: pdm_api_types::UPID_SCHEMA, + }, )] /// Register an ACME account. fn register_account( @@ -193,6 +196,9 @@ pub async fn get_account(name: AcmeAccountName) -> Result { permission: &Permission::Privilege(&["system", "certificates"], PRIV_SYS_MODIFY, false), }, protected: true, + returns: { + schema: pdm_api_types::UPID_SCHEMA, + }, )] /// Update an ACME account. pub fn update_account( @@ -236,6 +242,9 @@ pub fn update_account( permission: &Permission::Privilege(&["system", "certificates"], PRIV_SYS_MODIFY, false), }, protected: true, + returns: { + schema: pdm_api_types::UPID_SCHEMA, + }, )] /// Deactivate an ACME account. pub fn deactivate_account( diff --git a/server/src/api/config/views.rs b/server/src/api/config/views.rs index 79bc6f1..3e2865d 100644 --- a/server/src/api/config/views.rs +++ b/server/src/api/config/views.rs @@ -257,6 +257,7 @@ pub fn remove_view(id: String, digest: Option) -> Result<(), Error access: { permission: &Permission::Privilege(&["view", "{id}"], PRIV_RESOURCE_AUDIT, false), }, + returns: { type: ViewConfig }, )] /// Get the config of a single view. pub fn read_view(id: String) -> Result { diff --git a/server/src/api/metric_collection.rs b/server/src/api/metric_collection.rs index 0658fb1..b4c81c6 100644 --- a/server/src/api/metric_collection.rs +++ b/server/src/api/metric_collection.rs @@ -39,7 +39,15 @@ pub async fn trigger_metric_collection(remote: Option) -> Result<(), Err Ok(()) } -#[api] +#[api( + returns: { + type: Array, + description: "A list of metric collection statuses.", + items: { + type: MetricCollectionStatus, + } + } +)] /// Read metric collection status. fn get_metric_collection_status() -> Result, Error> { metric_collection::get_status() diff --git a/server/src/api/mod.rs b/server/src/api/mod.rs index ef9964d..e3efed8 100644 --- a/server/src/api/mod.rs +++ b/server/src/api/mod.rs @@ -48,6 +48,10 @@ pub const ROUTER: Router = Router::new() access: { description: "Anyone can access this, just a cheap check if the API daemon is online.", permission: &Permission::World, + }, + returns: { + type: String, + description: "The string \"pong\"." } )] /// A simple ping method. returns "pong" @@ -59,6 +63,24 @@ fn ping() -> Result { access: { description: "Any valid user can access this.", permission: &Permission::Anybody, + }, + returns: { + type: Object, + description: "Version information.", + properties: { + version: { + type: String, + description: "The version string." + }, + release: { + type: String, + description: "The package release.", + }, + repoid: { + type: String, + description: "The repoid." + } + } } )] /// Return the program's version/release info diff --git a/server/src/api/nodes/certificates.rs b/server/src/api/nodes/certificates.rs index 52c2ae3..5d8b924 100644 --- a/server/src/api/nodes/certificates.rs +++ b/server/src/api/nodes/certificates.rs @@ -201,6 +201,9 @@ pub async fn delete_custom_certificate() -> Result<(), Error> { permission: &Permission::Privilege(&["system", "certificates"], PRIV_SYS_MODIFY, false), }, protected: true, + returns: { + schema: pdm_api_types::UPID_SCHEMA, + } )] /// Order a new ACME certificate. pub fn new_acme_cert(force: bool, rpcenv: &mut dyn RpcEnvironment) -> Result { @@ -223,6 +226,9 @@ pub fn new_acme_cert(force: bool, rpcenv: &mut dyn RpcEnvironment) -> Result) -> Result<( access: { permission: &Permission::Privilege(&["system", "network", "interfaces"], PRIV_SYS_MODIFY, false), }, + returns: { + schema: pdm_api_types::UPID_SCHEMA, + } )] /// Reload network configuration (requires ifupdown2). pub async fn reload_network_config(rpcenv: &mut dyn RpcEnvironment) -> Result { diff --git a/server/src/api/nodes/rrddata.rs b/server/src/api/nodes/rrddata.rs index de7f5a5..7590096 100644 --- a/server/src/api/nodes/rrddata.rs +++ b/server/src/api/nodes/rrddata.rs @@ -38,6 +38,13 @@ impl DataPoint for PdmNodeDatapoint { }, }, }, + returns: { + type: Array, + description: "An array of RRD data points.", + items: { + type: PdmNodeDatapoint, + } + } )] /// Read RRD data for this PDM node. fn get_node_rrddata(timeframe: RrdTimeframe, cf: RrdMode) -> Result, Error> { diff --git a/server/src/api/nodes/tasks.rs b/server/src/api/nodes/tasks.rs index 9725f02..00dcf35 100644 --- a/server/src/api/nodes/tasks.rs +++ b/server/src/api/nodes/tasks.rs @@ -311,6 +311,39 @@ const TEST_STATUS_PARAM_SCHEMA: Schema = proxmox_schema::BooleanSchema::new( ) .schema(); +#[sortable] +const DATA_SCHEMA: Schema = proxmox_schema::ObjectSchema::new( + "A line of a task log.", + &sorted!([ + ( + "n", + false, + &proxmox_schema::IntegerSchema::new("Line number.") + .minimum(0) + .schema() + ), + ( + "t", + false, + &proxmox_schema::StringSchema::new("The line of the log.").schema() + ) + ]), +) +.schema(); + +const TOTAL_SCHEMA: Schema = proxmox_schema::IntegerSchema::new("Total number of lines.") + .minimum(0) + .schema(); + +const SUCCESS_SCHEMA: Schema = + proxmox_schema::IntegerSchema::new("Whether the request was successful.") + .minimum(0) + .maximum(1) + .schema(); + +const ACTIVE_SCHEMA: Schema = + proxmox_schema::BooleanSchema::new("Whether the task is still active.").schema(); + #[sortable] pub const API_METHOD_READ_TASK_LOG: proxmox_router::ApiMethod = proxmox_router::ApiMethod::new( &proxmox_router::ApiHandler::AsyncHttp(&read_task_log), @@ -329,7 +362,22 @@ pub const API_METHOD_READ_TASK_LOG: proxmox_router::ApiMethod = proxmox_router:: .access( Some("Users can access their own tasks, or need Sys.Audit on /system/tasks."), &Permission::Anybody, -); +) +.returns(proxmox_schema::ReturnType::new( + true, + &proxmox_schema::ObjectSchema::new( + "Returns lines of a task log. If `download` is set to `true`, instead of providing a JSON\ + response the log file will be downloaded.", + &sorted!([ + ("data", false, &DATA_SCHEMA), + ("total", false, &TOTAL_SCHEMA), + ("success", false, &SUCCESS_SCHEMA), + ("active", false, &ACTIVE_SCHEMA) + ]), + ) + .schema(), +)); + fn read_task_log( _parts: Parts, _req_body: hyper::body::Incoming, diff --git a/server/src/api/pbs/mod.rs b/server/src/api/pbs/mod.rs index 15e4272..7679159 100644 --- a/server/src/api/pbs/mod.rs +++ b/server/src/api/pbs/mod.rs @@ -142,6 +142,11 @@ async fn list_datastores(remote: String) -> Result Result, Error> permission: &Permission::Privilege(&["/"], PRIV_SYS_MODIFY, false), }, + returns: { type: Remote } )] /// Scans the given connection info for pbs host information. /// @@ -294,6 +300,7 @@ pub async fn scan_remote_pbs( permission: &Permission::Privilege(&["resource", "{remote}"], PRIV_RESOURCE_AUDIT, false), description: "The user needs to have at least the `Resource.Audit` privilege on `/resource/{remote}`." }, + returns: { type: pbs_api_types::NodeStatus } )] /// Get status for the PBS remote async fn get_status(remote: String) -> Result { diff --git a/server/src/api/pbs/rrddata.rs b/server/src/api/pbs/rrddata.rs index 74c670d..ffc8006 100644 --- a/server/src/api/pbs/rrddata.rs +++ b/server/src/api/pbs/rrddata.rs @@ -104,7 +104,12 @@ impl DataPoint for PbsDatastoreDataPoint { access: { permission: &Permission::Privilege(&["resource", "{remote}"], PRIV_RESOURCE_AUDIT, false), description: "The user needs to have at least the `Resource.Audit` privilege on `/resource/{remote}`." - } + }, + returns: { + type: Array, + description: "A list of PBS node data points.", + items: { type: PbsNodeDataPoint }, + }, )] /// Read PBS node stats async fn get_pbs_node_rrd_data( @@ -133,7 +138,12 @@ async fn get_pbs_node_rrd_data( access: { permission: &Permission::Privilege(&["resource", "{remote}", "datastore", "{datastore}"], PRIV_RESOURCE_AUDIT, false), description: "The user needs to have at least the `Resource.Audit` privilege on `/resource/{remote}/datastore/{datastore}`." - } + }, + returns: { + type: Array, + description: "A list of PBS datastore data points.", + items: { type: PbsDatastoreDataPoint }, + }, )] /// Read PBS datastore stats async fn get_pbs_datastore_rrd_data( diff --git a/server/src/api/pve/mod.rs b/server/src/api/pve/mod.rs index 34d9b76..05dd557 100644 --- a/server/src/api/pve/mod.rs +++ b/server/src/api/pve/mod.rs @@ -386,6 +386,7 @@ async fn probe_tls( permission: &Permission::Privilege(&["/"], PRIV_SYS_MODIFY, false), }, + returns: { type: Remote }, )] /// Scans the given connection info for pve cluster information /// @@ -474,6 +475,13 @@ pub async fn scan_remote_pve( permission: &Permission::Privilege(&["/"], PRIV_SYS_MODIFY, false), }, + returns: { + type: Array, + description: "A list of realms of a PVE remote.", + items: { + type: ListRealm, + } + }, )] /// Scans the given connection info for pve cluster information pub async fn list_realm_remote_pve( diff --git a/server/src/api/pve/node.rs b/server/src/api/pve/node.rs index 47bd5b3..d8690f6 100644 --- a/server/src/api/pve/node.rs +++ b/server/src/api/pve/node.rs @@ -48,6 +48,13 @@ const STORAGE_ROUTER: Router = Router::new() }, access: { permission: &Permission::Privilege(&["resource", "{remote}", "node", "{node}"], PRIV_RESOURCE_AUDIT, false), + }, + returns: { + type: Array, + description: "A list of network interfaces of a PVE remote.", + items: { + type: pve_api_types::NetworkInterface, + } } )] /// Get network interfaces from PVE node @@ -100,6 +107,13 @@ async fn get_network( access: { permission: &Permission::Privilege(&["resource", "{remote}", "node", "{node}"], PRIV_RESOURCE_AUDIT, false), description: "if `target` is set, also requires PRIV_RESOURCE_AUDIT on /resource/{remote}/node/{target}" + }, + returns: { + type: Array, + description: "A list of storages of a PVE remote.", + items: { + type: pve_api_types::StorageInfo + } } )] /// Get status for all datastores @@ -130,6 +144,7 @@ async fn get_storages( access: { permission: &Permission::Privilege(&["resource", "{remote}", "node", "{node}"], PRIV_RESOURCE_AUDIT, false), }, + returns: { type: pve_api_types::NodeStatus }, )] /// Get status for the node async fn get_status(remote: String, node: String) -> Result { diff --git a/server/src/api/pve/qemu.rs b/server/src/api/pve/qemu.rs index cd0d5d2..efab228 100644 --- a/server/src/api/pve/qemu.rs +++ b/server/src/api/pve/qemu.rs @@ -440,6 +440,7 @@ pub async fn qemu_migrate( &Permission::Privilege(&["resource", "{remote}", "guest", "{vmid}"], PRIV_RESOURCE_MIGRATE, false), ]), }, + returns: { type: QemuMigratePreconditions } )] /// Qemu (local) migrate preconditions async fn qemu_migrate_preconditions( diff --git a/server/src/api/pve/rrddata.rs b/server/src/api/pve/rrddata.rs index 9fed967..226b675 100644 --- a/server/src/api/pve/rrddata.rs +++ b/server/src/api/pve/rrddata.rs @@ -180,6 +180,13 @@ impl DataPoint for PveStorageDataPoint { access: { permission: &Permission::Privilege(&["resource", "{remote}", "guest", "{vmid}"], PRIV_RESOURCE_AUDIT, false), }, + returns: { + type: Array, + description: "A list of RRD data points for a QEMU guest.", + items: { + type: QemuDataPoint + } + } )] /// Read qemu stats async fn get_qemu_rrd_data( @@ -209,6 +216,13 @@ async fn get_qemu_rrd_data( access: { permission: &Permission::Privilege(&["resource", "{remote}", "guest", "{vmid}"], PRIV_RESOURCE_AUDIT, false), }, + returns: { + type: Array, + description: "A list of RRD data points for an LXC guest.", + items: { + type: LxcDataPoint + } + } )] /// Read lxc stats async fn get_lxc_rrd_data( @@ -238,6 +252,13 @@ async fn get_lxc_rrd_data( access: { permission: &Permission::Privilege(&["resource", "{remote}", "node", "{node}"], PRIV_RESOURCE_AUDIT, false), }, + returns: { + type: Array, + description: "A list of RRD data points for a PVE node.", + items: { + type: NodeDataPoint + } + } )] /// Read node stats async fn get_node_rrd_data( diff --git a/server/src/api/remote_tasks.rs b/server/src/api/remote_tasks.rs index 02b6383..bce427f 100644 --- a/server/src/api/remote_tasks.rs +++ b/server/src/api/remote_tasks.rs @@ -49,6 +49,13 @@ const SUBDIRS: SubdirMap = &sorted!([ }, }, + returns: { + type: Array, + description: "A list of tasks for all remotes.", + items: { + type: TaskListItem + } + }, )] /// Get the list of tasks for all remotes. async fn list_tasks( @@ -91,6 +98,7 @@ async fn list_tasks( }, }, }, + returns: { type: TaskStatistics } )] /// Get task statistics for the specified filters. async fn task_statistics( diff --git a/server/src/api/remote_updates.rs b/server/src/api/remote_updates.rs index bea2d86..f630e50 100644 --- a/server/src/api/remote_updates.rs +++ b/server/src/api/remote_updates.rs @@ -38,6 +38,7 @@ const SUBDIRS: SubdirMap = &sorted!([ permission: &Permission::Anybody, description: "Resource.Modify privileges are needed on /resource/{remote}", }, + returns: { type: UpdateSummary } )] /// Return available update summary for managed remote nodes. pub fn update_summary(rpcenv: &mut dyn RpcEnvironment) -> Result { @@ -69,6 +70,7 @@ pub fn update_summary(rpcenv: &mut dyn RpcEnvironment) -> Result Result { @@ -158,6 +160,7 @@ async fn apt_update_available(remote: String, node: String) -> Result Result { diff --git a/server/src/api/remotes.rs b/server/src/api/remotes.rs index 5d5d9fd..bc0c871 100644 --- a/server/src/api/remotes.rs +++ b/server/src/api/remotes.rs @@ -376,6 +376,13 @@ impl DataPoint for RemoteDatapoint { }, }, }, + returns: { + type: Array, + description: "A list remote RRD data points.", + items: { + type: RemoteDatapoint, + } + } )] /// Read metric collection RRD data. fn get_per_remote_rrd_data( diff --git a/server/src/api/resources.rs b/server/src/api/resources.rs index 15c2c47..7eeb0ce 100644 --- a/server/src/api/resources.rs +++ b/server/src/api/resources.rs @@ -706,6 +706,7 @@ pub async fn get_subscription_status( Only resources for which the user has `Resource.Audit` on `/resource/{remote_name}` will be considered when calculating the top entities." }, + returns: { type: TopEntities } )] /// Returns the top X entities regarding the chosen type async fn get_top_entities( -- 2.47.3 _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel