Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/ami.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,13 @@ impl Redfish for Bmc {
fn set_utc_timezone<'a>(&'a self) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.s.set_utc_timezone().await })
}

fn set_ntp_servers<'a>(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AMI servers require PATCH's to be sent with an If-Match header. Instead of delegating it to the standard implementation, do the following:

        if servers.is_empty() {
            return Ok(());
        }
        let url = format!("Managers/{}/NetworkProtocol", self.s.manager_id());
        let body = HashMap::from([(
            "NTP",
            serde_json::json!({
                "NTPServers": servers,
                "ProtocolEnabled": true,
            }),
        )]);
        self.s.client.patch_with_if_match(&url, body).await

&'a self,
servers: &'a [String],
) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.s.set_manager_ntp_servers(servers).await })
}
}

impl Bmc {
Expand Down
45 changes: 45 additions & 0 deletions src/dell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1388,6 +1388,51 @@ impl Redfish for Bmc {
Ok(())
})
}

fn set_ntp_servers<'a>(
&'a self,
servers: &'a [String],
) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move {
if servers.is_empty() {
return Ok(());
}

let mut attrs = HashMap::new();
attrs.insert("NTPConfigGroup.1.NTPEnable", "Enabled");

@krish-nvidia krish-nvidia Jun 11, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused slots keep stale values when fewer than 3 servers are passed into set_ntp_servers. We should explicitly blank them out so the set is authoritative. Something like:

let mut attrs = HashMap::from([("NTPConfigGroup.1.NTPEnable", "Enabled")]);
const NTP_KEYS: [&str; 3] = [
    "NTPConfigGroup.1.NTP1",
    "NTPConfigGroup.1.NTP2",
    "NTPConfigGroup.1.NTP3",
];
for (i, key) in NTP_KEYS.into_iter().enumerate() {
    // blank unused slots so the set is authoritative
    attrs.insert(key, servers.get(i).map_or("", String::as_str));
}

if let Some(s1) = servers.first() {
attrs.insert("NTPConfigGroup.1.NTP1", s1.as_str());
}
if let Some(s2) = servers.get(1) {
attrs.insert("NTPConfigGroup.1.NTP2", s2.as_str());
}
if let Some(s3) = servers.get(2) {
attrs.insert("NTPConfigGroup.1.NTP3", s3.as_str());
}

// Try standard path first
let body = HashMap::from([("Attributes", attrs)]);
let manager_id = self.s.manager_id();
let standard_url = format!("Managers/{manager_id}/Attributes");
match self.s.client.patch(&standard_url, &body).await {
Ok(_) => return Ok(()),
Err(RedfishError::HTTPErrorCode {
status_code: StatusCode::NOT_FOUND,
..
}) => {
tracing::info!(
"Managers/Attributes not found, using OEM DellAttributes path for NTP server config"
);
}
Err(e) => return Err(e),
}

// Fallback to OEM DellAttributes path
let oem_url = format!("Managers/{manager_id}/Oem/Dell/DellAttributes/{manager_id}");
self.s.client.patch(&oem_url, body).await?;
Ok(())
})
}
}

impl Bmc {
Expand Down
21 changes: 21 additions & 0 deletions src/hpe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1197,6 +1197,27 @@ impl Redfish for Bmc {
fn set_utc_timezone<'a>(&'a self) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.s.set_utc_timezone().await })
}

fn set_ntp_servers<'a>(
&'a self,
servers: &'a [String],
) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move {
if servers.is_empty() {
return Ok(());
}

// iLO supports at most 2 static NTP servers; extra entries are ignored.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can do something like this instead:
let static_ntp_servers: Vec<String> = servers.iter().take(2).cloned().collect();

Also we should log when a user passes in more than 2 servers:

if servers.len() > 2 {
    tracing::warn!("iLO supports at most 2 static NTP servers; ignoring {} extra", servers.len() - 2);
}

let static_ntp_servers = vec![
servers.first().cloned().unwrap_or_default(),
servers.get(1).cloned().unwrap_or_default(),
];

let url = format!("Managers/{}/DateTime", self.s.manager_id());
let body = HashMap::from([("StaticNTPServers", static_ntp_servers)]);
self.s.client.patch(&url, body).await.map(|_resp| ())
})
}
}

impl Bmc {
Expand Down
7 changes: 7 additions & 0 deletions src/lenovo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1230,6 +1230,13 @@ impl Redfish for Bmc {
fn set_utc_timezone<'a>(&'a self) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.s.set_utc_timezone().await })
}

fn set_ntp_servers<'a>(
&'a self,
servers: &'a [String],
) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.s.set_manager_ntp_servers(servers).await })
}
}

impl Bmc {
Expand Down
6 changes: 6 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,12 @@ pub trait Redfish: Send + Sync + 'static {
// Sets the timezone to UTC
// Only applicable to Dells
fn set_utc_timezone<'a>(&'a self) -> RedfishFuture<'a, Result<(), RedfishError>>;

// Sets the NTP servers
fn set_ntp_servers<'a>(
&'a self,
servers: &'a [String],
) -> RedfishFuture<'a, Result<(), RedfishError>>;
}

#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)]
Expand Down
7 changes: 7 additions & 0 deletions src/liteon_powershelf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,13 @@ impl Redfish for Bmc {
fn set_utc_timezone<'a>(&'a self) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.s.set_utc_timezone().await })
}

fn set_ntp_servers<'a>(
&'a self,
servers: &'a [String],
) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.s.set_manager_ntp_servers(servers).await })
}
}

impl Bmc {
Expand Down
7 changes: 7 additions & 0 deletions src/nvidia_dpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1101,6 +1101,13 @@ impl Redfish for Bmc {
fn set_utc_timezone<'a>(&'a self) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.s.set_utc_timezone().await })
}

fn set_ntp_servers<'a>(
&'a self,
servers: &'a [String],
) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.s.set_manager_ntp_servers(servers).await })
}
}

impl Bmc {
Expand Down
7 changes: 7 additions & 0 deletions src/nvidia_gbswitch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1075,6 +1075,13 @@ impl Redfish for Bmc {
fn set_utc_timezone<'a>(&'a self) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.s.set_utc_timezone().await })
}

fn set_ntp_servers<'a>(
&'a self,
servers: &'a [String],
) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.s.set_manager_ntp_servers(servers).await })
}
}

impl Bmc {
Expand Down
7 changes: 7 additions & 0 deletions src/nvidia_gbx00.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1329,6 +1329,13 @@ impl Redfish for Bmc {
fn set_utc_timezone<'a>(&'a self) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.s.set_utc_timezone().await })
}

fn set_ntp_servers<'a>(
&'a self,
servers: &'a [String],
) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.s.set_manager_ntp_servers(servers).await })
}
}

impl Bmc {
Expand Down
7 changes: 7 additions & 0 deletions src/nvidia_gh200.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1023,6 +1023,13 @@ impl Redfish for Bmc {
fn set_utc_timezone<'a>(&'a self) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.s.set_utc_timezone().await })
}

fn set_ntp_servers<'a>(
&'a self,
servers: &'a [String],
) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.s.set_manager_ntp_servers(servers).await })
}
}

impl Bmc {
Expand Down
7 changes: 7 additions & 0 deletions src/nvidia_viking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1268,6 +1268,13 @@ impl Redfish for Bmc {
fn set_utc_timezone<'a>(&'a self) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.s.set_utc_timezone().await })
}

fn set_ntp_servers<'a>(
&'a self,
servers: &'a [String],
) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.s.set_manager_ntp_servers(servers).await })
}
}

impl Bmc {
Expand Down
24 changes: 24 additions & 0 deletions src/standard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1230,6 +1230,13 @@ impl Redfish for RedfishStandard {
Ok(())
})
}

fn set_ntp_servers<'a>(
&'a self,
servers: &'a [String],
) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.set_manager_ntp_servers(servers).await })
}
}

impl RedfishStandard {
Expand Down Expand Up @@ -1624,6 +1631,23 @@ impl RedfishStandard {
Ok(body)
}

/// Set NTP servers via the standard ManagerNetworkProtocol resource.
pub async fn set_manager_ntp_servers(&self, servers: &[String]) -> Result<(), RedfishError> {
if servers.is_empty() {
return Ok(());
}

let url = format!("Managers/{}/NetworkProtocol", self.manager_id(),);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: extra comma next to self.manager_id()

let ntp_servers = HashMap::from([(
"NTP",
json!({
"NTPServers": servers,
"ProtocolEnabled": true,
}),
)]);
self.client.patch(&url, ntp_servers).await.map(|_resp| ())
}

pub async fn reset_manager(
&self,
reset_type: ManagerResetType,
Expand Down
7 changes: 7 additions & 0 deletions src/supermicro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,13 @@ impl Redfish for Bmc {
fn set_utc_timezone<'a>(&'a self) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.s.set_utc_timezone().await })
}

fn set_ntp_servers<'a>(
&'a self,
servers: &'a [String],
) -> crate::RedfishFuture<'a, Result<(), RedfishError>> {
Box::pin(async move { self.s.set_manager_ntp_servers(servers).await })
}
}

impl Bmc {
Expand Down
Loading