From 8b04dbb4d28f0824ad1c7864e222d6ac109c222f Mon Sep 17 00:00:00 2001 From: Ishan Jain Date: Sun, 1 May 2022 19:38:09 +0530 Subject: [PATCH] Added routing/rule, ip/route. updated system/health, ip/dhcp-client --- src/ip/dhcp_client.rs | 4 +- src/ip/mod.rs | 1 + src/ip/route.rs | 51 ++++++++++ src/ip/types.rs | 48 ++++++++- src/lib.rs | 4 +- src/routing/mod.rs | 4 + src/routing/rule.rs | 52 ++++++++++ src/routing/types.rs | 19 ++++ src/serde_helpers/mod.rs | 1 + src/system/health.rs | 2 +- tests/ip_test.rs | 28 ++++++ tests/routing_test.rs | 212 +++++++++++++++++++++++++++++++++++++++ 12 files changed, 421 insertions(+), 5 deletions(-) create mode 100644 src/ip/route.rs create mode 100644 src/routing/mod.rs create mode 100644 src/routing/rule.rs create mode 100644 src/routing/types.rs create mode 100644 tests/routing_test.rs diff --git a/src/ip/dhcp_client.rs b/src/ip/dhcp_client.rs index 876c47a..77b6dee 100644 --- a/src/ip/dhcp_client.rs +++ b/src/ip/dhcp_client.rs @@ -2,14 +2,14 @@ pub use crate::ip::types::DhcpClient; use crate::{Client, ClientError}; use serde::{Deserialize, Serialize}; -/// list all DHCPv4 Clients +/// List all DHCPv4 Clients pub async fn list(client: &mut Client) -> Result, ClientError> { let url = format!("{}/dhcp-client", super::BASE); client.execute_get::>(&url).await } -/// get a specific DHCPv4 Client +/// Get a specific DHCPv4 Client pub async fn get(client: &mut Client, id: &str) -> Result { let url = format!("{}/dhcp-client/{}", super::BASE, id); diff --git a/src/ip/mod.rs b/src/ip/mod.rs index 42d6909..afa6036 100644 --- a/src/ip/mod.rs +++ b/src/ip/mod.rs @@ -1,6 +1,7 @@ pub mod address; pub mod dhcp_client; pub mod dhcp_server; +pub mod route; mod types; const BASE: &str = "rest/ip"; diff --git a/src/ip/route.rs b/src/ip/route.rs new file mode 100644 index 0000000..c896a4c --- /dev/null +++ b/src/ip/route.rs @@ -0,0 +1,51 @@ +pub use crate::ip::types::Route; +use crate::{Client, ClientError}; +use serde::{Deserialize, Serialize}; + +/// List all IPv4 Routes +pub async fn list(client: &mut Client) -> Result, ClientError> { + let url = format!("{}/route", super::BASE); + + client.execute_get::>(&url).await +} + +/// Get a specific IPv4 Route +pub async fn get(client: &mut Client, rid: &str) -> Result { + let url = format!("{}/route/{}", super::BASE, rid); + + client.execute_get::(&url).await +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct RouteInput { + pub numbers: String, +} + +/// Disable an IPv4 Route +pub async fn disable(client: &mut Client, input: RouteInput) -> Result<(), ClientError> { + let url = format!("{}/route/disable", super::BASE); + + client + .execute_post_with_no_response::(&url, input) + .await +} + +/// Enable an IPv4 Route +pub async fn enable(client: &mut Client, input: RouteInput) -> Result<(), ClientError> { + let url = format!("{}/route/enable", super::BASE); + + client + .execute_post_with_no_response::(&url, input) + .await +} + +/// Remove a IPv4 Route +pub async fn remove(client: &mut Client, input: RouteInput) -> Result<(), ClientError> { + let url = format!("{}/route/remove", super::BASE); + + client + .execute_post_with_no_response::(&url, input) + .await +} + +//TODO(ishan): add set/unset/reset diff --git a/src/ip/types.rs b/src/ip/types.rs index d49ba9b..0d28aaa 100644 --- a/src/ip/types.rs +++ b/src/ip/types.rs @@ -1,4 +1,4 @@ -use crate::serde_helpers::deserialize_bool; +use crate::serde_helpers::{deserialize_bool, deserialize_u16}; use serde::{Deserialize, Serialize}; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -139,3 +139,49 @@ pub struct DhcpClient { #[serde(rename = "use-peer-ntp", deserialize_with = "deserialize_bool")] pub use_peer_ntp: bool, } + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Route { + #[serde(rename = ".id")] + pub id: String, + pub comment: Option, + #[serde(default, deserialize_with = "deserialize_bool")] + pub disabled: bool, + pub distance: String, + #[serde(rename = "dst-address")] + pub dst_address: String, + #[serde(deserialize_with = "deserialize_bool")] + pub dynamic: bool, + #[serde(default, deserialize_with = "deserialize_bool")] + pub ecmp: bool, + pub gateway: String, + #[serde(rename = "hw-offloaded", deserialize_with = "deserialize_bool")] + pub hw_offloaded: bool, + #[serde(rename = "immediate-gw")] + pub immediate_gw: String, + #[serde(deserialize_with = "deserialize_bool")] + pub inactive: bool, + #[serde(rename = "pref-src")] + pub pref_src: Option, + #[serde(rename = "routing-table")] + pub routing_table: String, + #[serde(deserialize_with = "deserialize_u16")] + pub scope: u16, + #[serde(default, rename = "static", deserialize_with = "deserialize_bool")] + pub static_field: bool, + #[serde(rename = "suppress-hw-offload", deserialize_with = "deserialize_bool")] + pub suppress_hw_offload: bool, + #[serde( + default, + rename = "target-scope", + deserialize_with = "deserialize_bool" + )] + pub target_scope: bool, + #[serde(default, deserialize_with = "deserialize_bool")] + pub active: bool, + #[serde(default, deserialize_with = "deserialize_bool")] + pub connect: bool, + #[serde(rename = "local-address")] + pub local_address: Option, +} diff --git a/src/lib.rs b/src/lib.rs index dfe90cb..e78efd3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,9 @@ mod client; +mod serde_helpers; + pub mod interface; pub mod ip; -mod serde_helpers; +pub mod routing; pub mod system; pub use client::*; diff --git a/src/routing/mod.rs b/src/routing/mod.rs new file mode 100644 index 0000000..68b127a --- /dev/null +++ b/src/routing/mod.rs @@ -0,0 +1,4 @@ +pub mod rule; +mod types; + +const BASE: &str = "rest/routing"; diff --git a/src/routing/rule.rs b/src/routing/rule.rs new file mode 100644 index 0000000..70ea71e --- /dev/null +++ b/src/routing/rule.rs @@ -0,0 +1,52 @@ +use serde::{Deserialize, Serialize}; + +use crate::{Client, ClientError}; + +pub use crate::routing::types::Rule; + +/// List all routing rules +pub async fn list(client: &mut Client) -> Result, ClientError> { + let url = format!("{}/rule", super::BASE); + + client.execute_get::>(&url).await +} + +/// Get a specific routing rule +pub async fn get(client: &mut Client, id: &str) -> Result { + let url = format!("{}/rule/{}", super::BASE, id); + + client.execute_get::(&url).await +} + +// TODO(ishan): Figure out a smarter way to implement these common operations +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct RuleInput { + pub numbers: String, +} + +/// Disable a rule +pub async fn disable(client: &mut Client, input: RuleInput) -> Result<(), ClientError> { + let url = format!("{}/rule/disable", super::BASE); + + client + .execute_post_with_no_response::(&url, input) + .await +} + +/// Enable a rule +pub async fn enable(client: &mut Client, input: RuleInput) -> Result<(), ClientError> { + let url = format!("{}/rule/enable", super::BASE); + + client + .execute_post_with_no_response::(&url, input) + .await +} + +/// Remove a rule +pub async fn remove(client: &mut Client, input: RuleInput) -> Result<(), ClientError> { + let url = format!("{}/rule/remove", super::BASE); + + client + .execute_post_with_no_response::(&url, input) + .await +} diff --git a/src/routing/types.rs b/src/routing/types.rs new file mode 100644 index 0000000..4864aa6 --- /dev/null +++ b/src/routing/types.rs @@ -0,0 +1,19 @@ +use crate::serde_helpers::deserialize_bool; +use serde::{Deserialize, Serialize}; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Rule { + #[serde(rename = ".id")] + pub id: String, + #[serde(rename = ".nextid")] + pub nextid: Option, + pub action: String, + #[serde(default, deserialize_with = "deserialize_bool")] + pub disabled: bool, + #[serde(default, deserialize_with = "deserialize_bool")] + pub inactive: bool, + #[serde(rename = "src-address")] + pub src_address: String, + pub table: String, +} diff --git a/src/serde_helpers/mod.rs b/src/serde_helpers/mod.rs index a1bf9f7..c6e2439 100644 --- a/src/serde_helpers/mod.rs +++ b/src/serde_helpers/mod.rs @@ -52,6 +52,7 @@ where } } +#[allow(unused)] pub fn maybe_deserialize_u64<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, diff --git a/src/system/health.rs b/src/system/health.rs index 84d1b29..09d98e6 100644 --- a/src/system/health.rs +++ b/src/system/health.rs @@ -8,7 +8,7 @@ pub async fn health(client: &mut Client) -> Result, ClientError> { client.execute_get::>(&url).await } -/// voltage can be used to get device's voltag reading +/// voltage can be used to get device's voltage reading pub async fn voltage(client: &mut Client) -> Result { let url = format!("{}/health/voltage", super::BASE); diff --git a/tests/ip_test.rs b/tests/ip_test.rs index f123182..82a28e9 100644 --- a/tests/ip_test.rs +++ b/tests/ip_test.rs @@ -182,3 +182,31 @@ async fn release_dhcp_lease() -> Result<(), ClientError> { Ok(()) } + +#[tokio::test] +async fn list_routes() -> Result<(), ClientError> { + let base = Url::parse("https://10.0.10.1")?; + let mut client = Client::new(base, "admin".to_string(), "ifd783far".to_string(), true) + .expect("error in creating client"); + + let response = mikrotik::ip::route::list(&mut client).await?; + + println!("{:?}", response); + + Ok(()) +} + +#[tokio::test] +async fn get_route() -> Result<(), ClientError> { + let base = Url::parse("https://10.0.10.1")?; + let mut client = Client::new(base, "admin".to_string(), "ifd783far".to_string(), true) + .expect("error in creating client"); + + let response = mikrotik::ip::route::list(&mut client).await?; + + let response = mikrotik::ip::route::get(&mut client, &response[0].id).await?; + + println!("{:?}", response); + + Ok(()) +} diff --git a/tests/routing_test.rs b/tests/routing_test.rs new file mode 100644 index 0000000..82a28e9 --- /dev/null +++ b/tests/routing_test.rs @@ -0,0 +1,212 @@ +use mikrotik::{ip::dhcp_client::DhcpClientInput, Client, ClientError}; +use reqwest::Url; + +#[tokio::test] +async fn list_dhcp_servers() -> Result<(), ClientError> { + let base = Url::parse("https://10.0.10.1")?; + let mut client = Client::new(base, "admin".to_string(), "ifd783far".to_string(), true) + .expect("error in creating client"); + + let response = mikrotik::ip::dhcp_server::list(&mut client).await?; + + println!("{:?}", response); + + Ok(()) +} + +#[tokio::test] +async fn get_dhcp_server() -> Result<(), ClientError> { + let base = Url::parse("https://10.0.10.1")?; + let mut client = Client::new(base, "admin".to_string(), "ifd783far".to_string(), true) + .expect("error in creating client"); + + let response = mikrotik::ip::dhcp_server::get(&mut client, "vlan-150").await?; + + println!("{:?}", response); + + Ok(()) +} + +#[tokio::test] +async fn list_network() -> Result<(), ClientError> { + let base = Url::parse("https://10.0.10.1")?; + let mut client = Client::new(base, "admin".to_string(), "ifd783far".to_string(), true) + .expect("error in creating client"); + + let response = mikrotik::ip::dhcp_server::list_network(&mut client).await?; + + println!("{:?}", response); + + Ok(()) +} + +#[tokio::test] +async fn get_network() -> Result<(), ClientError> { + let base = Url::parse("https://10.0.10.1")?; + let mut client = Client::new(base, "admin".to_string(), "ifd783far".to_string(), true) + .expect("error in creating client"); + + let response = mikrotik::ip::dhcp_server::list_network(&mut client).await?; + + let response = mikrotik::ip::dhcp_server::get_network(&mut client, &response[0].id).await?; + + println!("{:?}", response); + + Ok(()) +} + +#[tokio::test] +async fn list_leases() -> Result<(), ClientError> { + let base = Url::parse("https://10.0.10.1")?; + let mut client = Client::new(base, "admin".to_string(), "ifd783far".to_string(), true) + .expect("error in creating client"); + + let response = mikrotik::ip::dhcp_server::list_leases(&mut client).await?; + + println!("{:?}", response); + + Ok(()) +} + +#[tokio::test] +async fn get_lease() -> Result<(), ClientError> { + let base = Url::parse("https://10.0.10.1")?; + let mut client = Client::new(base, "admin".to_string(), "ifd783far".to_string(), true) + .expect("error in creating client"); + + let response = mikrotik::ip::dhcp_server::list_leases(&mut client).await?; + + let response = mikrotik::ip::dhcp_server::get_lease(&mut client, &response[0].id).await?; + + println!("{:?}", response); + + Ok(()) +} + +#[tokio::test] +async fn list_address() -> Result<(), ClientError> { + let base = Url::parse("https://10.0.10.1")?; + let mut client = Client::new(base, "admin".to_string(), "ifd783far".to_string(), true) + .expect("error in creating client"); + + let response = mikrotik::ip::address::list(&mut client).await?; + + println!("{:?}", response); + + Ok(()) +} + +#[tokio::test] +async fn get_address() -> Result<(), ClientError> { + let base = Url::parse("https://10.0.10.1")?; + let mut client = Client::new(base, "admin".to_string(), "ifd783far".to_string(), true) + .expect("error in creating client"); + + let response = mikrotik::ip::address::list(&mut client).await?; + + let response = mikrotik::ip::address::get(&mut client, &response[0].id).await?; + + println!("{:?}", response); + + Ok(()) +} + +#[tokio::test] +async fn list_dhcp_client() -> Result<(), ClientError> { + let base = Url::parse("https://10.0.10.1")?; + let mut client = Client::new(base, "admin".to_string(), "ifd783far".to_string(), true) + .expect("error in creating client"); + + let response = mikrotik::ip::dhcp_client::list(&mut client).await?; + + println!("{:?}", response); + + Ok(()) +} + +#[tokio::test] +async fn get_dhcp_client() -> Result<(), ClientError> { + let base = Url::parse("https://10.0.10.1")?; + let mut client = Client::new(base, "admin".to_string(), "ifd783far".to_string(), true) + .expect("error in creating client"); + + let response = mikrotik::ip::dhcp_client::list(&mut client).await?; + + let response = mikrotik::ip::dhcp_client::get(&mut client, &response[0].id).await?; + + println!("{:?}", response); + + Ok(()) +} + +#[tokio::test] +async fn renew_dhcp_lease() -> Result<(), ClientError> { + let base = Url::parse("https://10.0.10.1")?; + let mut client = Client::new(base, "admin".to_string(), "ifd783far".to_string(), true) + .expect("error in creating client"); + + let response = mikrotik::ip::dhcp_client::list(&mut client).await?; + + let response = mikrotik::ip::dhcp_client::renew( + &mut client, + DhcpClientInput { + numbers: response[0].id.clone(), + }, + ) + .await?; + + println!("{:?}", response); + + Ok(()) +} + +#[tokio::test] +async fn release_dhcp_lease() -> Result<(), ClientError> { + let base = Url::parse("https://10.0.10.1")?; + let mut client = Client::new(base, "admin".to_string(), "ifd783far".to_string(), true) + .expect("error in creating client"); + + let response = mikrotik::ip::dhcp_client::list(&mut client).await?; + + println!("{:?}", response); + + let response = mikrotik::ip::dhcp_client::release( + &mut client, + DhcpClientInput { + numbers: response[0].id.clone(), + }, + ) + .await?; + + println!("{:?}", response); + + Ok(()) +} + +#[tokio::test] +async fn list_routes() -> Result<(), ClientError> { + let base = Url::parse("https://10.0.10.1")?; + let mut client = Client::new(base, "admin".to_string(), "ifd783far".to_string(), true) + .expect("error in creating client"); + + let response = mikrotik::ip::route::list(&mut client).await?; + + println!("{:?}", response); + + Ok(()) +} + +#[tokio::test] +async fn get_route() -> Result<(), ClientError> { + let base = Url::parse("https://10.0.10.1")?; + let mut client = Client::new(base, "admin".to_string(), "ifd783far".to_string(), true) + .expect("error in creating client"); + + let response = mikrotik::ip::route::list(&mut client).await?; + + let response = mikrotik::ip::route::get(&mut client, &response[0].id).await?; + + println!("{:?}", response); + + Ok(()) +}