nv_redfish_core/lib.rs
1// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16//! Core Redfish foundation library used by code generated from the CSDL compiler.
17//!
18//! Purpose
19//! - Serve as a dependency for autogenerated Redfish types produced by the CSDL compiler.
20//! - Provide semantic-unaware primitives that generated code relies on.
21//! - Avoid any knowledge of specific Redfish services, schemas, or OEM semantics.
22//!
23//! Scope (building blocks only)
24//! - Identity and metadata: [`ODataId`], [`ODataETag`]
25//! - EDM value wrappers: [`EdmDateTimeOffset`], [`EdmDuration`]
26//! - Navigation properties: [`NavProperty<T>`]
27//! - Generic operation traits: [`Creatable`], [`Updatable`], [`Deletable`]
28//! - Entity contracts: [`EntityTypeRef`], [`Expandable`]
29//! - Action envelope: [`Action<T, R>`]
30//! - Client abstraction: [`Bmc`] (transport-agnostic interface used by generated code)
31//!
32//! Non-goals
33//! - No service- or schema-specific models are defined here.
34//! - No business logic or policy decisions are embedded here.
35//! - No transport specification
36//!
37//! How generated code uses these primitives
38//! - Each generated entity struct implements [`EntityTypeRef`].
39//! - Navigation properties in generated code are wrapped in [`NavProperty<T>`].
40//! - Generated actions are represented as [`Action<T, R>`].
41//! - If the schema allows it, generated types implement [`Creatable`], [`Updatable`], and/or
42//! [`Deletable`] and route operations through a user-provided [`Bmc`] implementation.
43
44#![deny(
45 clippy::all,
46 clippy::pedantic,
47 clippy::nursery,
48 clippy::suspicious,
49 clippy::complexity,
50 clippy::perf
51)]
52#![deny(
53 clippy::absolute_paths,
54 clippy::todo,
55 clippy::unimplemented,
56 clippy::tests_outside_test_module,
57 clippy::panic,
58 clippy::unwrap_used,
59 clippy::unwrap_in_result,
60 clippy::unused_trait_names,
61 clippy::print_stdout,
62 clippy::print_stderr
63)]
64#![deny(missing_docs)]
65
66/// Action-related types.
67pub mod action;
68/// BMC trait and credentials.
69pub mod bmc;
70/// Custom deserialization helpers.
71pub mod deserialize;
72/// Dynamic properties support.
73pub mod dynamic_properties;
74/// `Edm.DateTimeOffset` type.
75pub mod edm_date_time_offset;
76/// `Edm.Duration` type.
77pub mod edm_duration;
78/// `Edm.PrimitiveType` type.
79pub mod edm_primitive_type;
80/// Navigation property wrapper.
81pub mod nav_property;
82/// Type for `@odata.id` identifier.
83pub mod odata;
84/// Support of redfish queries
85pub mod query;
86/// Upload data types.
87pub mod upload;
88
89use crate::query::ExpandQuery;
90use futures_core::TryStream;
91use serde::{Deserialize, Serialize};
92use std::fmt;
93use std::pin::Pin;
94use std::time::Duration;
95use std::{future::Future, sync::Arc};
96
97#[doc(inline)]
98pub use action::Action;
99#[doc(inline)]
100pub use action::ActionError;
101#[doc(inline)]
102pub use bmc::Bmc;
103#[doc(inline)]
104pub use deserialize::de_optional_nullable;
105#[doc(inline)]
106pub use deserialize::de_required_nullable;
107#[doc(inline)]
108pub use dynamic_properties::DynamicProperties;
109#[doc(inline)]
110pub use edm_date_time_offset::EdmDateTimeOffset;
111#[doc(inline)]
112pub use edm_duration::EdmDuration;
113#[doc(inline)]
114pub use edm_primitive_type::EdmPrimitiveType;
115#[doc(inline)]
116pub use nav_property::NavProperty;
117#[doc(inline)]
118pub use nav_property::Reference;
119#[doc(inline)]
120pub use nav_property::ReferenceLeaf;
121#[doc(inline)]
122pub use odata::ODataETag;
123#[doc(inline)]
124pub use odata::ODataId;
125#[doc(inline)]
126pub use query::FilterQuery;
127#[doc(inline)]
128pub use query::ToFilterLiteral;
129#[doc(inline)]
130pub use serde_json::Value as AdditionalProperties;
131#[doc(inline)]
132pub use upload::DataStream;
133#[cfg(feature = "update-service-deprecated")]
134#[doc(inline)]
135pub use upload::HttpPushUriUpdateRequest;
136#[doc(inline)]
137pub use upload::MultipartUpdateRequest;
138#[doc(inline)]
139pub use upload::OemMultipartPart;
140#[doc(inline)]
141pub use upload::OemMultipartPartNameError;
142#[doc(inline)]
143pub use upload::OemMultipartPartReader;
144#[doc(inline)]
145pub use upload::UploadReader;
146#[cfg(feature = "update-service-deprecated")]
147#[doc(inline)]
148pub use upload::UploadStream;
149#[doc(inline)]
150pub use uuid::Uuid as EdmGuid;
151
152/// Entity type reference trait implemented by the CSDL compiler
153/// for all generated entity types and for all [`NavProperty<T>`] where
154/// `T` is a struct for an entity type.
155pub trait EntityTypeRef: Send + Sync + Sized {
156 /// Value of `@odata.id` field of the Entity.
157 fn odata_id(&self) -> &ODataId;
158
159 /// Value of `@odata.etag` field of the Entity.
160 fn etag(&self) -> Option<&ODataETag>;
161
162 /// Refresh the entity by fetching it again from the BMC.
163 fn refresh<B: Bmc>(&self, bmc: &B) -> impl Future<Output = Result<Arc<Self>, B::Error>> + Send
164 where
165 Self: for<'de> Deserialize<'de> + 'static,
166 {
167 bmc.get::<Self>(self.odata_id())
168 }
169}
170
171/// Defines entity types that support `$expand` via query parameters.
172pub trait Expandable: EntityTypeRef + for<'de> Deserialize<'de> + 'static {
173 /// Expand the entity according to the provided query.
174 fn expand<B: Bmc>(
175 &self,
176 bmc: &B,
177 query: ExpandQuery,
178 ) -> impl Future<Output = Result<Arc<Self>, B::Error>> + Send {
179 bmc.expand::<Self>(self.odata_id(), query)
180 }
181}
182
183/// Boxed fallible stream used by BMC streaming APIs.
184pub type BoxTryStream<T, E> =
185 Pin<Box<dyn TryStream<Ok = T, Error = E, Item = Result<T, E>> + Send>>;
186
187/// Location of an asynchronous task monitor.
188///
189/// Wraps the `Location` returned for an operation that is completing
190/// asynchronously.
191#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
192#[repr(transparent)]
193pub struct AsyncTaskLocation(
194 /// `OData` URI returned in the async response `Location` header.
195 pub ODataId,
196);
197
198impl From<ODataId> for AsyncTaskLocation {
199 fn from(value: ODataId) -> Self {
200 Self(value)
201 }
202}
203
204/// Outcome of a mutating Redfish operation that can complete asynchronously.
205#[derive(Debug)]
206pub struct AsyncTask {
207 /// Location to use for polling completion.
208 pub location: AsyncTaskLocation,
209
210 /// Recommended duration to wait before polling again.
211 pub retry_after: Option<Duration>,
212}
213
214/// Outcome of a mutating Redfish operation.
215#[derive(Debug)]
216pub enum ModificationResponse<T> {
217 /// Request completed synchronously
218 Entity(T),
219 /// Request is completing asynchronously with the provided task location.
220 Task(AsyncTask),
221 /// Request completed successfully with no response body
222 Empty,
223}
224
225/// Redfish session creation returns the session resource in the response body,
226/// the authentication token in the `X-Auth-Token` header, and the session URI in
227/// the `Location` header.
228pub struct SessionCreateResponse<T> {
229 /// Created session entity.
230 pub entity: T,
231 /// Authentication token from `X-Auth-Token`.
232 pub auth_token: String,
233 /// Session resource URI from `Location`.
234 pub location: ODataId,
235}
236
237impl<T: fmt::Debug> fmt::Debug for SessionCreateResponse<T> {
238 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239 f.debug_struct("SessionCreateResponse")
240 .field("entity", &self.entity)
241 .field("auth_token", &"[REDACTED]")
242 .field("location", &self.location)
243 .finish()
244 }
245}
246
247/// This trait is assigned to the collections that are marked as
248/// creatable in the CSDL specification.
249pub trait Creatable<V: Send + Sync + Serialize, R: Send + Sync + for<'de> Deserialize<'de>>:
250 EntityTypeRef
251{
252 /// Create an entity using `create` as payload.
253 fn create<B: Bmc>(
254 &self,
255 bmc: &B,
256 create: &V,
257 ) -> impl Future<Output = Result<ModificationResponse<R>, B::Error>> + Send {
258 bmc.create::<V, R>(self.odata_id(), create)
259 }
260}
261
262/// This trait is assigned to entity types that are marked as
263/// updatable in the CSDL specification.
264pub trait Updatable<V: Sync + Send + Serialize>: EntityTypeRef + for<'de> Deserialize<'de> {
265 /// Update an entity using `update` as payload.
266 fn update<B: Bmc>(
267 &self,
268 bmc: &B,
269 update: &V,
270 ) -> impl Future<Output = Result<ModificationResponse<Self>, B::Error>> + Send {
271 bmc.update::<V, Self>(self.odata_id(), self.etag(), update)
272 }
273}
274
275/// This trait is assigned to entity types that are marked as
276/// deletable in the CSDL specification.
277pub trait Deletable: EntityTypeRef + for<'de> Deserialize<'de> {
278 /// Delete current entity.
279 fn delete<B: Bmc>(
280 &self,
281 bmc: &B,
282 ) -> impl Future<Output = Result<ModificationResponse<Self>, B::Error>> + Send {
283 bmc.delete::<Self>(self.odata_id())
284 }
285}
286
287/// This trait is assigned to updatable entity types to support
288/// @Redfish.Settings workflow.
289pub trait RedfishSettings<E: EntityTypeRef>: Sized {
290 /// Reference to the enity type object.
291 fn settings_object(&self) -> Option<NavProperty<E>>;
292}
293
294/// Trait for converting enum variants to `snake_case` strings
295pub trait ToSnakeCase {
296 /// Convert this enum variant to a `snake_case` string
297 fn to_snake_case(&self) -> &'static str;
298}
299
300/// Trait for types that can be used as filter properties in `OData` queries
301pub trait FilterProperty {
302 /// Returns the `OData` property path for this property
303 fn property_path(&self) -> &str;
304}