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 [`Deletable`]
42//! and route operations through a user-provided [`Bmc`] implementation.
43//!
44
45#![deny(
46 clippy::all,
47 clippy::pedantic,
48 clippy::nursery,
49 clippy::suspicious,
50 clippy::complexity,
51 clippy::perf
52)]
53#![deny(
54 clippy::absolute_paths,
55 clippy::todo,
56 clippy::unimplemented,
57 clippy::tests_outside_test_module,
58 clippy::panic,
59 clippy::unwrap_used,
60 clippy::unwrap_in_result,
61 clippy::unused_trait_names,
62 clippy::print_stdout,
63 clippy::print_stderr
64)]
65#![deny(missing_docs)]
66
67/// Action-related types.
68pub mod action;
69/// BMC trait and credentials.
70pub mod bmc;
71/// Custom deserialization helpers.
72pub mod deserialize;
73/// Dynamic properties support.
74pub mod dynamic_properties;
75/// `Edm.DateTimeOffset` type.
76pub mod edm_date_time_offset;
77/// `Edm.Duration` type.
78pub mod edm_duration;
79/// `Edm.PrimitiveType` type.
80pub mod edm_primitive_type;
81/// Navigation property wrapper.
82pub mod nav_property;
83/// Type for `@odata.id` identifier.
84pub mod odata;
85/// Support of redfish queries
86pub mod query;
87
88use crate::query::ExpandQuery;
89use futures_core::TryStream;
90use serde::{Deserialize, Serialize};
91use std::fmt;
92use std::pin::Pin;
93use std::{future::Future, sync::Arc};
94
95#[doc(inline)]
96pub use action::Action;
97#[doc(inline)]
98pub use action::ActionError;
99#[doc(inline)]
100pub use bmc::Bmc;
101#[doc(inline)]
102pub use deserialize::de_optional_nullable;
103#[doc(inline)]
104pub use deserialize::de_required_nullable;
105#[doc(inline)]
106pub use dynamic_properties::DynamicProperties;
107#[doc(inline)]
108pub use edm_date_time_offset::EdmDateTimeOffset;
109#[doc(inline)]
110pub use edm_duration::EdmDuration;
111#[doc(inline)]
112pub use edm_primitive_type::EdmPrimitiveType;
113#[doc(inline)]
114pub use nav_property::NavProperty;
115#[doc(inline)]
116pub use nav_property::Reference;
117#[doc(inline)]
118pub use nav_property::ReferenceLeaf;
119#[doc(inline)]
120pub use odata::ODataETag;
121#[doc(inline)]
122pub use odata::ODataId;
123#[doc(inline)]
124pub use query::FilterQuery;
125#[doc(inline)]
126pub use query::ToFilterLiteral;
127#[doc(inline)]
128pub use serde_json::Value as AdditionalProperties;
129#[doc(inline)]
130pub use uuid::Uuid as EdmGuid;
131
132/// Entity type reference trait implemented by the CSDL compiler
133/// for all generated entity types and for all [`NavProperty<T>`] where
134/// `T` is a struct for an entity type.
135pub trait EntityTypeRef: Send + Sync + Sized {
136 /// Value of `@odata.id` field of the Entity.
137 fn odata_id(&self) -> &ODataId;
138
139 /// Value of `@odata.etag` field of the Entity.
140 fn etag(&self) -> Option<&ODataETag>;
141
142 /// Refresh the entity by fetching it again from the BMC.
143 fn refresh<B: Bmc>(&self, bmc: &B) -> impl Future<Output = Result<Arc<Self>, B::Error>> + Send
144 where
145 Self: for<'de> Deserialize<'de> + 'static,
146 {
147 bmc.get::<Self>(self.odata_id())
148 }
149}
150
151/// Defines entity types that support `$expand` via query parameters.
152pub trait Expandable: EntityTypeRef + for<'de> Deserialize<'de> + 'static {
153 /// Expand the entity according to the provided query.
154 fn expand<B: Bmc>(
155 &self,
156 bmc: &B,
157 query: ExpandQuery,
158 ) -> impl Future<Output = Result<Arc<Self>, B::Error>> + Send {
159 bmc.expand::<Self>(self.odata_id(), query)
160 }
161}
162
163/// Boxed fallible stream used by BMC streaming APIs.
164pub type BoxTryStream<T, E> =
165 Pin<Box<dyn TryStream<Ok = T, Error = E, Item = Result<T, E>> + Send>>;
166
167/// Outcome of a mutating Redfish operation that can complete asynchronously.
168#[derive(Debug)]
169pub struct AsyncTask {
170 /// Request completed successfully with no response body
171 pub id: ODataId,
172 /// The recommended number of seconds to wait before polling again
173 pub retry_after_secs: Option<u64>,
174}
175
176/// Outcome of a mutating Redfish operation.
177#[derive(Debug)]
178pub enum ModificationResponse<T> {
179 /// Request completed synchronously
180 Entity(T),
181 /// Requst completed asynchronously, with the provided `ODataId` to poll for completion
182 Task(AsyncTask),
183 /// Request completed successfully with no response body
184 Empty,
185}
186
187/// Redfish session creation returns the session resource in the response body,
188/// the authentication token in the `X-Auth-Token` header, and the session URI in
189/// the `Location` header.
190pub struct SessionCreateResponse<T> {
191 /// Created session entity.
192 pub entity: T,
193 /// Authentication token from `X-Auth-Token`.
194 pub auth_token: String,
195 /// Session resource URI from `Location`.
196 pub location: ODataId,
197}
198
199impl<T: fmt::Debug> fmt::Debug for SessionCreateResponse<T> {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 f.debug_struct("SessionCreateResponse")
202 .field("entity", &self.entity)
203 .field("auth_token", &"[REDACTED]")
204 .field("location", &self.location)
205 .finish()
206 }
207}
208
209/// This trait is assigned to the collections that are marked as
210/// creatable in the CSDL specification.
211pub trait Creatable<V: Send + Sync + Serialize, R: Send + Sync + for<'de> Deserialize<'de>>:
212 EntityTypeRef
213{
214 /// Create an entity using `create` as payload.
215 fn create<B: Bmc>(
216 &self,
217 bmc: &B,
218 create: &V,
219 ) -> impl Future<Output = Result<ModificationResponse<R>, B::Error>> + Send {
220 bmc.create::<V, R>(self.odata_id(), create)
221 }
222}
223
224/// This trait is assigned to entity types that are marked as
225/// updatable in the CSDL specification.
226pub trait Updatable<V: Sync + Send + Serialize>: EntityTypeRef + for<'de> Deserialize<'de> {
227 /// Update an entity using `update` as payload.
228 fn update<B: Bmc>(
229 &self,
230 bmc: &B,
231 update: &V,
232 ) -> impl Future<Output = Result<ModificationResponse<Self>, B::Error>> + Send {
233 bmc.update::<V, Self>(self.odata_id(), self.etag(), update)
234 }
235}
236
237/// This trait is assigned to entity types that are marked as
238/// deletable in the CSDL specification.
239pub trait Deletable: EntityTypeRef + for<'de> Deserialize<'de> {
240 /// Delete current entity.
241 fn delete<B: Bmc>(
242 &self,
243 bmc: &B,
244 ) -> impl Future<Output = Result<ModificationResponse<Self>, B::Error>> + Send {
245 bmc.delete::<Self>(self.odata_id())
246 }
247}
248
249/// This trait is assigned to updatable entity types to support
250/// @Redfish.Settings workflow.
251pub trait RedfishSettings<E: EntityTypeRef>: Sized {
252 /// Reference to the enity type object.
253 fn settings_object(&self) -> Option<NavProperty<E>>;
254}
255
256/// Trait for converting enum variants to `snake_case` strings
257pub trait ToSnakeCase {
258 /// Convert this enum variant to a `snake_case` string
259 fn to_snake_case(&self) -> &'static str;
260}
261
262/// Trait for types that can be used as filter properties in `OData` queries
263pub trait FilterProperty {
264 /// Returns the `OData` property path for this property
265 fn property_path(&self) -> &str;
266}