feat: started to prepare inventory / topoplogy for NCD #1

Merged
johnride merged 17 commits from feat/settingUpNDC into master 2025-05-06 16:38:41 +00:00
6 changed files with 33 additions and 3 deletions
Showing only changes of commit 8118df85ee - Show all commits

View File

@ -124,6 +124,9 @@ impl DhcpServer for DummyInfra {
async fn set_filename(&self, _filename: &str) -> Result<(), ExecutorError> {
unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA)
}
async fn set_filename64(&self, _filename: &str) -> Result<(), ExecutorError> {
unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA)
}
fn get_ip(&self) -> IpAddress {
unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA)
}

View File

@ -49,6 +49,7 @@ pub trait DhcpServer: Send + Sync {
async fn set_next_server(&self, ip: IpAddress) -> Result<(), ExecutorError>;
async fn set_boot_filename(&self, boot_filename: &str) -> Result<(), ExecutorError>;
async fn set_filename(&self, filename: &str) -> Result<(), ExecutorError>;

Ca gosse de devoir fix ces dummy la tout le temps. Peut-etre qu'on pourrait creer une macro assez facilement qui cree une implementation dummy? Pas urgent.

Ca gosse de devoir fix ces dummy la tout le temps. Peut-etre qu'on pourrait creer une macro assez facilement qui cree une implementation dummy? Pas urgent.
async fn set_filename64(&self, filename64: &str) -> Result<(), ExecutorError>;
fn get_ip(&self) -> IpAddress;
fn get_host(&self) -> LogicalHost;
async fn commit_config(&self) -> Result<(), ExecutorError>;

View File

@ -79,4 +79,14 @@ impl DhcpServer for OPNSenseFirewall {
Ok(())
}
async fn set_filename64(&self, filename: &str) -> Result<(), ExecutorError> {
{
let mut writable_opnsense = self.opnsense_config.write().await;
writable_opnsense.dhcp().set_filename64(filename);
debug!("OPNsense dhcp server set filename {filename}");
}
Ok(())
}
}

View File

@ -19,6 +19,7 @@ pub struct DhcpScore {
pub next_server: Option<IpAddress>,
pub boot_filename: Option<String>,
pub filename: Option<String>,
pub filename64: Option<String>,
pub filename_ipxe: Option<String>,
}
@ -139,9 +140,22 @@ impl DhcpInterpret {
None => Outcome::noop(),
};
let filename64_outcome = match &self.score.filename64 {
Some(filename64) => {
let dhcp_server = Arc::new(topology.dhcp_server.clone());
dhcp_server.set_filename64(&filename64).await?;
Outcome::new(
InterpretStatus::SUCCESS,
format!("Dhcp Interpret Set filename64 to {filename64}"),
)
}
None => Outcome::noop(),
};
if next_server_outcome.status == InterpretStatus::NOOP
Review

Rendu a 5 copier-coller du meme bout de code ca meriterait un refactor pour une fonction qui prend une closure qui a le minimum d'information.

Un petit coup de Claude m'a donne ceci qui semble legit :

async fn set_pxe_options(
    &self,
    _inventory: &Inventory,
    topology: &HAClusterTopology,
) -> Result<Outcome, InterpretError> {
    async fn process_option<T, F, Fut>(
        option: &Option<T>, 
        description: &str,
        action: F
    ) -> Result<Outcome, InterpretError> 
    where
        T: std::fmt::Display,
        F: FnOnce(&T) -> Fut,
        Fut: std::future::Future<Output = Result<(), InterpretError>>,
    {
        match option {
            Some(value) => {
                action(value).await?;
                Ok(Outcome::new(
                    InterpretStatus::SUCCESS,
                    format!("Dhcp Interpret Set {} to {}", description, value),
                ))
            }
            None => Ok(Outcome::noop()),
        }
    }

    let dhcp_server = Arc::new(topology.dhcp_server.clone());
    
    let next_server_outcome = process_option(
        &self.score.next_server,
        "next boot",
        |next_server| dhcp_server.set_next_server(*next_server)
    ).await?;
    
    let boot_filename_outcome = process_option(
        &self.score.boot_filename,
        "boot filename",
        |boot_filename| dhcp_server.set_boot_filename(boot_filename)
    ).await?;
    
    let filename_outcome = process_option(
        &self.score.filename,
        "filename",
        |filename| dhcp_server.set_filename(filename)
    ).await?;
    
    let filename64_outcome = process_option(
        &self.score.filename64,
        "filename64",
        |filename64| dhcp_server.set_filename64(filename64)
    ).await?;
    
    let filenameipxe_outcome = process_option(
        &self.score.filenameipxe,
        "filenameipxe",
        |filenameipxe| dhcp_server.set_filenameipxe(filenameipxe)
    ).await?;

    if next_server_outcome.status == InterpretStatus::NOOP
        && boot_filename_outcome.status == InterpretStatus::NOOP
        && filename_outcome.status == InterpretStatus::NOOP
        && filename64_outcome.status == InterpretStatus::NOOP
        && filenameipxe_outcome.status == InterpretStatus::NOOP
    {
        return Ok(Outcome::noop());
    }

    Ok(Outcome::new(
        InterpretStatus::SUCCESS,
        format!(
            "Dhcp Interpret Set next boot to [{:?}], boot_filename to [{:?}], filename to [{:?}], filename64 to [{:?}], filenameipxe to [{:?}]",
            self.score.next_server, self.score.boot_filename, self.score.filename, self.score.filename64, self.score.filenameipxe
        ),
    ))
}
Rendu a 5 copier-coller du meme bout de code ca meriterait un refactor pour une fonction qui prend une closure qui a le minimum d'information. Un petit coup de Claude m'a donne ceci qui semble legit : ```rust async fn set_pxe_options( &self, _inventory: &Inventory, topology: &HAClusterTopology, ) -> Result<Outcome, InterpretError> { async fn process_option<T, F, Fut>( option: &Option<T>, description: &str, action: F ) -> Result<Outcome, InterpretError> where T: std::fmt::Display, F: FnOnce(&T) -> Fut, Fut: std::future::Future<Output = Result<(), InterpretError>>, { match option { Some(value) => { action(value).await?; Ok(Outcome::new( InterpretStatus::SUCCESS, format!("Dhcp Interpret Set {} to {}", description, value), )) } None => Ok(Outcome::noop()), } } let dhcp_server = Arc::new(topology.dhcp_server.clone()); let next_server_outcome = process_option( &self.score.next_server, "next boot", |next_server| dhcp_server.set_next_server(*next_server) ).await?; let boot_filename_outcome = process_option( &self.score.boot_filename, "boot filename", |boot_filename| dhcp_server.set_boot_filename(boot_filename) ).await?; let filename_outcome = process_option( &self.score.filename, "filename", |filename| dhcp_server.set_filename(filename) ).await?; let filename64_outcome = process_option( &self.score.filename64, "filename64", |filename64| dhcp_server.set_filename64(filename64) ).await?; let filenameipxe_outcome = process_option( &self.score.filenameipxe, "filenameipxe", |filenameipxe| dhcp_server.set_filenameipxe(filenameipxe) ).await?; if next_server_outcome.status == InterpretStatus::NOOP && boot_filename_outcome.status == InterpretStatus::NOOP && filename_outcome.status == InterpretStatus::NOOP && filename64_outcome.status == InterpretStatus::NOOP && filenameipxe_outcome.status == InterpretStatus::NOOP { return Ok(Outcome::noop()); } Ok(Outcome::new( InterpretStatus::SUCCESS, format!( "Dhcp Interpret Set next boot to [{:?}], boot_filename to [{:?}], filename to [{:?}], filename64 to [{:?}], filenameipxe to [{:?}]", self.score.next_server, self.score.boot_filename, self.score.filename, self.score.filename64, self.score.filenameipxe ), )) } ```
&& boot_filename_outcome.status == InterpretStatus::NOOP
&& filename_outcome.status == InterpretStatus::NOOP
&& filename64_outcome.status == InterpretStatus::NOOP
{
return Ok(Outcome::noop());
}
@ -149,8 +163,8 @@ impl DhcpInterpret {
Ok(Outcome::new(
InterpretStatus::SUCCESS,
format!(
"Dhcp Interpret Set next boot to [{:?}], boot_filename to [{:?}], filename to [{:?}]",
self.score.boot_filename, self.score.boot_filename, self.score.filename
"Dhcp Interpret Set next boot to [{:?}], boot_filename to [{:?}], filename to [{:?}], filename64 to [{:?}]",
self.score.boot_filename, self.score.boot_filename, self.score.filename, self.score.filename64
),
))
}

View File

@ -41,8 +41,9 @@ impl OKDBootstrapDhcpScore {
// router address, this is leaking implementation details
Some(topology.router.get_gateway()),
Some("bootx64.efi".to_string()),
Some(format!("{}:8080/boot.ipxe", topology.router.get_gateway())),
Some("undionly.kpxe".to_string()),
Some("ipxe.efi".to_string()),
Some(format!("{}:8080/boot.ipxe", topology.router.get_gateway())),
),
}
}

View File

@ -35,6 +35,7 @@ impl OKDDhcpScore {
boot_filename: None,
filename_ipxe: Some(format!("{}:8080/boot.ipxe", topology.router.get_gateway())),
filename: Some("undionly.kpxe".to_string()),
filename64: Some("ipxe.efi".to_string()),
},
}
}