Skip to content

Wip/qmonet/frr reload (rebased) #428

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
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
143 changes: 143 additions & 0 deletions mgmt/src/frr/frr_reload/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Open Network Fabric Authors

//! Wrapper for the FRR reload utility (frr_reload.py).

use std::process::{Command, Stdio};
use tracing::info;

#[allow(dead_code)]
pub fn reload_frr(
frr_reload_bin: &str,
frr_config_file: &str,
) -> Result<(), Box<dyn std::error::Error>> {
frr_test_config(frr_reload_bin, frr_config_file)?;
frr_do_reload(frr_reload_bin, frr_config_file)?;

info!("FRR successfully reloaded");
Ok(())
}

fn frr_test_config(
frr_reload_bin: &str,
frr_config_file: &str,
) -> Result<(), Box<dyn std::error::Error>> {
run_frr_reload_script(frr_reload_bin, frr_config_file, &["--test"])
}

fn frr_do_reload(
frr_reload_bin: &str,
frr_config_file: &str,
) -> Result<(), Box<dyn std::error::Error>> {
run_frr_reload_script(
frr_reload_bin,
frr_config_file,
&["--reload", "--overwrite"],
)
}

fn run_frr_reload_script(
frr_reload_bin: &str,
frr_config_file: &str,
action_args: &[&str],
) -> Result<(), Box<dyn std::error::Error>> {
let output = Command::new(frr_reload_bin)
.args(action_args)
.arg(frr_config_file)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.map_err(|e| format!("Failed to spawn command: {}", e))?
.wait_with_output()
.map_err(|e| format!("Failed to wait for command: {}", e))?;

if !output.stderr.is_empty() {
return Err(format!(
"Command printed an error message. Command status: {}, stdout: {}, stderr: {}",
output.status,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
)
.into());
}

if !output.status.success() {
return Err(format!(
"Command exited with non-zero status. Command status: {}, stdout: {}, stderr: {}",
output.status,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
)
.into());
}

Ok(())
}

#[cfg(test)]
mod tests {
use super::*;

const FRR_CONFIG: &str = "/etc/frr/frr.conf";

fn binpath(name: &str) -> String {
let test_path: &str = "mgmt/src/processor/frr_reload_test";
format!("{test_path}/{name}")
}

#[test]
fn test_reload_frr() {
let bin = binpath("pass");
let result = reload_frr(bin.as_str(), FRR_CONFIG);
assert!(
result.is_ok(),
"FRR reload test failed: {:?} (bin: {bin})",
result
);
}

#[test]
fn test_reload_frr_fail_errcode() {
let result = frr_do_reload(binpath("fail-errcode").as_str(), FRR_CONFIG);
assert!(
result.is_err(),
"FRR config test succeeded unexpectedly: {:?}",
result
);
assert_eq!(
result.map_err(|e| e.to_string()),
Err("Command exited with non-zero status. Command status: exit status: 1, stdout: , stderr: "
.to_string())
);
}

#[test]
fn test_reload_frr_fail_stderr() {
let result = frr_do_reload(binpath("fail-stderr").as_str(), FRR_CONFIG);
assert!(
result.is_err(),
"FRR cofig test succeeded unexpectedly: {:?}",
result
);
assert_eq!(
result.map_err(|e| e.to_string()),
Err("Command printed an error message. Command status: exit status: 0, stdout: , stderr: failure\n"
.to_string())
);
}

#[test]
fn test_reload_frr_errcode_stderr() {
let result = frr_do_reload(binpath("fail-errcode-stderr").as_str(), FRR_CONFIG);
assert!(
result.is_err(),
"FRR cofig test succeeded unexpectedly: {:?}",
result
);
assert_eq!(
result.map_err(|e| e.to_string()),
Err("Command printed an error message. Command status: exit status: 1, stdout: , stderr: failure\n"
.to_string())
);
}
}
Binary file added mgmt/src/frr/frr_reload/test/fail-errcode
Binary file not shown.
Binary file added mgmt/src/frr/frr_reload/test/fail-errcode-stderr
Binary file not shown.
6 changes: 6 additions & 0 deletions mgmt/src/frr/frr_reload/test/fail-errcode-stderr.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <stdio.h>

int main(void) {
fprintf(stderr, "failure\n");
return 1;
}
3 changes: 3 additions & 0 deletions mgmt/src/frr/frr_reload/test/fail-errcode.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
int main(void) {
return 1;
}
Binary file added mgmt/src/frr/frr_reload/test/fail-stderr
Binary file not shown.
6 changes: 6 additions & 0 deletions mgmt/src/frr/frr_reload/test/fail-stderr.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <stdio.h>

int main(void) {
fprintf(stderr, "failure\n");
return 0;
}
Binary file added mgmt/src/frr/frr_reload/test/pass
Binary file not shown.
6 changes: 6 additions & 0 deletions mgmt/src/frr/frr_reload/test/pass.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <stdio.h>

int main(void) {
fprintf(stdout, "success\n");
return 0;
}
2 changes: 2 additions & 0 deletions mgmt/src/frr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@
//! FRR drivers: the logic to drive FRR.
//! Currently only one driver exists, leveraging frr-reload.py.

pub mod frr_reload;
pub mod renderer;

1 change: 1 addition & 0 deletions mgmt/src/processor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ mod confbuild;
mod namegen;
pub mod proc;
mod tests;

Loading