use serde::{Deserialize, Serialize}; use serde_json::Value; pub fn odata_ref(id: &str) -> ODataLink { ODataLink { odata_id: id.to_string(), } } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct ODataLink { #[serde(rename = "@odata.id")] pub odata_id: String, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct Status { pub state: String, pub health: String, #[serde(skip_serializing_if = "Option::is_none")] pub health_rollup: Option, } impl Status { pub fn enabled_ok() -> Self { Self { state: "Enabled".to_string(), health: "OK".to_string(), health_rollup: None, } } pub fn enabled_health(health: &str) -> Self { Self { state: "Enabled".to_string(), health: health.to_string(), health_rollup: None, } } pub fn disabled_ok() -> Self { Self { state: "Disabled".to_string(), health: "OK".to_string(), health_rollup: None, } } pub fn offline_ok() -> Self { Self { state: "Offline".to_string(), health: "OK".to_string(), health_rollup: None, } } } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct ServiceRoot { #[serde(rename = "@odata.type")] pub odata_type: String, #[serde(rename = "@odata.id")] pub odata_id: String, #[serde(rename = "@odata.context")] pub odata_context: String, pub id: String, pub name: String, pub redfish_version: String, #[serde(rename = "UUID")] pub uuid: String, pub protocol_features_supported: ProtocolFeaturesSupported, pub systems: ODataLink, pub chassis: ODataLink, pub managers: ODataLink, pub session_service: ODataLink, pub account_service: ODataLink, pub event_service: ODataLink, pub links: ServiceRootLinks, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct ProtocolFeaturesSupported { pub excerpt_query: bool, pub expand_query: ExpandQuery, pub filter_query: bool, pub only_member_query: bool, pub select_query: bool, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct ExpandQuery { pub expand_all: bool, pub levels: bool, pub max_levels: u32, pub no_links: bool, pub top: bool, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct ServiceRootLinks { pub sessions: ODataLink, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct Collection { #[serde(rename = "@odata.type")] pub odata_type: String, #[serde(rename = "@odata.id")] pub odata_id: String, #[serde(rename = "@odata.context")] pub odata_context: String, pub name: String, pub description: String, #[serde(rename = "Members@odata.count")] pub members_count: u64, pub members: Vec, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct ComputerSystem { #[serde(rename = "@odata.type")] pub odata_type: String, #[serde(rename = "@odata.id")] pub odata_id: String, #[serde(rename = "@odata.context")] pub odata_context: String, #[serde(rename = "@odata.etag")] pub odata_etag: String, pub id: String, pub name: String, pub description: String, pub system_type: String, pub asset_tag: String, pub manufacturer: String, pub model: String, pub serial_number: String, pub part_number: String, pub power_state: String, pub bios_version: String, pub status: Status, pub boot: Boot, pub processor_summary: ProcessorSummary, pub memory_summary: MemorySummary, pub trusted_modules: Vec, pub actions: ComputerSystemActions, pub links: ComputerSystemLinks, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct Boot { pub boot_source_override_enabled: String, pub boot_source_override_mode: Option, pub boot_source_override_target: Option, pub uefi_target_boot_source_override: Option, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct ProcessorSummary { pub count: Option, pub logical_processor_count: Option, pub model: String, pub status: Status, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct MemorySummary { pub total_system_memory_gi_b: Option, pub status: Status, } #[derive(Debug, Clone, Serialize)] pub struct ComputerSystemActions { #[serde(rename = "#ComputerSystem.Reset")] pub reset: ActionTarget, #[serde(rename = "#ComputerSystem.SetDefaultBootOrder")] pub set_default_boot_order: ActionTarget, } #[derive(Debug, Clone, Serialize)] pub struct ActionTarget { pub target: String, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct ComputerSystemLinks { pub chassis: Vec, pub managed_by: Vec, } #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct ResetRequest { #[serde(default = "default_reset_type")] pub reset_type: String, } #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct ComputerSystemPatchRequest { #[serde(default)] pub boot: Option, } #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct BootPatch { #[serde(default)] pub boot_source_override_enabled: Option, #[serde(default)] pub boot_source_override_target: Option, #[serde(default)] pub boot_source_override_mode: Option, #[serde(default)] pub uefi_target_boot_source_override: Option, } fn default_reset_type() -> String { "ForceRestart".to_string() } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct Manager { #[serde(rename = "@odata.type")] pub odata_type: String, #[serde(rename = "@odata.id")] pub odata_id: String, #[serde(rename = "@odata.context")] pub odata_context: String, pub id: String, pub name: String, pub description: String, pub manager_type: String, pub status: Status, pub firmware_version: String, pub manufacturer: String, pub model: String, pub date_time: String, pub date_time_local_offset: String, pub service_entry_point_uuid: String, pub command_shell: CommandShell, pub graphical_console: GraphicalConsole, pub virtual_media: ODataLink, pub links: ManagerLinks, pub network_protocol: ODataLink, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct CommandShell { pub service_enabled: bool, pub max_concurrent_sessions: u32, pub connect_types_supported: Vec, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct GraphicalConsole { pub service_enabled: bool, pub max_concurrent_sessions: u32, pub connect_types_supported: Vec, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct ManagerLinks { pub manager_for_servers: Vec, pub manager_for_chassis: Vec, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct VirtualMedia { #[serde(rename = "@odata.type")] pub odata_type: String, #[serde(rename = "@odata.id")] pub odata_id: String, #[serde(rename = "@odata.context")] pub odata_context: String, pub id: String, pub name: String, pub description: String, pub media_types: Vec, pub connected_via: Option, pub inserted: bool, pub image: Option, pub image_name: Option, pub write_protected: bool, pub transfer_method: Option, pub transfer_protocol_type: Option, pub status: Status, pub actions: VirtualMediaActions, } #[derive(Debug, Clone, Serialize)] pub struct VirtualMediaActions { #[serde(rename = "#VirtualMedia.InsertMedia")] pub insert_media: ActionTarget, #[serde(rename = "#VirtualMedia.EjectMedia")] pub eject_media: ActionTarget, } #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct InsertMediaRequest { pub image: String, #[serde(default)] pub write_protected: Option, #[serde(default)] pub transfer_method: Option, #[serde(default)] pub transfer_protocol_type: Option, pub media_types: Option>, pub inserted: Option, pub user_name: Option, pub password: Option, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct Chassis { #[serde(rename = "@odata.type")] pub odata_type: String, #[serde(rename = "@odata.id")] pub odata_id: String, #[serde(rename = "@odata.context")] pub odata_context: String, pub id: String, pub name: String, pub description: String, pub chassis_type: String, pub asset_tag: String, pub manufacturer: String, pub model: String, pub serial_number: String, pub part_number: String, pub power_state: String, pub status: Status, pub power: ODataLink, pub links: ChassisLinks, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct ChassisLinks { pub computer_systems: Vec, pub managed_by: Vec, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct Power { #[serde(rename = "@odata.type")] pub odata_type: String, #[serde(rename = "@odata.id")] pub odata_id: String, #[serde(rename = "@odata.context")] pub odata_context: String, pub id: String, pub name: String, pub power_control: Vec, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct PowerControl { #[serde(rename = "@odata.id")] pub odata_id: String, pub member_id: String, pub name: String, pub power_consumed_watts: Option, pub power_capacity_watts: Option, pub power_requested_watts: Option, pub power_metrics: Option, pub status: Status, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct PowerMetric { pub interval_in_min: u32, pub min_consumed_watts: Option, pub max_consumed_watts: Option, pub average_consumed_watts: Option, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct SessionService { #[serde(rename = "@odata.type")] pub odata_type: String, #[serde(rename = "@odata.id")] pub odata_id: String, #[serde(rename = "@odata.context")] pub odata_context: String, pub id: String, pub name: String, pub description: String, pub service_enabled: bool, pub session_timeout: String, pub sessions: ODataLink, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct Session { #[serde(rename = "@odata.type")] pub odata_type: String, #[serde(rename = "@odata.id")] pub odata_id: String, #[serde(rename = "@odata.context")] pub odata_context: String, pub id: String, pub name: String, pub description: String, pub user_name: String, } #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct SessionCreateRequest { pub user_name: String, pub password: String, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct AccountService { #[serde(rename = "@odata.type")] pub odata_type: String, #[serde(rename = "@odata.id")] pub odata_id: String, #[serde(rename = "@odata.context")] pub odata_context: String, pub id: String, pub name: String, pub description: String, pub service_enabled: bool, pub accounts: ODataLink, pub roles: ODataLink, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct ManagerAccount { #[serde(rename = "@odata.type")] pub odata_type: String, #[serde(rename = "@odata.id")] pub odata_id: String, #[serde(rename = "@odata.context")] pub odata_context: String, pub id: String, pub name: String, pub description: String, pub enabled: bool, pub user_name: String, pub role_id: String, pub locked: bool, pub links: ManagerAccountLinks, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct ManagerAccountLinks { pub role: ODataLink, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct EventService { #[serde(rename = "@odata.type")] pub odata_type: String, #[serde(rename = "@odata.id")] pub odata_id: String, #[serde(rename = "@odata.context")] pub odata_context: String, pub id: String, pub name: String, pub description: String, pub service_enabled: bool, pub delivery_retry_attempts: u32, pub delivery_retry_interval_seconds: u32, pub event_format_types: Vec, pub registry_prefixes: Vec, pub subordinate_resources: bool, #[serde(rename = "SSEFilterPropertiesSupported")] pub sse_filter_properties_supported: SseFilterPropertiesSupported, pub server_sent_event_uri: Option, pub actions: EventServiceActions, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct SseFilterPropertiesSupported { pub event_format_type: bool, pub message_id: bool, pub metric_report_definition: bool, pub origin_resource: bool, pub registry_prefix: bool, pub resource_type: bool, } #[derive(Debug, Clone, Serialize)] pub struct EventServiceActions { #[serde(rename = "#EventService.SubmitTestEvent")] pub submit_test_event: ActionTarget, } #[derive(Debug, Clone, Serialize)] pub struct RedfishError { pub error: RedfishErrorBody, } #[derive(Debug, Clone, Serialize)] pub struct RedfishErrorBody { pub code: String, pub message: String, #[serde( rename = "@Message.ExtendedInfo", skip_serializing_if = "Vec::is_empty" )] pub extended_info: Vec, } #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "PascalCase")] pub struct RedfishExtendedInfo { #[serde(rename = "@odata.type")] pub odata_type: String, pub message_id: String, pub message: String, pub severity: String, pub resolution: String, } impl RedfishError { pub fn general_error(message: &str) -> Self { Self { error: RedfishErrorBody { code: "Base.1.18.GeneralError".to_string(), message: message.to_string(), extended_info: vec![], }, } } pub fn authentication_required() -> Self { Self { error: RedfishErrorBody { code: "Base.1.18.AuthenticationRequired".to_string(), message: "Authentication is required to access this resource".to_string(), extended_info: vec![RedfishExtendedInfo { odata_type: "#Message.v1_2_1.Message".to_string(), message_id: "Base.1.18.AuthenticationRequired".to_string(), message: "Authentication is required to access this resource".to_string(), severity: "Critical".to_string(), resolution: "Authenticate using HTTP Basic auth or create a session via POST /redfish/v1/SessionService/Sessions".to_string(), }], }, } } pub fn invalid_credentials() -> Self { Self { error: RedfishErrorBody { code: "Base.1.18.AuthenticationRequired".to_string(), message: "Invalid username or password".to_string(), extended_info: vec![RedfishExtendedInfo { odata_type: "#Message.v1_2_1.Message".to_string(), message_id: "Base.1.18.InvalidCredentials".to_string(), message: "Invalid username or password".to_string(), severity: "Critical".to_string(), resolution: "Correct the credentials and retry".to_string(), }], }, } } pub fn resource_not_found() -> Self { Self { error: RedfishErrorBody { code: "Base.1.18.ResourceNotFound".to_string(), message: "The requested resource was not found".to_string(), extended_info: vec![], }, } } pub fn action_not_supported(action: &str) -> Self { Self { error: RedfishErrorBody { code: "Base.1.18.ActionNotSupported".to_string(), message: format!("Action '{}' is not supported", action), extended_info: vec![], }, } } pub fn property_missing(property: &str) -> Self { Self { error: RedfishErrorBody { code: "Base.1.18.PropertyMissing".to_string(), message: format!("Property '{}' is required", property), extended_info: vec![], }, } } pub fn service_unavailable(msg: &str) -> Self { Self { error: RedfishErrorBody { code: "Base.1.18.ServiceUnavailable".to_string(), message: msg.to_string(), extended_info: vec![], }, } } }