Some checks failed
Run Check Script / check (pull_request) Failing after 30s
168 lines
5.8 KiB
Rust
168 lines
5.8 KiB
Rust
use askama::Template;
|
|
use async_trait::async_trait;
|
|
use derive_new::new;
|
|
use harmony_types::net::{IpAddress, Url};
|
|
use serde::Serialize;
|
|
use std::net::{IpAddr, Ipv4Addr};
|
|
|
|
use crate::{
|
|
data::{FileContent, FilePath, Version},
|
|
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
|
|
inventory::Inventory,
|
|
modules::{dhcp::DhcpScore, http::StaticFilesHttpScore, tftp::TftpScore},
|
|
score::Score,
|
|
topology::{DhcpServer, HttpServer, Router, TftpServer, Topology},
|
|
};
|
|
use harmony_types::id::Id;
|
|
|
|
#[derive(Debug, new, Clone, Serialize)]
|
|
pub struct OKDIpxeScore {
|
|
pub kickstart_filename: String,
|
|
pub harmony_inventory_agent: String,
|
|
pub cluster_pubkey: FileContent,
|
|
}
|
|
|
|
impl<T: Topology + DhcpServer + TftpServer + HttpServer + Router> Score<T> for OKDIpxeScore {
|
|
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
|
Box::new(OKDIpxeInterpret::new(self.clone()))
|
|
}
|
|
|
|
fn name(&self) -> String {
|
|
"OkdIpxeScore".to_string()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, new, Clone)]
|
|
pub struct OKDIpxeInterpret {
|
|
score: OKDIpxeScore,
|
|
}
|
|
|
|
#[async_trait]
|
|
impl<T: Topology + DhcpServer + TftpServer + HttpServer + Router> Interpret<T>
|
|
for OKDIpxeInterpret
|
|
{
|
|
async fn execute(
|
|
&self,
|
|
inventory: &Inventory,
|
|
topology: &T,
|
|
) -> Result<Outcome, InterpretError> {
|
|
let gateway_ip = topology.get_gateway();
|
|
|
|
let dhcp_server_ip = match DhcpServer::get_ip(topology) {
|
|
std::net::IpAddr::V4(ipv4_addr) => ipv4_addr,
|
|
std::net::IpAddr::V6(_ipv6_addr) => todo!("Support ipv6 someday"),
|
|
};
|
|
|
|
// TODO this could overflow, we should use proper subnet maths here instead of an ip
|
|
// address and guessing the subnet size from there
|
|
let start = Ipv4Addr::from(u32::from(dhcp_server_ip) + 100);
|
|
let end = Ipv4Addr::from(u32::from(dhcp_server_ip) + 150);
|
|
|
|
let scores: Vec<Box<dyn Score<T>>> = vec![
|
|
Box::new(DhcpScore {
|
|
host_binding: vec![],
|
|
domain: None,
|
|
next_server: Some(topology.get_gateway()),
|
|
boot_filename: None,
|
|
filename: Some("undionly.kpxe".to_string()),
|
|
filename64: Some("ipxe.efi".to_string()),
|
|
filenameipxe: Some(format!("http://{gateway_ip}:8080/boot.ipxe").to_string()),
|
|
dhcp_range: (IpAddress::from(start), IpAddress::from(end)),
|
|
}),
|
|
Box::new(TftpScore {
|
|
files_to_serve: Url::LocalFolder("./data/pxe/okd/tftpboot/".to_string()),
|
|
}),
|
|
Box::new(StaticFilesHttpScore {
|
|
remote_path: None,
|
|
// TODO The current russh based copy is way too slow, check for a lib update or use scp
|
|
// when available
|
|
//
|
|
// For now just run :
|
|
// scp -r data/pxe/okd/http_files/* root@192.168.1.1:/usr/local/http/
|
|
//
|
|
folder_to_serve: None,
|
|
// folder_to_serve: Some(Url::LocalFolder("./data/pxe/okd/http_files/".to_string())),
|
|
files: vec![
|
|
FileContent {
|
|
path: FilePath::Relative("boot.ipxe".to_string()),
|
|
content: BootIpxeTpl {
|
|
gateway_ip: &gateway_ip,
|
|
}
|
|
.to_string(),
|
|
},
|
|
FileContent {
|
|
path: FilePath::Relative(self.score.kickstart_filename.clone()),
|
|
content: InventoryKickstartTpl {
|
|
gateway_ip: &gateway_ip,
|
|
harmony_inventory_agent: &self.score.harmony_inventory_agent,
|
|
cluster_pubkey_filename: &self.score.cluster_pubkey.path.to_string(),
|
|
}
|
|
.to_string(),
|
|
},
|
|
FileContent {
|
|
path: FilePath::Relative("fallback.ipxe".to_string()),
|
|
content: FallbackIpxeTpl {
|
|
gateway_ip: &gateway_ip,
|
|
kickstart_filename: &self.score.kickstart_filename,
|
|
}
|
|
.to_string(),
|
|
},
|
|
self.score.cluster_pubkey.clone(),
|
|
],
|
|
}),
|
|
];
|
|
|
|
for score in scores {
|
|
let result = score.interpret(inventory, topology).await;
|
|
match result {
|
|
Ok(outcome) => match outcome.status {
|
|
InterpretStatus::SUCCESS => continue,
|
|
InterpretStatus::NOOP => continue,
|
|
_ => return Err(InterpretError::new(outcome.message)),
|
|
},
|
|
Err(e) => return Err(e),
|
|
};
|
|
}
|
|
inquire::Confirm::new(&format!("Execute the copy : `scp -r data/pxe/okd/http_files/* root@{}:/usr/local/http/` and confirm when done to continue", HttpServer::get_ip(topology))).prompt().expect("Prompt error");
|
|
|
|
Ok(Outcome::success("Ipxe installed".to_string()))
|
|
}
|
|
|
|
fn get_name(&self) -> InterpretName {
|
|
InterpretName::Ipxe
|
|
}
|
|
|
|
fn get_version(&self) -> Version {
|
|
todo!()
|
|
}
|
|
|
|
fn get_status(&self) -> InterpretStatus {
|
|
todo!()
|
|
}
|
|
|
|
fn get_children(&self) -> Vec<Id> {
|
|
todo!()
|
|
}
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "boot.ipxe.j2")]
|
|
struct BootIpxeTpl<'a> {
|
|
gateway_ip: &'a IpAddr,
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "fallback.ipxe.j2")]
|
|
struct FallbackIpxeTpl<'a> {
|
|
gateway_ip: &'a IpAddr,
|
|
kickstart_filename: &'a str,
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "inventory.kickstart.j2")]
|
|
struct InventoryKickstartTpl<'a> {
|
|
gateway_ip: &'a IpAddr,
|
|
cluster_pubkey_filename: &'a str,
|
|
harmony_inventory_agent: &'a str,
|
|
}
|