diff --git a/Cargo.lock b/Cargo.lock index c87ad01..a6d0296 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -543,7 +543,7 @@ dependencies = [ [[package]] name = "netbox2netshot" -version = "0.1.2" +version = "0.1.3" dependencies = [ "anyhow", "ctor", @@ -602,9 +602,9 @@ checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" [[package]] name = "openssl" -version = "0.10.33" +version = "0.10.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a61075b62a23fef5a29815de7536d940aa35ce96d18ce0cc5076272db678a577" +checksum = "6d7830286ad6a3973c0f1d9b73738f69c76b739301d0229c4b96501695cbe4c8" dependencies = [ "bitflags", "cfg-if", @@ -622,9 +622,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openssl-sys" -version = "0.9.61" +version = "0.9.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "313752393519e876837e09e1fa183ddef0be7735868dced3196f4472d536277f" +checksum = "fa52160d45fa2e7608d504b7c3a3355afed615e6d8b627a74458634ba21b69bd" dependencies = [ "autocfg", "cc", diff --git a/Cargo.toml b/Cargo.toml index 59fbe48..0329335 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "netbox2netshot" -version = "0.1.2" +version = "0.1.3" authors = ["Mathieu Poussin "] edition = "2018" description = "Synchronization tool between netbox and netshot" diff --git a/README.md b/README.md index a25a4ac..70528f8 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,7 @@ cargo install netbox2netshot Most parameters can be set either via command line arguments or environment variables ```bash -USAGE: - netbox2netshot [FLAGS] [OPTIONS] --netbox-token --netbox-url --netshot-url +netbox2netshot [FLAGS] [OPTIONS] --netbox-url --netshot-domain-id --netshot-token --netshot-url FLAGS: -c, --check Check mode, will not push any change to Netshot @@ -34,12 +33,16 @@ OPTIONS: --netbox-devices-filter The querystring to use to select the devices from netbox [env: NETBOX_DEVICES_FILTER=] [default: ] - --netbox-token The Netbox token [env: NETBOX_TOKEN] [default: ] + --netbox-token The Netbox token [env: NETBOX_TOKEN] [default: ] --netbox-url The Netbox API URL [env: NETBOX_URL=] - --netshot-token The Netshot token [env: NETSHOT_TOKEN] - --netshot-url The Netshot API URL [env: NETSHOT_URL=] + --netbox-vms-filter + The querystring to use to select the VM from netbox [env: NETBOX_VMS_FILTER=] + --netshot-domain-id The domain ID to use when importing a new device [env: NETSHOT_DOMAIN_ID=] + + --netshot-token The Netshot token [env: NETSHOT_TOKEN] + --netshot-url The Netshot API URL [env: NETSHOT_URL=] ``` The query-string format need to be like this (url query string without the `?`): diff --git a/src/main.rs b/src/main.rs index 4b45e90..d166957 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use anyhow::{Error, Result}; -use flexi_logger::{Duplicate, Logger, LogTarget}; +use flexi_logger::{Duplicate, LogTarget, Logger}; use structopt::StructOpt; use rest::{netbox, netshot}; @@ -47,6 +47,13 @@ struct Opt { )] netbox_devices_filter: String, + #[structopt( + long, + help = "The querystring to use to select the VM from netbox", + env + )] + netbox_vms_filter: Option, + #[structopt(short, long, help = "Check mode, will not push any change to Netshot")] check: bool, } @@ -86,12 +93,21 @@ async fn main() -> Result<(), Error> { .collect(); log::info!("Getting devices list from Netbox"); - let netbox_devices = netbox_client + let mut netbox_devices = netbox_client .get_devices(&opt.netbox_devices_filter) .await?; + if opt.netbox_vms_filter.is_some() { + log::info!("Getting VMS list rom Netbox"); + let mut vms = netbox_client + .get_vms(&opt.netbox_vms_filter.unwrap()) + .await?; + log::debug!("Merging VMs and Devices lists"); + netbox_devices.append(&mut vms); + } + log::debug!("Building netbox devices hashmap"); - let netbox_hashmap: HashMap<_, _> = netbox_devices + let mut netbox_hashmap: HashMap<_, _> = netbox_devices .into_iter() .filter_map(|device| match device.primary_ip4 { Some(x) => Some(( @@ -144,7 +160,7 @@ async fn main() -> Result<(), Error> { #[cfg(test)] mod tests { - use flexi_logger::{Duplicate, Logger, LogTarget}; + use flexi_logger::{Duplicate, LogTarget, Logger}; #[ctor::ctor] fn enable_logging() { diff --git a/src/rest/netbox.rs b/src/rest/netbox.rs index 60ba922..ceace9f 100644 --- a/src/rest/netbox.rs +++ b/src/rest/netbox.rs @@ -2,12 +2,13 @@ use crate::common::APP_USER_AGENT; use anyhow::{anyhow, Error, Result}; use reqwest::header::{HeaderMap, HeaderValue}; use serde::{Deserialize, Serialize}; -use std::collections::HashMap; const API_LIMIT: u32 = 100; const PATH_PING: &str = "/api/dcim/devices/?name=netbox2netshot-ping"; const PATH_DCIM_DEVICES: &str = "/api/dcim/devices/"; +const PATH_VIRT_VM: &str = "/api/virtualization/virtual-machines/"; +/// The Netbox client #[derive(Debug)] pub struct NetboxClient { pub url: String, @@ -94,13 +95,14 @@ impl NetboxClient { /// Get a single device page pub async fn get_devices_page( &self, + path: &str, query_string: &String, limit: u32, offset: u32, ) -> Result { let url = format!( "{}{}?limit={}&offset={}&{}", - self.url, PATH_DCIM_DEVICES, limit, offset, query_string + self.url, path, limit, offset, query_string ); let page: NetboxDCIMDeviceList = self.client.get(url).send().await?.json().await?; Ok(page) @@ -113,7 +115,7 @@ impl NetboxClient { loop { let mut response = self - .get_devices_page(&query_string, API_LIMIT, offset) + .get_devices_page(PATH_DCIM_DEVICES, &query_string, API_LIMIT, offset) .await?; devices.append(&mut response.results); @@ -138,6 +140,39 @@ impl NetboxClient { log::info!("Fetched {} devices from Netbox", devices.len()); Ok(devices) } + + /// Get the VMs as device using the given filter + pub async fn get_vms(&self, query_string: &String) -> Result, Error> { + let mut devices: Vec = Vec::new(); + let mut offset = 0; + + loop { + let mut response = self + .get_devices_page(PATH_VIRT_VM, &query_string, API_LIMIT, offset) + .await?; + + devices.append(&mut response.results); + + let pages_count = response.count / API_LIMIT; + log::debug!( + "Got {} VM devices on the {} matches (page {}/{})", + devices.len(), + response.count, + (offset / API_LIMIT), + pages_count + ); + + match response.next { + Some(x) => { + offset = extract_offset(&x)?; + } + None => break, + } + } + + log::info!("Fetched {} VM devices from Netbox", devices.len()); + Ok(devices) + } } #[cfg(test)]