Skip to main content

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}