From f2011fd486d555d54132ea4255e369ca6502b279 Mon Sep 17 00:00:00 2001 From: ByteOtter Date: Tue, 23 Apr 2024 14:34:09 +0200 Subject: [PATCH 01/17] implement skeleten translation function --- src/configuration/config_parser.rs | 6 +++--- src/publisher/api_client.rs | 24 ++++++++++++++++++---- src/publisher/publisher.rs | 25 ++++++++++++++++------ src/publisher/translator.rs | 33 +++++++++++++++++++++++++++--- 4 files changed, 72 insertions(+), 16 deletions(-) diff --git a/src/configuration/config_parser.rs b/src/configuration/config_parser.rs index 1834bab..11ba448 100644 --- a/src/configuration/config_parser.rs +++ b/src/configuration/config_parser.rs @@ -59,13 +59,13 @@ use super::config_exceptions::{self, *}; /// # Members /// - netbox: `NetBoxConfig` - Configuration parameters for the NetBox connection. /// - system: `SystemConfig` - Parameters abouth the system. -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct ConfigData { pub netbox: NetboxConfig, pub system: SystemConfig, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct NetboxConfig { pub netbox_api_token: String, pub netbox_uri: String, @@ -94,7 +94,7 @@ pub struct NetboxConfig { /// * tenant: `Option` - ID of tenant this device belongs to. (e.g: team or individual) /// * rack: `Option` - ID of the rack this device is located in. /// * position: `Option` - Position of the device within a rack if any. -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct SystemConfig { pub name: String, pub site_id: Option, diff --git a/src/publisher/api_client.rs b/src/publisher/api_client.rs index 6b080e3..e8d5edc 100644 --- a/src/publisher/api_client.rs +++ b/src/publisher/api_client.rs @@ -14,7 +14,10 @@ use thanix_client::{ util::ThanixClient, }; -use super::{publisher, publisher_exceptions}; +use super::{ + publisher, + publisher_exceptions::{self, NetBoxApiError}, +}; /// Tests connection to the NetBox API. /// @@ -50,7 +53,18 @@ pub fn test_connection(client: &ThanixClient) -> Result<(), publisher_exceptions } } -pub fn create_device(client: &ThanixClient, payload: &WritableDeviceWithConfigContextRequest) { +/// Send request to create a new device in NetBox. +/// +/// # Parameters +/// +/// * client: `&ThanixClient` - The `ThanixClient` instance to use for communication. +/// * payload: `&WritableDeviceWithConfigContextRequest` - The information about the device serving +/// as a request body. +/// +pub fn create_device( + client: &ThanixClient, + payload: &WritableDeviceWithConfigContextRequest, +) -> Result { println!("Creating Device in NetBox..."); match dcim_devices_create(client, payload.clone()) { @@ -59,8 +73,10 @@ pub fn create_device(client: &ThanixClient, payload: &WritableDeviceWithConfigCo DcimDevicesCreateResponse::Http201(created_device) => { // TODO println!( - "\x1b[32m[success] Device creation successful!\x1b[0m \n+++ Your machine can be found under the ID {}. +++", created_device.id - ); + "\x1b[32m[success]\x1b[0m Device creation successful! New Device-ID {}.", + created_device.id + ); + return Ok(created_device.id); } DcimDevicesCreateResponse::Other(other_response) => { // TODO diff --git a/src/publisher/publisher.rs b/src/publisher/publisher.rs index 44c5248..71a5afc 100644 --- a/src/publisher/publisher.rs +++ b/src/publisher/publisher.rs @@ -10,12 +10,12 @@ use std::process; /// TODO: 1. Implement Creation/update logic 2. Denest by splitting query logic off 3. Do not panic upon request fail use thanix_client::{ paths::{ - self, DcimDevicesCreateResponse, DcimDevicesListQuery, DcimDevicesListResponse, + self, DcimDevicesListQuery, DcimDevicesListResponse, VirtualizationVirtualMachinesListQuery, VirtualizationVirtualMachinesListResponse, }, types::{ - DeviceWithConfigContext, VirtualMachineWithConfigContext, - WritableDeviceWithConfigContextRequest, + self, DeviceWithConfigContext, VirtualMachineWithConfigContext, + WritableDeviceWithConfigContextRequest, WritableInterfaceRequest, }, util::ThanixClient, }; @@ -80,15 +80,28 @@ pub fn register_machine( if machine.dmi_information.system_information.is_virtual { todo!("Virtual machine creation not yet implemented!") // TODO: VM Creation / Update } else { - let payload: WritableDeviceWithConfigContextRequest = - translator::information_to_device(&client, &machine, config_data); + let device_payload: WritableDeviceWithConfigContextRequest = + translator::information_to_device(&client, &machine, config_data.clone()); match search_for_matches(&machine, &nb_devices) { Some(device_id) => { todo!("Device update not yet implemented.") // TODO Implement machine update } None => { - create_device(client, &payload); + let device_id = match create_device(client, &device_payload) { + Ok(id) => id, + Err(e) => { + println!("{}", e); + process::exit(1); + } + }; + let interface_payload: WritableInterfaceRequest = + translator::information_to_interface( + &client, + &machine, + config_data.clone(), + &device_id, + ); } } } diff --git a/src/publisher/translator.rs b/src/publisher/translator.rs index 49dcb22..d799c1f 100644 --- a/src/publisher/translator.rs +++ b/src/publisher/translator.rs @@ -5,14 +5,13 @@ //! TODO: //! - Identify primary IPv4 or IPv6 using the primary_network_interface field from `ConfigData`. use core::net::IpAddr; -use std::net::Ipv4Addr; use std::process; use std::str::FromStr; use thanix_client::paths::{ self, DcimPlatformsListQuery, DcimSitesListQuery, IpamIpAddressesListQuery, }; use thanix_client::types::{ - IPAddress, Platform, Site, WritableDeviceWithConfigContextRequest, + IPAddress, Platform, Site, WritableDeviceWithConfigContextRequest, WritableInterfaceRequest, WritableVirtualMachineWithConfigContextRequest, }; use thanix_client::util::ThanixClient; @@ -115,6 +114,7 @@ pub fn information_to_device( // payload.virtual_chassis = todo!(); // payload.vc_position = todo!(); // payload.vc_priority = todo!(); + payload.tenant = config_data.system.tenant; payload.location = config_data.system.location; payload @@ -135,11 +135,38 @@ pub fn information_to_device( pub fn information_to_vm( state: &ThanixClient, machine: &Machine, - config_data: &ConfigData, + config_data: ConfigData, ) -> WritableVirtualMachineWithConfigContextRequest { todo!("Translation of collected information to VM not implemented yet!") } +/// Translate gathered information into a `WritableInterfaceRequest` payload. +/// +/// # Parameters +/// +/// * state: `&ThanixClient` - The client instance to be used for communication. +/// * machine: `&Machine` - The collectedd information about the device or machine. +/// * config_data: `ConfigData` - The configuration data. +/// * device_id: `&i64` - The ID of the device that this interface belongs to. +/// +/// # Returns +/// +/// * payload: `WritableInterfaceRequest` - Payload for creating an interface. +pub fn information_to_interface( + state: &ThanixClient, + machine: &Machine, + config_data: ConfigData, + device_id: &i64, +) -> WritableInterfaceRequest { + println!("Creating Network Interface..."); + + let mut payload: WritableInterfaceRequest = WritableInterfaceRequest::default(); + + payload.device = device_id.to_owned(); + + payload +} + /// Returns the ID of the platform this machine uses. /// /// # Parameters From fb29724e782c2bc078e0de45d9271da16e0f79ef Mon Sep 17 00:00:00 2001 From: ByteOtter Date: Tue, 23 Apr 2024 15:05:44 +0200 Subject: [PATCH 02/17] implement API request logic --- src/publisher/api_client.rs | 49 ++++++++++++++++++++++++++++---- src/publisher/publisher.rs | 12 +++++++- src/publisher/translator.rs | 56 +++++++++++++++++++++++++------------ 3 files changed, 93 insertions(+), 24 deletions(-) diff --git a/src/publisher/api_client.rs b/src/publisher/api_client.rs index e8d5edc..c877d7b 100644 --- a/src/publisher/api_client.rs +++ b/src/publisher/api_client.rs @@ -9,8 +9,8 @@ extern crate thanix_client; use reqwest::{blocking::Client, Error as ReqwestError}; use thanix_client::{ - paths::{dcim_devices_create, DcimDevicesCreateResponse}, - types::WritableDeviceWithConfigContextRequest, + paths::{dcim_devices_create, dcim_interfaces_create, DcimDevicesCreateResponse}, + types::{WritableDeviceWithConfigContextRequest, WritableInterfaceRequest}, util::ThanixClient, }; @@ -71,12 +71,11 @@ pub fn create_device( Ok(response) => { match response { DcimDevicesCreateResponse::Http201(created_device) => { - // TODO println!( - "\x1b[32m[success]\x1b[0m Device creation successful! New Device-ID {}.", + "\x1b[32m[success]\x1b[0m Device creation successful! New Device-ID: '{}'.", created_device.id ); - return Ok(created_device.id); + Ok(created_device.id) } DcimDevicesCreateResponse::Other(other_response) => { // TODO @@ -92,3 +91,43 @@ pub fn create_device( } } } + +/// Create an interface object in NetBox. +/// +/// # Parameters +/// +/// * client: `&ThanixClient` - The client instance necessary for communication. +/// * payload: `&WritableInterfaceRequest` - The payload for the API request. +/// +/// # Returns +/// +/// * `Ok(i64)` - The ID of the interface object. +/// * `Err(NetBoxApiError)` - Error will be passed back to `publisher`. +/// +/// # Panics +/// +/// Panics if NetBox become unreachable. +pub fn create_interface( + client: &ThanixClient, + payload: WritableInterfaceRequest, +) -> Result { + println!("Creating interface in NetBox..."); + + match dcim_interfaces_create(client, payload) { + Ok(response) => { + match response { + thanix_client::paths::DcimInterfacesCreateResponse::Http201(result) => { + println!("\x1b[32m[success]\x1b[0m Interface created successfully. New Interface ID: {}", result.id); + Ok(result.id) + } + thanix_client::paths::DcimInterfacesCreateResponse::Other(other_response) => { + let exc: NetBoxApiError = NetBoxApiError::Other(other_response.text().unwrap()); + Err(exc) + } + } + } + Err(e) => { + panic!("[FATAL] NetBox connection failed. {}", e); + } + } +} diff --git a/src/publisher/publisher.rs b/src/publisher/publisher.rs index 71a5afc..d649096 100644 --- a/src/publisher/publisher.rs +++ b/src/publisher/publisher.rs @@ -23,7 +23,7 @@ use thanix_client::{ use crate::{ configuration::config_parser::ConfigData, publisher::{ - api_client::{create_device, test_connection}, + api_client::{create_device, create_interface, test_connection}, translator, }, Machine, @@ -88,6 +88,7 @@ pub fn register_machine( todo!("Device update not yet implemented.") // TODO Implement machine update } None => { + // Creates Device. Will need to be updated after IP Adress creation. let device_id = match create_device(client, &device_payload) { Ok(id) => id, Err(e) => { @@ -95,6 +96,7 @@ pub fn register_machine( process::exit(1); } }; + let interface_payload: WritableInterfaceRequest = translator::information_to_interface( &client, @@ -102,6 +104,14 @@ pub fn register_machine( config_data.clone(), &device_id, ); + + let interface_id = match create_interface(client, interface_payload) { + Ok(id) => id, + Err(e) => { + println!("{}", e); + process::exit(1); + } + }; } } } diff --git a/src/publisher/translator.rs b/src/publisher/translator.rs index d799c1f..4b59485 100644 --- a/src/publisher/translator.rs +++ b/src/publisher/translator.rs @@ -163,6 +163,26 @@ pub fn information_to_interface( let mut payload: WritableInterfaceRequest = WritableInterfaceRequest::default(); payload.device = device_id.to_owned(); + // payload.vdcs = todo!(); + // payload.module = todo!(); + payload.name = match config_data.system.primary_network_interface { + Some(interface_name) => interface_name, + None => String::from("Nazara Generic Network Interface"), + }; + // payload.label = todo!(); + // payload.r#type = todo!(); + // payload.parent = todo!(); + // payload.bridge = todo!(); + // payload.lag = todo!(); + // payload.mtu = todo!(); + payload.mac_address = todo!("Search for nwi specified as primary, get mac address."); + payload.speed = todo!(); + payload.description = String::from("This interface was automatically created by Nazara."); + payload.mode = todo!(); + payload.rf_role = todo!(); + payload.rf_channel = todo!(); + payload.poe_mode = todo!(); + payload.poe_type = todo!(); payload } @@ -366,24 +386,24 @@ fn get_site_id(state: &ThanixClient, config_data: &ConfigData) -> Option { None } -// Create a new IP-Adress object in NetBox if the collected IP Adresses for the preferred interface -// do not exist yet. -// -// # Parameters -// -// * state: `&ThanixClient` - The `ThanixClient` object used for API connection. -// * config_data: `&ConfigData` - The config information which identifies the preferred network -// interface. -// * sys_info: `&Machine` - Collected system information which contains the IP Adresses to create. -// -// # Returns -// -// Return `Ok(i64)` containing the ID of the created IP Adress entry if the creation was -// successful. Otherwise, return `NetBoxApiError`. -// -// # Panics -// -// This function panics if the connection to NetBox fails. +/// Create a new IP-Adress object in NetBox if the collected IP Adresses for the preferred interface +/// do not exist yet. +/// +/// # Parameters +/// +/// * state: `&ThanixClient` - The `ThanixClient` object used for API connection. +/// * config_data: `&ConfigData` - The config information which identifies the preferred network +/// interface. +/// * sys_info: `&Machine` - Collected system information which contains the IP Adresses to create. +/// +/// # Returns +/// +/// Return `Ok(i64)` containing the ID of the created IP Adress entry if the creation was +/// successful. Otherwise, return `NetBoxApiError`. +/// +/// # Panics +/// +/// This function panics if the connection to NetBox fails. fn create_ip_adresses( state: &ThanixClient, config_data: &ConfigData, From 90e77c1f1264d086258867102a6a9f0a4f2190f5 Mon Sep 17 00:00:00 2001 From: ByteOtter Date: Thu, 25 Apr 2024 12:23:50 +0200 Subject: [PATCH 03/17] add interface creation logic v1 --- src/publisher/api_client.rs | 13 +++++--- src/publisher/publisher.rs | 2 +- src/publisher/translator.rs | 60 ++++++++++++++++++++++++++++++------- 3 files changed, 59 insertions(+), 16 deletions(-) diff --git a/src/publisher/api_client.rs b/src/publisher/api_client.rs index c877d7b..074809a 100644 --- a/src/publisher/api_client.rs +++ b/src/publisher/api_client.rs @@ -9,7 +9,10 @@ extern crate thanix_client; use reqwest::{blocking::Client, Error as ReqwestError}; use thanix_client::{ - paths::{dcim_devices_create, dcim_interfaces_create, DcimDevicesCreateResponse}, + paths::{ + dcim_devices_create, dcim_interfaces_create, DcimDevicesCreateResponse, + DcimInterfacesCreateResponse, + }, types::{WritableDeviceWithConfigContextRequest, WritableInterfaceRequest}, util::ThanixClient, }; @@ -65,7 +68,7 @@ pub fn create_device( client: &ThanixClient, payload: &WritableDeviceWithConfigContextRequest, ) -> Result { - println!("Creating Device in NetBox..."); + println!("Creating device in NetBox..."); match dcim_devices_create(client, payload.clone()) { Ok(response) => { @@ -111,7 +114,7 @@ pub fn create_interface( client: &ThanixClient, payload: WritableInterfaceRequest, ) -> Result { - println!("Creating interface in NetBox..."); + println!("Creating network interface in NetBox..."); match dcim_interfaces_create(client, payload) { Ok(response) => { @@ -127,7 +130,9 @@ pub fn create_interface( } } Err(e) => { - panic!("[FATAL] NetBox connection failed. {}", e); + eprintln!("\x1b[33m[warning]\x1b[0m Error while decoding NetBox Response. This is probably still fine and a problem with NetBox.\nError: {}", e); + let exc = NetBoxApiError::Other(e.to_string()); + Err(exc) } } } diff --git a/src/publisher/publisher.rs b/src/publisher/publisher.rs index d649096..c9780df 100644 --- a/src/publisher/publisher.rs +++ b/src/publisher/publisher.rs @@ -108,7 +108,7 @@ pub fn register_machine( let interface_id = match create_interface(client, interface_payload) { Ok(id) => id, Err(e) => { - println!("{}", e); + eprintln!("{}", e); process::exit(1); } }; diff --git a/src/publisher/translator.rs b/src/publisher/translator.rs index 4b59485..6a895a6 100644 --- a/src/publisher/translator.rs +++ b/src/publisher/translator.rs @@ -5,6 +5,7 @@ //! TODO: //! - Identify primary IPv4 or IPv6 using the primary_network_interface field from `ConfigData`. use core::net::IpAddr; +use std::collections::HashMap; use std::process; use std::str::FromStr; use thanix_client::paths::{ @@ -165,24 +166,48 @@ pub fn information_to_interface( payload.device = device_id.to_owned(); // payload.vdcs = todo!(); // payload.module = todo!(); - payload.name = match config_data.system.primary_network_interface { - Some(interface_name) => interface_name, + payload.name = match &config_data.system.primary_network_interface { + Some(interface_name) => interface_name.to_owned(), None => String::from("Nazara Generic Network Interface"), }; // payload.label = todo!(); - // payload.r#type = todo!(); + // FIXME: + payload.r#type = String::from("bridge"); // payload.parent = todo!(); // payload.bridge = todo!(); // payload.lag = todo!(); // payload.mtu = todo!(); - payload.mac_address = todo!("Search for nwi specified as primary, get mac address."); - payload.speed = todo!(); + + // Get the interfce we are looking for as primary, then get its parameters. + // These filter statements can probably be split off into their own function. + payload.mac_address = match &config_data.system.primary_network_interface { + Some(nwi_name) => { + let interface = machine + .network_information + .iter() + .find(|nwi| nwi.name == nwi_name.to_owned()); + interface.map(|nwi| nwi.mac_addr.clone()).flatten() + } + None => None, + }; + payload.speed = match config_data.system.primary_network_interface { + Some(nwi_name) => { + let interface = machine + .network_information + .iter() + .find(|nwi| nwi.name == nwi_name); + interface.map(|nwi| nwi.interface_speed.clone()).flatten() + } + None => None, + }; payload.description = String::from("This interface was automatically created by Nazara."); - payload.mode = todo!(); - payload.rf_role = todo!(); - payload.rf_channel = todo!(); - payload.poe_mode = todo!(); - payload.poe_type = todo!(); + // payload.mode = todo!(); + // payload.rf_role = todo!(); + // payload.rf_channel = todo!(); + // payload.poe_mode = todo!(); + // payload.poe_type = todo!(); + // FIXME: + payload.custom_fields = Some(HashMap::new()); payload } @@ -192,6 +217,14 @@ pub fn information_to_interface( /// # Parameters /// /// * state: `&ThanixClient` - The client required for searching for the platform. +/// +/// # Returns +/// +/// Returns `Some(i64)` if the specified platform exists, else returns `None`. +/// +/// # Aborts +/// +/// If the netBox connection fails, this may terimnate the process. fn get_platform_id(state: &ThanixClient, platform_name: String) -> Option { println!("Searching for id of platform '{}' ... ", platform_name); let platform_list: Vec; @@ -231,13 +264,18 @@ fn get_platform_id(state: &ThanixClient, platform_name: String) -> Option { /// The function will retrieve a list of IPv4 Adresses from NetBox, /// then search this list for the IP Adress Nazara collected. /// -/// The "primary_network_interface" paramter specified in the `nazara_config.toml` +/// The `primary_network_interface` paramter specified in the `nazara_config.toml` /// will be used to specify which adress to search for. /// /// # Parameters /// /// * state: `&ThanixClient` - The client required for making API requests. /// * machine: `&Machine` - The collected machine information. +/// +/// # Returns +/// +/// Returns the ID of the IP address object `i64` if a match has been found. +/// Else returns `None`. fn get_primary_addresses( state: &ThanixClient, machine: &Machine, From e2c2573968d34a6ba3eac703d573b9adde5da41e Mon Sep 17 00:00:00 2001 From: ByteOtter Date: Fri, 26 Apr 2024 13:18:09 +0200 Subject: [PATCH 04/17] add interface configuration to config_parser --- src/configuration/config_parser.rs | 79 ++++++++++++++++++++++++++ src/configuration/config_template.toml | 35 ++++++++++++ 2 files changed, 114 insertions(+) diff --git a/src/configuration/config_parser.rs b/src/configuration/config_parser.rs index 11ba448..9c473c7 100644 --- a/src/configuration/config_parser.rs +++ b/src/configuration/config_parser.rs @@ -63,6 +63,7 @@ use super::config_exceptions::{self, *}; pub struct ConfigData { pub netbox: NetboxConfig, pub system: SystemConfig, + pub nwi: NwiConfig, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -119,6 +120,80 @@ pub struct SystemConfig { pub position: Option, } +/// Information about the system's interface. +/// +/// # Members +/// +/// * name: `String` - The name of the interface. +/// * id: `Option` - The ID of the interface, if it already exists. Mutually exclusive with +/// name. +/// * vdcs: `Option>` +/// * module: `Option` - The module assigned to this interface. +/// * label: `Option` - The phyiscal label of this device if any. +/// * r#type: `String` - The type of the interface (e.g. "bridge") +/// * enabled: `bool` - Whether this device is enabled or not. Default: `True`. +/// * parent: `Option` - ID of the parent interface if applicable. +/// * bridge: `Option` - ID of the bridge device for this interface if applicable. +/// * lag: `Option` +/// * mtu: `Option` +/// * duplex: `Option` +/// * wwn: `Option` +/// * mgmt_only: `bool` - Whether this interface may only be used for management. Default: `False`. +/// * description: `Option` - Optional description of the device. +/// * mode: `Option` - The mode this interface operates in. +/// * rf_role: `Option` +/// * rf_channel: `Option` +/// * poe_mode: `Option` +/// * poe_type: `Option` +/// * rf_channel_frequency: `Option` +/// * rf_channel_width: `Option` +/// * poe_mode: `Option` - The PoE mode of the interface. +/// * poe_type: `Option` +/// * rf_channel_frequency: `Option` +/// * rf_channel_width: `Option` +/// * tx_power: `Option` +/// * untagged_vlans: `Option>` - List of IDs of untagged VLANs assigned to this +/// interface. +/// * tagged_vlans: `Option>` - List of IDs of tagged VLANs assigned to this interface. +/// * mark_connected: `bool` - Whether this interface is connected. Default: `True`. +/// * wireless_lans: `Option>` +/// * vrf: `Option` +/// * custom_fields: `Option>` - Any Custom fields you wish to +/// add in form a of a Key-Value list. +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct NwiConfig { + pub name: Option, + pub id: Option, + pub vdcs: Option>, + pub module: Option, + pub label: Option, + #[serde(rename = "rtype")] + pub r#type: String, // I hate this field name, but that's what the openAPI schema said. + pub enabled: bool, + pub parent: Option, + pub bridge: Option, + pub lag: Option, + pub mtu: Option, + pub duplex: Option, + pub wwn: Option, + pub mgmt_only: bool, + pub description: Option, + pub mode: Option, + pub rf_role: Option, + pub rf_channel: Option, + pub poe_mode: Option, + pub poe_type: Option, + pub rf_channel_frequency: Option, + pub rf_channel_width: Option, + pub tx_power: Option, + pub untagged_vlans: Option>, + pub tagged_vlans: Option>, + pub mark_connected: bool, + pub wireless_lans: Option>, + pub vrf: Option, + pub custom_fields: Option> +} + /// Set up configuration /// /// This function reads the configuration file located at `~/.nazara-config.toml`. If no file can be found, a warning is @@ -410,6 +485,10 @@ impl ConfigData { /// # Returns /// /// * `config: ConfigData` - A `ConfigData` object. + /// + /// # Aborts + /// + /// This function pay terminate the process if it cannot read the cofnig file. fn read_config_file() -> ConfigData { let mut file = match File::open(get_config_dir()) { Ok(file) => file, diff --git a/src/configuration/config_template.toml b/src/configuration/config_template.toml index ca9f028..06c168f 100644 --- a/src/configuration/config_template.toml +++ b/src/configuration/config_template.toml @@ -44,3 +44,38 @@ platform = "x86_64" # collect_cpu_information = true # # collect_network_information = true + +[nwi] +# name = "" # The name of your interface. Must correspond to an interface name present on this device. +# id = 0 # The ID of the desired interface, if it already exists. (Mutually exclusive with name) +# vdcs = [] +# module = 0 +# label = "" # The physical label on the interface or device, if applicable. +# r#type = "" # The type of the interface (e.g "bridge") +enabled = true # Whether this interface is enabled or not. Default: True. +# parent = 0 # ID of the parent interface if applicable. +# bridge = 0 # ID of the bridge device associated with this interface if applicable. +# lag = 0 +# mtu = 0 # 32-bit unsigned interger! +# duplex = "" +# wwn = "" +mgmt_only = false # Whether this interface shall be used for management only. (Default: False) +# description = "" # Optional description of this interface. +# mode = "" # Mode this interface operates in. +# rf_role = "" +# rf_channel = "" +# poe_mode = "" +# poe_type = "" +# rf_channel_frequency = 0.0 # f64 value. +# rf_channel_width = 0.0 # f64 value. +# tx_power = 0 # u8 value +# untagged_vlans = [] # List of IDs of the untagged VLANs associated to this interface. +# tagged_vlans = [] # List of IDs of the tagged VLANs associated to this interfacce. +mark_connected = true # Whether this interface is currently connected or not. +# wireless_lans = [] # List of IDs of the wireless lans associated with this interface. +# vrf = 0 + +[nwi.custom_fields] +# Custom fields of the interface go here. + + From 9c3bd28b56fdb4c69ce7cf557c0aeaab5f3f7cd3 Mon Sep 17 00:00:00 2001 From: ByteOtter Date: Fri, 26 Apr 2024 13:35:39 +0200 Subject: [PATCH 05/17] fix missing nwi parameters in payload --- src/publisher/translator.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/publisher/translator.rs b/src/publisher/translator.rs index 6a895a6..b5b5021 100644 --- a/src/publisher/translator.rs +++ b/src/publisher/translator.rs @@ -172,11 +172,11 @@ pub fn information_to_interface( }; // payload.label = todo!(); // FIXME: - payload.r#type = String::from("bridge"); - // payload.parent = todo!(); - // payload.bridge = todo!(); - // payload.lag = todo!(); - // payload.mtu = todo!(); + payload.r#type = config_data.nwi.r#type; + payload.parent = config_data.nwi.parent; + payload.bridge = config_data.nwi.bridge; + payload.lag = config_data.nwi.lag; + payload.mtu = config_data.nwi.mtu; // Get the interfce we are looking for as primary, then get its parameters. // These filter statements can probably be split off into their own function. @@ -201,13 +201,14 @@ pub fn information_to_interface( None => None, }; payload.description = String::from("This interface was automatically created by Nazara."); - // payload.mode = todo!(); - // payload.rf_role = todo!(); - // payload.rf_channel = todo!(); - // payload.poe_mode = todo!(); - // payload.poe_type = todo!(); - // FIXME: - payload.custom_fields = Some(HashMap::new()); + payload.mode = config_data.nwi.mode.unwrap_or(String::from("")); + payload.rf_role = config_data.nwi.rf_role.unwrap_or(String::from("")); + payload.rf_channel = config_data.nwi.rf_channel.unwrap_or(String::from("")); + payload.poe_mode = config_data.nwi.poe_mode.unwrap_or(String::from("")); + payload.poe_type = config_data.nwi.poe_type.unwrap_or(String::from("")); + payload.custom_fields = config_data.nwi.custom_fields; + payload.mark_connected = config_data.nwi.mark_connected; + payload.enabled = config_data.nwi.enabled; payload } From bcc8126a452b971c3e293b738836ea17dd95f676 Mon Sep 17 00:00:00 2001 From: ByteOtter Date: Fri, 26 Apr 2024 15:35:19 +0200 Subject: [PATCH 06/17] add skeleton logic to create ip address --- src/publisher/api_client.rs | 39 +++++++++++-- src/publisher/publisher.rs | 108 +++++++++++++----------------------- src/publisher/translator.rs | 33 ++++++++++- 3 files changed, 105 insertions(+), 75 deletions(-) diff --git a/src/publisher/api_client.rs b/src/publisher/api_client.rs index 074809a..8af1c25 100644 --- a/src/publisher/api_client.rs +++ b/src/publisher/api_client.rs @@ -10,10 +10,9 @@ extern crate thanix_client; use reqwest::{blocking::Client, Error as ReqwestError}; use thanix_client::{ paths::{ - dcim_devices_create, dcim_interfaces_create, DcimDevicesCreateResponse, - DcimInterfacesCreateResponse, + dcim_devices_create, dcim_interfaces_create, ipam_ip_addresses_create, DcimDevicesCreateResponse, DcimInterfacesCreateResponse }, - types::{WritableDeviceWithConfigContextRequest, WritableInterfaceRequest}, + types::{WritableDeviceWithConfigContextRequest, WritableIPAddressRequest, WritableInterfaceRequest}, util::ThanixClient, }; @@ -120,7 +119,7 @@ pub fn create_interface( Ok(response) => { match response { thanix_client::paths::DcimInterfacesCreateResponse::Http201(result) => { - println!("\x1b[32m[success]\x1b[0m Interface created successfully. New Interface ID: {}", result.id); + println!("\x1b[32m[success]\x1b[0m Interface created successfully. New Interface ID: '{}'", result.id); Ok(result.id) } thanix_client::paths::DcimInterfacesCreateResponse::Other(other_response) => { @@ -130,7 +129,37 @@ pub fn create_interface( } } Err(e) => { - eprintln!("\x1b[33m[warning]\x1b[0m Error while decoding NetBox Response. This is probably still fine and a problem with NetBox.\nError: {}", e); + eprintln!("\x1b[33m[warning]\x1b[0m Error while decoding NetBox Response while creating network interface. This is probably still fine and a problem with NetBox.\nError: {}", e); + let exc = NetBoxApiError::Other(e.to_string()); + Err(exc) + } + } +} + +/// Create new IP adress object. +/// +/// # Parameters +/// +/// * client: `&ThanixClient` - The client instance necessary for communication. +/// * payload: `&` +pub fn create_ip(client: &ThanixClient, payload: WritableIPAddressRequest) -> Result { + println!("Creating new IP address object..."); + + match ipam_ip_addresses_create(client, payload) { + Ok(response) => { + match response { + thanix_client::paths::IpamIpAddressesCreateResponse::Http201(result) => { + println!("\x1b[32m[success]\x1b[0m IP Address created successfully. New IP ID: '{}'", result.id); + Ok(result.id) + } + thanix_client::paths::IpamIpAddressesCreateResponse::Other(other_response) => { + let exc: NetBoxApiError = NetBoxApiError::Other(other_response.text().unwrap()); + Err(exc) + } + } + }, + Err(e) => { + eprintln!("\x1b[33m[warning]\x1b[0m Error while decoding NetBox response while creating IP address. This probably is still fine and a problem with NetBox.\nError: {}", e); let exc = NetBoxApiError::Other(e.to_string()); Err(exc) } diff --git a/src/publisher/publisher.rs b/src/publisher/publisher.rs index c9780df..e7b3098 100644 --- a/src/publisher/publisher.rs +++ b/src/publisher/publisher.rs @@ -14,8 +14,7 @@ use thanix_client::{ VirtualizationVirtualMachinesListQuery, VirtualizationVirtualMachinesListResponse, }, types::{ - self, DeviceWithConfigContext, VirtualMachineWithConfigContext, - WritableDeviceWithConfigContextRequest, WritableInterfaceRequest, + self, DeviceWithConfigContext, VirtualMachineWithConfigContext, WritableDeviceWithConfigContextRequest, WritableIPAddressRequest, WritableInterfaceRequest }, util::ThanixClient, }; @@ -23,7 +22,7 @@ use thanix_client::{ use crate::{ configuration::config_parser::ConfigData, publisher::{ - api_client::{create_device, create_interface, test_connection}, + api_client::{create_device, create_interface, create_ip, test_connection}, translator, }, Machine, @@ -96,81 +95,40 @@ pub fn register_machine( process::exit(1); } }; + let interface_id: i64; + // TODO: Check if interface ID is valid, if not, create new interface. + if config_data.nwi.id.is_none() || !interface_exists(client, &config_data.nwi.id) { + let interface_payload: WritableInterfaceRequest = + translator::information_to_interface( + &client, + &machine, + config_data.clone(), + &device_id, + ); - let interface_payload: WritableInterfaceRequest = - translator::information_to_interface( - &client, - &machine, - config_data.clone(), - &device_id, - ); + interface_id = match create_interface(client, interface_payload) { + Ok(id) => id, + Err(e) => { + eprintln!("{}", e); + process::exit(1); + } + }; + } else { + interface_id = config_data.nwi.id.unwrap(); + } + + let ip_payload: WritableIPAddressRequest = translator::information_to_ip(client, &machine, &config_data, interface_id); - let interface_id = match create_interface(client, interface_payload) { + let ip_id = match create_ip(client, ip_payload) { Ok(id) => id, Err(e) => { eprintln!("{}", e); process::exit(1); } }; - } + } } } - - // check if virtual machine, create or update virtual machine. - // if machine.dmi_information.system_information.is_virtual { - // match search_for_matches(&machine, &nb_devices) { - // Some(vm_id) => { - // match paths::virtualization_virtual_machines_update( - // &client, - // VirtualizationVirtualMachinesUpdateQuery::default(), - // vm_id, - // ) { - // Ok(response) => { - // todo!() - // } - // Err(err) => { - // panic!("{}", err) - // } - // } - // } - // None => { - // match paths::virtualization_virtual_machines_create( - // &client, - // VirtualizationVirtualMachinesCreateQuery::default(), - // ) { - // Ok(response) => { - // todo!() - // } - // Err(err) => { - // panic!("{}", err) - // } - // } - // } - // } - // } else { - // // proper physical machines - // match search_for_matches(&machine, &nb_devices) { - // Some(id) => { - // match paths::dcim_devices_update(&client, DcimDevicesUpdateQuery::default(), id) { - // Ok(response) => { - // todo!() - // } - // Err(err) => { - // panic!("{}", err) - // } - // } - // } - // None => match paths::dcim_devices_create(&client, DcimDevicesCreateQuery::default()) { - // Ok(response) => { - // todo!() - // } - // Err(err) => { - // panic!("{}", err) - // } - // }, - // } - // } - Ok(()) } @@ -182,6 +140,20 @@ fn create_machine(client: &ThanixClient, machine: &Machine) -> Result<(), NetBox Ok(()) } +/// Checks if a given network interface ID corresponds to a interface which already exsists. +/// +/// # Parameter +/// +/// * state: `&ThanixClient` - Client instance to use for communication. +/// * id: `&Option` - ID parameter retrieved from the config file. +/// +/// # Returns +/// +/// True/False depending on whether the interface exists. +fn interface_exists(state: &ThanixClient, id: &Option) -> bool { + todo!("check if interface exists must be implemented!"); +} + /// Get list of machines. /// /// Sends a `GET` request to either the `/dcim/devices` endpoint, in case of physical machines, diff --git a/src/publisher/translator.rs b/src/publisher/translator.rs index b5b5021..6e3dbca 100644 --- a/src/publisher/translator.rs +++ b/src/publisher/translator.rs @@ -12,8 +12,7 @@ use thanix_client::paths::{ self, DcimPlatformsListQuery, DcimSitesListQuery, IpamIpAddressesListQuery, }; use thanix_client::types::{ - IPAddress, Platform, Site, WritableDeviceWithConfigContextRequest, WritableInterfaceRequest, - WritableVirtualMachineWithConfigContextRequest, + IPAddress, Platform, Site, WritableDeviceWithConfigContextRequest, WritableIPAddressRequest, WritableInterfaceRequest, WritableVirtualMachineWithConfigContextRequest }; use thanix_client::util::ThanixClient; @@ -213,6 +212,36 @@ pub fn information_to_interface( payload } +/// Returns the payload necessary to create a new IP address. +/// +/// # Parameters +/// +/// * state: `&ThanixClient` - The client instance necessary for communication. +/// * machine: `&Machine` - Collected machine information. +/// * config_data: `&ConfigData` - Data read from the config file. +/// * interface_id: `i64` - ID of the network interface this IP belongs to. +pub fn information_to_ip(state: &ThanixClient, machine: &Machine, config_data: &ConfigData, interface_id: i64) -> WritableIPAddressRequest { + println!("Creating IP Address payload..."); + + let mut payload: WritableIPAddressRequest = WritableIPAddressRequest::default(); + + // payload.address = todo!(); + // payload.vrf = todo!(); + // payload.tenant = todo!(); + // payload.status = todo!(); + // payload.role = todo!(); + // payload.assigned_object_type = todo!(); + // payload.assigned_object_id = todo!(); + // payload.nat_inside = todo!(); + // payload.dns_name = todo!(); + payload.description = String::from("This Address was automatically created by Nazara."); + payload.comments = String::from("Automatically created by Nazara. Dummy only."); + // payload.tags = todo!(); + payload.custom_fields = Some(HashMap::new()); + + payload +} + /// Returns the ID of the platform this machine uses. /// /// # Parameters From 92d8045acfc646d64872ff110d5bd18cb521f420 Mon Sep 17 00:00:00 2001 From: ByteOtter Date: Mon, 29 Apr 2024 13:50:03 +0200 Subject: [PATCH 07/17] update thanix_client dep --- Cargo.toml | 2 +- src/configuration/config_parser.rs | 4 +-- src/publisher/api_client.rs | 53 ++++++++++++++++-------------- src/publisher/publisher.rs | 10 +++--- src/publisher/translator.rs | 10 ++++-- 5 files changed, 46 insertions(+), 33 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f6deda1..1d791dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ toml = "0.7.6" # This may not work in your environment. You can get your schema by visiting # https://your.netbox-instance.com/api/schema. # The yaml file will be downloaded and you can generate your client by using https://github.com/The-Nazara-Project/Thanix. -thanix_client = "1.0.0" +thanix_client = "1.1.0" # Uncomment this line if you are using a custom thanix client implementation. # Change the path to be relative to this Cargo.toml file. # The package parameter is the name of your client package. This is needed if you assigned a custom name upon creation. diff --git a/src/configuration/config_parser.rs b/src/configuration/config_parser.rs index 9c473c7..eb052b6 100644 --- a/src/configuration/config_parser.rs +++ b/src/configuration/config_parser.rs @@ -191,7 +191,7 @@ pub struct NwiConfig { pub mark_connected: bool, pub wireless_lans: Option>, pub vrf: Option, - pub custom_fields: Option> + pub custom_fields: Option>, } /// Set up configuration @@ -487,7 +487,7 @@ impl ConfigData { /// * `config: ConfigData` - A `ConfigData` object. /// /// # Aborts - /// + /// /// This function pay terminate the process if it cannot read the cofnig file. fn read_config_file() -> ConfigData { let mut file = match File::open(get_config_dir()) { diff --git a/src/publisher/api_client.rs b/src/publisher/api_client.rs index 8af1c25..af8505e 100644 --- a/src/publisher/api_client.rs +++ b/src/publisher/api_client.rs @@ -10,9 +10,12 @@ extern crate thanix_client; use reqwest::{blocking::Client, Error as ReqwestError}; use thanix_client::{ paths::{ - dcim_devices_create, dcim_interfaces_create, ipam_ip_addresses_create, DcimDevicesCreateResponse, DcimInterfacesCreateResponse + dcim_devices_create, dcim_interfaces_create, ipam_ip_addresses_create, + DcimDevicesCreateResponse, DcimInterfacesCreateResponse, + }, + types::{ + WritableDeviceWithConfigContextRequest, WritableIPAddressRequest, WritableInterfaceRequest, }, - types::{WritableDeviceWithConfigContextRequest, WritableIPAddressRequest, WritableInterfaceRequest}, util::ThanixClient, }; @@ -116,18 +119,16 @@ pub fn create_interface( println!("Creating network interface in NetBox..."); match dcim_interfaces_create(client, payload) { - Ok(response) => { - match response { - thanix_client::paths::DcimInterfacesCreateResponse::Http201(result) => { - println!("\x1b[32m[success]\x1b[0m Interface created successfully. New Interface ID: '{}'", result.id); - Ok(result.id) - } - thanix_client::paths::DcimInterfacesCreateResponse::Other(other_response) => { - let exc: NetBoxApiError = NetBoxApiError::Other(other_response.text().unwrap()); - Err(exc) - } + Ok(response) => match response { + thanix_client::paths::DcimInterfacesCreateResponse::Http201(result) => { + println!("\x1b[32m[success]\x1b[0m Interface created successfully. New Interface ID: '{}'", result.id); + Ok(result.id) } - } + thanix_client::paths::DcimInterfacesCreateResponse::Other(other_response) => { + let exc: NetBoxApiError = NetBoxApiError::Other(other_response.text().unwrap()); + Err(exc) + } + }, Err(e) => { eprintln!("\x1b[33m[warning]\x1b[0m Error while decoding NetBox Response while creating network interface. This is probably still fine and a problem with NetBox.\nError: {}", e); let exc = NetBoxApiError::Other(e.to_string()); @@ -142,20 +143,24 @@ pub fn create_interface( /// /// * client: `&ThanixClient` - The client instance necessary for communication. /// * payload: `&` -pub fn create_ip(client: &ThanixClient, payload: WritableIPAddressRequest) -> Result { +pub fn create_ip( + client: &ThanixClient, + payload: WritableIPAddressRequest, +) -> Result { println!("Creating new IP address object..."); match ipam_ip_addresses_create(client, payload) { - Ok(response) => { - match response { - thanix_client::paths::IpamIpAddressesCreateResponse::Http201(result) => { - println!("\x1b[32m[success]\x1b[0m IP Address created successfully. New IP ID: '{}'", result.id); - Ok(result.id) - } - thanix_client::paths::IpamIpAddressesCreateResponse::Other(other_response) => { - let exc: NetBoxApiError = NetBoxApiError::Other(other_response.text().unwrap()); - Err(exc) - } + Ok(response) => match response { + thanix_client::paths::IpamIpAddressesCreateResponse::Http201(result) => { + println!( + "\x1b[32m[success]\x1b[0m IP Address created successfully. New IP ID: '{}'", + result.id + ); + Ok(result.id) + } + thanix_client::paths::IpamIpAddressesCreateResponse::Other(other_response) => { + let exc: NetBoxApiError = NetBoxApiError::Other(other_response.text().unwrap()); + Err(exc) } }, Err(e) => { diff --git a/src/publisher/publisher.rs b/src/publisher/publisher.rs index e7b3098..0371c87 100644 --- a/src/publisher/publisher.rs +++ b/src/publisher/publisher.rs @@ -14,7 +14,8 @@ use thanix_client::{ VirtualizationVirtualMachinesListQuery, VirtualizationVirtualMachinesListResponse, }, types::{ - self, DeviceWithConfigContext, VirtualMachineWithConfigContext, WritableDeviceWithConfigContextRequest, WritableIPAddressRequest, WritableInterfaceRequest + self, DeviceWithConfigContext, VirtualMachineWithConfigContext, + WritableDeviceWithConfigContextRequest, WritableIPAddressRequest, WritableInterfaceRequest, }, util::ThanixClient, }; @@ -117,7 +118,8 @@ pub fn register_machine( interface_id = config_data.nwi.id.unwrap(); } - let ip_payload: WritableIPAddressRequest = translator::information_to_ip(client, &machine, &config_data, interface_id); + let ip_payload: WritableIPAddressRequest = + translator::information_to_ip(client, &machine, &config_data, interface_id); let ip_id = match create_ip(client, ip_payload) { Ok(id) => id, @@ -126,7 +128,7 @@ pub fn register_machine( process::exit(1); } }; - } + } } } Ok(()) @@ -151,7 +153,7 @@ fn create_machine(client: &ThanixClient, machine: &Machine) -> Result<(), NetBox /// /// True/False depending on whether the interface exists. fn interface_exists(state: &ThanixClient, id: &Option) -> bool { - todo!("check if interface exists must be implemented!"); + todo!("check if interface exists must be implemented!"); } /// Get list of machines. diff --git a/src/publisher/translator.rs b/src/publisher/translator.rs index 6e3dbca..7001832 100644 --- a/src/publisher/translator.rs +++ b/src/publisher/translator.rs @@ -12,7 +12,8 @@ use thanix_client::paths::{ self, DcimPlatformsListQuery, DcimSitesListQuery, IpamIpAddressesListQuery, }; use thanix_client::types::{ - IPAddress, Platform, Site, WritableDeviceWithConfigContextRequest, WritableIPAddressRequest, WritableInterfaceRequest, WritableVirtualMachineWithConfigContextRequest + IPAddress, Platform, Site, WritableDeviceWithConfigContextRequest, WritableIPAddressRequest, + WritableInterfaceRequest, WritableVirtualMachineWithConfigContextRequest, }; use thanix_client::util::ThanixClient; @@ -220,7 +221,12 @@ pub fn information_to_interface( /// * machine: `&Machine` - Collected machine information. /// * config_data: `&ConfigData` - Data read from the config file. /// * interface_id: `i64` - ID of the network interface this IP belongs to. -pub fn information_to_ip(state: &ThanixClient, machine: &Machine, config_data: &ConfigData, interface_id: i64) -> WritableIPAddressRequest { +pub fn information_to_ip( + state: &ThanixClient, + machine: &Machine, + config_data: &ConfigData, + interface_id: i64, +) -> WritableIPAddressRequest { println!("Creating IP Address payload..."); let mut payload: WritableIPAddressRequest = WritableIPAddressRequest::default(); From 543bffea54dc5ef4329f64afdfaee6418e421628 Mon Sep 17 00:00:00 2001 From: ByteOtter Date: Thu, 2 May 2024 16:53:11 +0200 Subject: [PATCH 08/17] add contingency search add contigency function to search if the interface was created regardless of parsing errors of the response --- src/publisher/api_client.rs | 50 +++++++++++++++++++++++++++++++------ src/publisher/publisher.rs | 34 ++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 11 deletions(-) diff --git a/src/publisher/api_client.rs b/src/publisher/api_client.rs index af8505e..cfeeea7 100644 --- a/src/publisher/api_client.rs +++ b/src/publisher/api_client.rs @@ -7,22 +7,21 @@ //! deserialize our data. extern crate thanix_client; -use reqwest::{blocking::Client, Error as ReqwestError}; +use reqwest::Error as ReqwestError; use thanix_client::{ paths::{ - dcim_devices_create, dcim_interfaces_create, ipam_ip_addresses_create, - DcimDevicesCreateResponse, DcimInterfacesCreateResponse, + dcim_devices_create, dcim_interfaces_create, dcim_interfaces_list, + ipam_ip_addresses_create, DcimDevicesCreateResponse, DcimInterfacesCreateResponse, + DcimInterfacesListQuery, }, types::{ - WritableDeviceWithConfigContextRequest, WritableIPAddressRequest, WritableInterfaceRequest, + Interface, WritableDeviceWithConfigContextRequest, WritableIPAddressRequest, + WritableInterfaceRequest, }, util::ThanixClient, }; -use super::{ - publisher, - publisher_exceptions::{self, NetBoxApiError}, -}; +use super::publisher_exceptions::{self, NetBoxApiError}; /// Tests connection to the NetBox API. /// @@ -170,3 +169,38 @@ pub fn create_ip( } } } + +pub fn get_interface_by_name( + state: &ThanixClient, + payload: &WritableInterfaceRequest, +) -> Result { + println!("Trying to retrieve interface by name '{}'...", payload.name); + + match dcim_interfaces_list(state, DcimInterfacesListQuery::default()) { + Ok(response) => { + let interface_list: Vec = match response { + thanix_client::paths::DcimInterfacesListResponse::Http200(interfaces) => { + interfaces.results + } + thanix_client::paths::DcimInterfacesListResponse::Other(response) => { + let err: NetBoxApiError = NetBoxApiError::Other(response.text().unwrap()); + return Err(err); + } + }; + + for interface in interface_list { + if interface.name == payload.name { + return Ok(interface); + } + } + Err(NetBoxApiError::Other(format!( + "No Inteface '{}' with name found. Creation possibly failed.", + payload.name + ))) + } + Err(e) => { + let err: NetBoxApiError = NetBoxApiError::Reqwest(e); + Err(err) + } + } +} diff --git a/src/publisher/publisher.rs b/src/publisher/publisher.rs index 0371c87..2139d8f 100644 --- a/src/publisher/publisher.rs +++ b/src/publisher/publisher.rs @@ -23,7 +23,9 @@ use thanix_client::{ use crate::{ configuration::config_parser::ConfigData, publisher::{ - api_client::{create_device, create_interface, create_ip, test_connection}, + api_client::{ + create_device, create_interface, create_ip, get_interface_by_name, test_connection, + }, translator, }, Machine, @@ -107,11 +109,20 @@ pub fn register_machine( &device_id, ); - interface_id = match create_interface(client, interface_payload) { + interface_id = match create_interface(client, interface_payload.clone()) { Ok(id) => id, Err(e) => { eprintln!("{}", e); - process::exit(1); + match cont_search_nwi(client, &interface_payload) { + Ok(id) => { + println!("\x1b[32m[success]\x1b[0m Interface found using name. Continuing..."); + id + } + Err(e) => { + eprintln!("\x1b[31m[error]\x1b[0m {}. Aborting...", e); + process::exit(1); + } + } } }; } else { @@ -156,6 +167,23 @@ fn interface_exists(state: &ThanixClient, id: &Option) -> bool { todo!("check if interface exists must be implemented!"); } +fn cont_search_nwi( + state: &ThanixClient, + payload: &WritableInterfaceRequest, +) -> Result { + println!( + "\x1b[36m[warning]\x1b[0m Error while creating interface. Contingency search started..." + ); + + match get_interface_by_name(state, payload) { + Ok(interface) => Ok(interface.id), + Err(e) => { + eprintln!("\x1b[31m[error]\x1b[0m {}", e); + process::exit(1); + } + } +} + /// Get list of machines. /// /// Sends a `GET` request to either the `/dcim/devices` endpoint, in case of physical machines, From 3a396a6327dd49a02075bbfa486eb9df2a8602e4 Mon Sep 17 00:00:00 2001 From: ByteOtter Date: Mon, 27 May 2024 10:04:16 +0200 Subject: [PATCH 09/17] Add some manual curl tests for the api --- .gitignore | 3 +++ test/manual/README.md | 6 ++++++ test/manual/api/get_nazara_interface.sh | 23 +++++++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 test/manual/README.md create mode 100755 test/manual/api/get_nazara_interface.sh diff --git a/.gitignore b/.gitignore index 5322394..2a78849 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ Cargo.lock # output.txt file used for testing output.txt output.json + +# Test output +test/manual/**/output/ diff --git a/test/manual/README.md b/test/manual/README.md new file mode 100644 index 0000000..754b0bb --- /dev/null +++ b/test/manual/README.md @@ -0,0 +1,6 @@ +# Manual Tests + +This directory contains scripts and files used to manually test Nazara or a given NetBox API. + +These can be used for sanity checking API responses to troubleshoot +potential parsing errors. diff --git a/test/manual/api/get_nazara_interface.sh b/test/manual/api/get_nazara_interface.sh new file mode 100755 index 0000000..a37f006 --- /dev/null +++ b/test/manual/api/get_nazara_interface.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Test NetBox's API response by manually requesting information. +# Must be run *after* running Nazara and registering your device. + +# USAGE: +# ./test_interfaces.sh $URL $TOKEN + +if [ "$#" -ne 2 ]; then + echo "Usage: $0 " + exit 1 +fi + +url=$1 +token=$2 + + +curl -X POST "$url/api/dcim/interfaces/" \ +-H "Authorization: Token $token" \ +-H "Content-Type: application/json" \ +-d '{"name": "Nazara0", "device": 112, "type": "1000base-t"}' \ +-o "./output/interfaces.json" + From f666b446b68f4673df2e137ca9b33c7a1d8231eb Mon Sep 17 00:00:00 2001 From: ByteOtter Date: Thu, 27 Jun 2024 08:31:23 +0200 Subject: [PATCH 10/17] Update Cargo.toml (tmp) --- Cargo.toml | 2 +- src/publisher/publisher.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1d791dd..9c1e2f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ thanix_client = "1.1.0" # Uncomment this line if you are using a custom thanix client implementation. # Change the path to be relative to this Cargo.toml file. # The package parameter is the name of your client package. This is needed if you assigned a custom name upon creation. -# thanix_client = { package = "your_package_name", path = "path/to/your/client/crate" } +# thanix_client = { package = "thanix_client", path = "path/to/your/crate" } [dev-dependencies] mockall = "0.11.4" diff --git a/src/publisher/publisher.rs b/src/publisher/publisher.rs index 2139d8f..4b78ec6 100644 --- a/src/publisher/publisher.rs +++ b/src/publisher/publisher.rs @@ -6,7 +6,6 @@ //! //! The actual request logic will be provided by the `thanix_client` crate. use std::process; - /// TODO: 1. Implement Creation/update logic 2. Denest by splitting query logic off 3. Do not panic upon request fail use thanix_client::{ paths::{ From e609fa0476e19c504222a5421cae88d03122de44 Mon Sep 17 00:00:00 2001 From: ByteOtter Date: Tue, 16 Jul 2024 18:16:44 +0200 Subject: [PATCH 11/17] Bump thanix-client to 2.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 9c1e2f4..c99a577 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ toml = "0.7.6" # This may not work in your environment. You can get your schema by visiting # https://your.netbox-instance.com/api/schema. # The yaml file will be downloaded and you can generate your client by using https://github.com/The-Nazara-Project/Thanix. -thanix_client = "1.1.0" +thanix_client = "2.0.0" # Uncomment this line if you are using a custom thanix client implementation. # Change the path to be relative to this Cargo.toml file. # The package parameter is the name of your client package. This is needed if you assigned a custom name upon creation. From faa27b0bcf89089a3fa431bb212a5a3c976fc6cb Mon Sep 17 00:00:00 2001 From: ByteOtter Date: Mon, 12 Aug 2024 14:28:40 +0200 Subject: [PATCH 12/17] Bump thanix_client version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c99a577..510b6e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ toml = "0.7.6" # This may not work in your environment. You can get your schema by visiting # https://your.netbox-instance.com/api/schema. # The yaml file will be downloaded and you can generate your client by using https://github.com/The-Nazara-Project/Thanix. -thanix_client = "2.0.0" +thanix_client = "2.0.1" # Uncomment this line if you are using a custom thanix client implementation. # Change the path to be relative to this Cargo.toml file. # The package parameter is the name of your client package. This is needed if you assigned a custom name upon creation. From a6090ce8b86365f7c5c108375050688bfdb17107 Mon Sep 17 00:00:00 2001 From: ByteOtter Date: Wed, 4 Sep 2024 13:16:11 +0200 Subject: [PATCH 13/17] Downgrade thanix_client to align with NetBox 3.6.x --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 510b6e3..9c1e2f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ toml = "0.7.6" # This may not work in your environment. You can get your schema by visiting # https://your.netbox-instance.com/api/schema. # The yaml file will be downloaded and you can generate your client by using https://github.com/The-Nazara-Project/Thanix. -thanix_client = "2.0.1" +thanix_client = "1.1.0" # Uncomment this line if you are using a custom thanix client implementation. # Change the path to be relative to this Cargo.toml file. # The package parameter is the name of your client package. This is needed if you assigned a custom name upon creation. From df2053e15440a8a339947d04db5ee51ec6cd81ef Mon Sep 17 00:00:00 2001 From: ByteOtter Date: Wed, 4 Sep 2024 13:16:34 +0200 Subject: [PATCH 14/17] Add documentation to contingency search function for Interfaces --- src/publisher.rs | 2 +- src/publisher/publisher.rs | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/publisher.rs b/src/publisher.rs index cc6442a..dcf5cdc 100644 --- a/src/publisher.rs +++ b/src/publisher.rs @@ -2,4 +2,4 @@ pub mod api_client; // TODO make this non-public pub mod publisher; pub mod publisher_exceptions; pub mod trans_validation; -pub mod translator; // make this not public // TODO make this non-public // TODO: make this non-public +pub mod translator; diff --git a/src/publisher/publisher.rs b/src/publisher/publisher.rs index 4b78ec6..06abb06 100644 --- a/src/publisher/publisher.rs +++ b/src/publisher/publisher.rs @@ -13,7 +13,7 @@ use thanix_client::{ VirtualizationVirtualMachinesListQuery, VirtualizationVirtualMachinesListResponse, }, types::{ - self, DeviceWithConfigContext, VirtualMachineWithConfigContext, + DeviceWithConfigContext, VirtualMachineWithConfigContext, WritableDeviceWithConfigContextRequest, WritableIPAddressRequest, WritableInterfaceRequest, }, util::ThanixClient, @@ -144,14 +144,6 @@ pub fn register_machine( Ok(()) } -/// Creates a new machine in NetBox by calling the `translator` module to translate the `machine` parameter -/// struct into the correct data type required by the API. -fn create_machine(client: &ThanixClient, machine: &Machine) -> Result<(), NetBoxApiError> { - println!("Creating new machine in NetBox..."); - // let payload = translator::information_to_device(machine); - Ok(()) -} - /// Checks if a given network interface ID corresponds to a interface which already exsists. /// /// # Parameter @@ -166,6 +158,13 @@ fn interface_exists(state: &ThanixClient, id: &Option) -> bool { todo!("check if interface exists must be implemented!"); } +// HACK +/// Contingency function to search for the previously created Network Interface, when the response +/// given my NetBox cannot be serialized correctly therefore no Interface ID is returned. +/// +/// # Parameters +/// * `state: &ThanixClient` - The client to communicate with the API. +/// * `payload: &WritableInterfaceRequest` - The API request payload. fn cont_search_nwi( state: &ThanixClient, payload: &WritableInterfaceRequest, From fabd4ec7fcdce314e926fe9f32a8af9a835eec31 Mon Sep 17 00:00:00 2001 From: ByteOtter Date: Thu, 5 Sep 2024 13:20:59 +0200 Subject: [PATCH 15/17] Implement workaround for unsanitary response data --- Cargo.toml | 4 +- src/publisher/api_client.rs | 21 ++++---- src/publisher/publisher.rs | 11 +++-- src/publisher/translator.rs | 96 +++++++++++++++---------------------- 4 files changed, 58 insertions(+), 74 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9c1e2f4..1d8fd8d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,11 +25,11 @@ toml = "0.7.6" # This may not work in your environment. You can get your schema by visiting # https://your.netbox-instance.com/api/schema. # The yaml file will be downloaded and you can generate your client by using https://github.com/The-Nazara-Project/Thanix. -thanix_client = "1.1.0" +# thanix_client = "1.1.0" # Uncomment this line if you are using a custom thanix client implementation. # Change the path to be relative to this Cargo.toml file. # The package parameter is the name of your client package. This is needed if you assigned a custom name upon creation. -# thanix_client = { package = "thanix_client", path = "path/to/your/crate" } +thanix_client = { package = "thanix_client", path = "/home/christopher/Codebase/nazara-project/Thanix/output/" } [dev-dependencies] mockall = "0.11.4" diff --git a/src/publisher/api_client.rs b/src/publisher/api_client.rs index cfeeea7..67c4dbd 100644 --- a/src/publisher/api_client.rs +++ b/src/publisher/api_client.rs @@ -10,13 +10,10 @@ extern crate thanix_client; use reqwest::Error as ReqwestError; use thanix_client::{ paths::{ - dcim_devices_create, dcim_interfaces_create, dcim_interfaces_list, - ipam_ip_addresses_create, DcimDevicesCreateResponse, DcimInterfacesCreateResponse, - DcimInterfacesListQuery, + dcim_devices_create, dcim_interfaces_create, dcim_interfaces_list, ipam_ip_addresses_create, DcimDevicesCreateResponse, DcimInterfacesListQuery }, types::{ - Interface, WritableDeviceWithConfigContextRequest, WritableIPAddressRequest, - WritableInterfaceRequest, + Interface, WritableDeviceWithConfigContextRequest, WritableIPAddressRequest, WritableInterfaceRequest }, util::ThanixClient, }; @@ -120,7 +117,7 @@ pub fn create_interface( match dcim_interfaces_create(client, payload) { Ok(response) => match response { thanix_client::paths::DcimInterfacesCreateResponse::Http201(result) => { - println!("\x1b[32m[success]\x1b[0m Interface created successfully. New Interface ID: '{}'", result.id); + println!("\x1b[32m[success]\x1b[0m Interface created successfully. New Interface-ID: '{}'", result.id); Ok(result.id) } thanix_client::paths::DcimInterfacesCreateResponse::Other(other_response) => { @@ -152,7 +149,7 @@ pub fn create_ip( Ok(response) => match response { thanix_client::paths::IpamIpAddressesCreateResponse::Http201(result) => { println!( - "\x1b[32m[success]\x1b[0m IP Address created successfully. New IP ID: '{}'", + "\x1b[32m[success]\x1b[0m IP Address created successfully. New IP-ID: '{}'", result.id ); Ok(result.id) @@ -174,13 +171,16 @@ pub fn get_interface_by_name( state: &ThanixClient, payload: &WritableInterfaceRequest, ) -> Result { - println!("Trying to retrieve interface by name '{}'...", payload.name); + println!( + "Trying to retrieve interface by name '{}'...", + payload.name.as_ref().unwrap() + ); match dcim_interfaces_list(state, DcimInterfacesListQuery::default()) { Ok(response) => { let interface_list: Vec = match response { thanix_client::paths::DcimInterfacesListResponse::Http200(interfaces) => { - interfaces.results + interfaces.results.unwrap() } thanix_client::paths::DcimInterfacesListResponse::Other(response) => { let err: NetBoxApiError = NetBoxApiError::Other(response.text().unwrap()); @@ -195,7 +195,7 @@ pub fn get_interface_by_name( } Err(NetBoxApiError::Other(format!( "No Inteface '{}' with name found. Creation possibly failed.", - payload.name + payload.name.as_ref().unwrap() ))) } Err(e) => { @@ -204,3 +204,4 @@ pub fn get_interface_by_name( } } } + diff --git a/src/publisher/publisher.rs b/src/publisher/publisher.rs index 06abb06..08e0603 100644 --- a/src/publisher/publisher.rs +++ b/src/publisher/publisher.rs @@ -64,7 +64,9 @@ pub fn probe(client: &ThanixClient) -> Result<(), NetBoxApiError> { /// /// # Parameters /// -/// - `client: &ThanixClient` - Reference to a `thanix_client` instance +/// - `client: &ThanixClient` - Reference to a `thanix_client` instance. +/// - `machine: Machine` - Information about the host machine collected by the `collector` module. +/// - `config_data: ConfigData` - Nazara's configuration. /// /// # Returns /// @@ -99,10 +101,11 @@ pub fn register_machine( }; let interface_id: i64; // TODO: Check if interface ID is valid, if not, create new interface. + // Create new interface object if no interface ID is given, or the given ID does + // not exist. if config_data.nwi.id.is_none() || !interface_exists(client, &config_data.nwi.id) { let interface_payload: WritableInterfaceRequest = translator::information_to_interface( - &client, &machine, config_data.clone(), &device_id, @@ -129,9 +132,9 @@ pub fn register_machine( } let ip_payload: WritableIPAddressRequest = - translator::information_to_ip(client, &machine, &config_data, interface_id); + translator::information_to_ip(&machine, &config_data, interface_id); - let ip_id = match create_ip(client, ip_payload) { + let _ = match create_ip(client, ip_payload) { Ok(id) => id, Err(e) => { eprintln!("{}", e); diff --git a/src/publisher/translator.rs b/src/publisher/translator.rs index 7001832..18902ef 100644 --- a/src/publisher/translator.rs +++ b/src/publisher/translator.rs @@ -2,10 +2,7 @@ //! //! This module handles the translation and processing of the data sent to or received from NetBox. //! -//! TODO: -//! - Identify primary IPv4 or IPv6 using the primary_network_interface field from `ConfigData`. use core::net::IpAddr; -use std::collections::HashMap; use std::process; use std::str::FromStr; use thanix_client::paths::{ @@ -20,8 +17,6 @@ use thanix_client::util::ThanixClient; use crate::collectors::network_collector::NetworkInformation; use crate::{configuration::config_parser::ConfigData, Machine}; -use super::publisher_exceptions::NetBoxApiError; - /// Translate the machine information to a `WritableDeviceWithConfigContextRequest` required by /// NetBox's API. /// @@ -94,7 +89,7 @@ pub fn information_to_device( payload.comments = config_data.system.comments; // payload.config_template = todo!(); payload.custom_fields = config_data.system.custom_fields; - // payload.description = todo!(); + payload.description = config_data.system.description; // payload.local_context_data = todo!(); // payload.oob_ip = todo!(); payload.primary_ip4 = get_primary_addresses( @@ -154,7 +149,6 @@ pub fn information_to_vm( /// /// * payload: `WritableInterfaceRequest` - Payload for creating an interface. pub fn information_to_interface( - state: &ThanixClient, machine: &Machine, config_data: ConfigData, device_id: &i64, @@ -163,22 +157,17 @@ pub fn information_to_interface( let mut payload: WritableInterfaceRequest = WritableInterfaceRequest::default(); - payload.device = device_id.to_owned(); - // payload.vdcs = todo!(); - // payload.module = todo!(); - payload.name = match &config_data.system.primary_network_interface { - Some(interface_name) => interface_name.to_owned(), - None => String::from("Nazara Generic Network Interface"), - }; - // payload.label = todo!(); + payload.device = Some(device_id.to_owned()); + payload.name = config_data.system.primary_network_interface.clone(); + // FIXME: - payload.r#type = config_data.nwi.r#type; + payload.r#type = Some(config_data.nwi.r#type); payload.parent = config_data.nwi.parent; payload.bridge = config_data.nwi.bridge; payload.lag = config_data.nwi.lag; payload.mtu = config_data.nwi.mtu; - // Get the interfce we are looking for as primary, then get its parameters. + // Get the interface we are looking for as primary, then get its parameters. // These filter statements can probably be split off into their own function. payload.mac_address = match &config_data.system.primary_network_interface { Some(nwi_name) => { @@ -200,15 +189,23 @@ pub fn information_to_interface( } None => None, }; - payload.description = String::from("This interface was automatically created by Nazara."); - payload.mode = config_data.nwi.mode.unwrap_or(String::from("")); - payload.rf_role = config_data.nwi.rf_role.unwrap_or(String::from("")); - payload.rf_channel = config_data.nwi.rf_channel.unwrap_or(String::from("")); - payload.poe_mode = config_data.nwi.poe_mode.unwrap_or(String::from("")); - payload.poe_type = config_data.nwi.poe_type.unwrap_or(String::from("")); + payload.description = Some(String::from( + "This interface was automatically created by Nazara.", + )); + payload.mode = Some(config_data.nwi.mode.unwrap_or(String::from(""))); + payload.rf_role = Some(config_data.nwi.rf_role.unwrap_or(String::from(""))); + payload.rf_channel = Some(config_data.nwi.rf_channel.unwrap_or(String::from(""))); + payload.poe_mode = Some(config_data.nwi.poe_mode.unwrap_or(String::from(""))); + payload.poe_type = Some(config_data.nwi.poe_type.unwrap_or(String::from(""))); payload.custom_fields = config_data.nwi.custom_fields; - payload.mark_connected = config_data.nwi.mark_connected; - payload.enabled = config_data.nwi.enabled; + payload.mark_connected = Some(config_data.nwi.mark_connected); + payload.enabled = Some(config_data.nwi.enabled); + payload.vdcs = Some(config_data.nwi.vdcs.unwrap_or_default()); + payload.label = Some(config_data.nwi.label.unwrap_or_default()); + payload.mgmt_only = Some(config_data.nwi.mgmt_only); + payload.tagged_vlans = Some(config_data.nwi.tagged_vlans.unwrap_or_default()); + payload.wireless_lans = Some(config_data.nwi.wireless_lans.unwrap_or_default()); + payload.tags = Some(Vec::new()); payload } @@ -222,7 +219,6 @@ pub fn information_to_interface( /// * config_data: `&ConfigData` - Data read from the config file. /// * interface_id: `i64` - ID of the network interface this IP belongs to. pub fn information_to_ip( - state: &ThanixClient, machine: &Machine, config_data: &ConfigData, interface_id: i64, @@ -231,19 +227,30 @@ pub fn information_to_ip( let mut payload: WritableIPAddressRequest = WritableIPAddressRequest::default(); - // payload.address = todo!(); + let local_interface: &NetworkInformation = machine + .network_information + .iter() + .find(|s| { + s.name + == as Clone>::clone( + &config_data.system.primary_network_interface, + ) + .unwrap() + }) + .unwrap(); + payload.address = format!("{}", local_interface.v4ip.unwrap()); // payload.vrf = todo!(); // payload.tenant = todo!(); - // payload.status = todo!(); + payload.status = String::from("active"); // payload.role = todo!(); - // payload.assigned_object_type = todo!(); - // payload.assigned_object_id = todo!(); + payload.assigned_object_type = Some(String::from("dcim.interface")); + payload.assigned_object_id = Some(interface_id as u64); // payload.nat_inside = todo!(); // payload.dns_name = todo!(); payload.description = String::from("This Address was automatically created by Nazara."); payload.comments = String::from("Automatically created by Nazara. Dummy only."); // payload.tags = todo!(); - payload.custom_fields = Some(HashMap::new()); + payload.custom_fields = config_data.nwi.custom_fields.clone(); payload } @@ -383,7 +390,6 @@ fn get_primary_addresses( }, } } - println!(); result } @@ -459,29 +465,3 @@ fn get_site_id(state: &ThanixClient, config_data: &ConfigData) -> Option { } None } - -/// Create a new IP-Adress object in NetBox if the collected IP Adresses for the preferred interface -/// do not exist yet. -/// -/// # Parameters -/// -/// * state: `&ThanixClient` - The `ThanixClient` object used for API connection. -/// * config_data: `&ConfigData` - The config information which identifies the preferred network -/// interface. -/// * sys_info: `&Machine` - Collected system information which contains the IP Adresses to create. -/// -/// # Returns -/// -/// Return `Ok(i64)` containing the ID of the created IP Adress entry if the creation was -/// successful. Otherwise, return `NetBoxApiError`. -/// -/// # Panics -/// -/// This function panics if the connection to NetBox fails. -fn create_ip_adresses( - state: &ThanixClient, - config_data: &ConfigData, - sys_info: &Machine, -) -> Result { - todo!(); -} From 74cc0b506646ee6ddaf3abcba13dfac98ee8c4b1 Mon Sep 17 00:00:00 2001 From: ByteOtter Date: Thu, 5 Sep 2024 13:29:44 +0200 Subject: [PATCH 16/17] Skip loopback device when collecting network interfaces --- src/collectors/network_collector.rs | 10 +++++++--- src/publisher/api_client.rs | 7 ++++--- src/publisher/publisher.rs | 4 ++-- src/publisher/translator.rs | 2 +- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/collectors/network_collector.rs b/src/collectors/network_collector.rs index 97826e0..09eed59 100644 --- a/src/collectors/network_collector.rs +++ b/src/collectors/network_collector.rs @@ -67,11 +67,11 @@ pub fn collect_network_information( match network_interfaces_result { Ok(network_interfaces) => { if network_interfaces.is_empty() { - return Err(collector_exceptions::NoNetworkInterfacesException { + Err(collector_exceptions::NoNetworkInterfacesException { message: "\x1b[31m[error]\x1b[0m No network interfaces found!".to_string(), - }); + }) } else { - return Ok(network_interfaces); + Ok(network_interfaces) } } Err(_) => { @@ -114,6 +114,10 @@ pub fn construct_network_information( let mut network_information: NetworkInformation; for network_interface in raw_information { + // Skip loopback device. + if network_interface.name == "lo" { + continue; + } match Some(&network_interface.addr) { Some(_v) => { // Cases where only one set of addresses exist. diff --git a/src/publisher/api_client.rs b/src/publisher/api_client.rs index 67c4dbd..1e019c8 100644 --- a/src/publisher/api_client.rs +++ b/src/publisher/api_client.rs @@ -10,10 +10,12 @@ extern crate thanix_client; use reqwest::Error as ReqwestError; use thanix_client::{ paths::{ - dcim_devices_create, dcim_interfaces_create, dcim_interfaces_list, ipam_ip_addresses_create, DcimDevicesCreateResponse, DcimInterfacesListQuery + dcim_devices_create, dcim_interfaces_create, dcim_interfaces_list, + ipam_ip_addresses_create, DcimDevicesCreateResponse, DcimInterfacesListQuery, }, types::{ - Interface, WritableDeviceWithConfigContextRequest, WritableIPAddressRequest, WritableInterfaceRequest + Interface, WritableDeviceWithConfigContextRequest, WritableIPAddressRequest, + WritableInterfaceRequest, }, util::ThanixClient, }; @@ -204,4 +206,3 @@ pub fn get_interface_by_name( } } } - diff --git a/src/publisher/publisher.rs b/src/publisher/publisher.rs index 08e0603..57f9c49 100644 --- a/src/publisher/publisher.rs +++ b/src/publisher/publisher.rs @@ -101,8 +101,8 @@ pub fn register_machine( }; let interface_id: i64; // TODO: Check if interface ID is valid, if not, create new interface. - // Create new interface object if no interface ID is given, or the given ID does - // not exist. + // Create new interface object if no interface ID is given, or the given ID does + // not exist. if config_data.nwi.id.is_none() || !interface_exists(client, &config_data.nwi.id) { let interface_payload: WritableInterfaceRequest = translator::information_to_interface( diff --git a/src/publisher/translator.rs b/src/publisher/translator.rs index 18902ef..cdd5dab 100644 --- a/src/publisher/translator.rs +++ b/src/publisher/translator.rs @@ -157,7 +157,7 @@ pub fn information_to_interface( let mut payload: WritableInterfaceRequest = WritableInterfaceRequest::default(); - payload.device = Some(device_id.to_owned()); + payload.device = Some(device_id.to_owned()); payload.name = config_data.system.primary_network_interface.clone(); // FIXME: From bae50c43e34dda4ac27f4c36dc67bbf5b1782803 Mon Sep 17 00:00:00 2001 From: ByteOtter Date: Thu, 5 Sep 2024 13:36:46 +0200 Subject: [PATCH 17/17] Use thanix_client v1.2.0 --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1d8fd8d..2c3f1b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,11 +25,11 @@ toml = "0.7.6" # This may not work in your environment. You can get your schema by visiting # https://your.netbox-instance.com/api/schema. # The yaml file will be downloaded and you can generate your client by using https://github.com/The-Nazara-Project/Thanix. -# thanix_client = "1.1.0" +thanix_client = "1.2.0" # Uncomment this line if you are using a custom thanix client implementation. # Change the path to be relative to this Cargo.toml file. # The package parameter is the name of your client package. This is needed if you assigned a custom name upon creation. -thanix_client = { package = "thanix_client", path = "/home/christopher/Codebase/nazara-project/Thanix/output/" } +# thanix_client = { package = "thanix_client", path = "/path/to/your/crate" } [dev-dependencies] mockall = "0.11.4"