diff --git a/.gitattributes b/.gitattributes index e5e8283..475c220 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,3 +2,5 @@ bootx64.efi filter=lfs diff=lfs merge=lfs -text grubx64.efi filter=lfs diff=lfs merge=lfs -text initrd filter=lfs diff=lfs merge=lfs -text linux filter=lfs diff=lfs merge=lfs -text +data/okd/bin/* filter=lfs diff=lfs merge=lfs -text +data/okd/installer_image/* filter=lfs diff=lfs merge=lfs -text diff --git a/adr/agent_discovery/mdns/src/discover.rs b/adr/agent_discovery/mdns/src/discover.rs index bf339de..276ca5c 100644 --- a/adr/agent_discovery/mdns/src/discover.rs +++ b/adr/agent_discovery/mdns/src/discover.rs @@ -1,4 +1,3 @@ -use log::debug; use mdns_sd::{ServiceDaemon, ServiceEvent}; use crate::SERVICE_TYPE; @@ -74,7 +73,7 @@ pub async fn discover() { // } } -async fn discover_example() { +async fn _discover_example() { use mdns_sd::{ServiceDaemon, ServiceEvent}; // Create a daemon diff --git a/data/okd/bin/kubectl b/data/okd/bin/kubectl new file mode 100755 index 0000000..e678ff0 --- /dev/null +++ b/data/okd/bin/kubectl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2c00e6cf8aeec70327e3c3a6d6efbedae34742e64af7a6f4380e4325827c3eb2 +size 123112560 diff --git a/data/okd/bin/oc b/data/okd/bin/oc new file mode 100755 index 0000000..e678ff0 --- /dev/null +++ b/data/okd/bin/oc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2c00e6cf8aeec70327e3c3a6d6efbedae34742e64af7a6f4380e4325827c3eb2 +size 123112560 diff --git a/data/okd/bin/oc_README.md b/data/okd/bin/oc_README.md new file mode 100644 index 0000000..e0934fd --- /dev/null +++ b/data/okd/bin/oc_README.md @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:75e9b59be7d37cdd5a9a5e7059831c7f728f092ca5fcd41bc36be5649bab5a9a +size 954 diff --git a/data/okd/bin/openshift-install b/data/okd/bin/openshift-install new file mode 100755 index 0000000..4837740 --- /dev/null +++ b/data/okd/bin/openshift-install @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:603d7920a886db2a7678fa8366a2964b5658ce153aaf6649a9b6772906dfc0ad +size 596820120 diff --git a/data/okd/bin/openshift-install_README.md b/data/okd/bin/openshift-install_README.md new file mode 100644 index 0000000..d082a4d --- /dev/null +++ b/data/okd/bin/openshift-install_README.md @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3885ee9469f6eb63c6c60b6b170d4c3766c4d255a677781418e3078e04601fd2 +size 706 diff --git a/data/okd/installer_image/scos-9.0.20250510-0-live-initramfs.x86_64.img b/data/okd/installer_image/scos-9.0.20250510-0-live-initramfs.x86_64.img new file mode 100644 index 0000000..6109433 --- /dev/null +++ b/data/okd/installer_image/scos-9.0.20250510-0-live-initramfs.x86_64.img @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c662e3b281ae4ce9d3a0b94c8286ef37ec7e452c1d3342d2b4dac734f8048d2e +size 101785184 diff --git a/data/okd/installer_image/scos-9.0.20250510-0-live-kernel.x86_64 b/data/okd/installer_image/scos-9.0.20250510-0-live-kernel.x86_64 new file mode 100644 index 0000000..86ccd1e --- /dev/null +++ b/data/okd/installer_image/scos-9.0.20250510-0-live-kernel.x86_64 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dceac0b7809536dea5ff109d231b487a2be4cad742e1152c1268cd800dd6450b +size 14968872 diff --git a/data/okd/installer_image/scos-9.0.20250510-0-live-rootfs.x86_64.img b/data/okd/installer_image/scos-9.0.20250510-0-live-rootfs.x86_64.img new file mode 100644 index 0000000..5b297fa --- /dev/null +++ b/data/okd/installer_image/scos-9.0.20250510-0-live-rootfs.x86_64.img @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:13469a5a76029ad4793e81ca3b7527c3ecce50e8783c7ecd88c08397b4729595 +size 1071223296 diff --git a/data/okd/installer_image/scos-live-initramfs.x86_64.img b/data/okd/installer_image/scos-live-initramfs.x86_64.img new file mode 120000 index 0000000..1bd01a0 --- /dev/null +++ b/data/okd/installer_image/scos-live-initramfs.x86_64.img @@ -0,0 +1 @@ +scos-9.0.20250510-0-live-initramfs.x86_64.img \ No newline at end of file diff --git a/data/okd/installer_image/scos-live-kernel.x86_64 b/data/okd/installer_image/scos-live-kernel.x86_64 new file mode 120000 index 0000000..8a83a5c --- /dev/null +++ b/data/okd/installer_image/scos-live-kernel.x86_64 @@ -0,0 +1 @@ +scos-9.0.20250510-0-live-kernel.x86_64 \ No newline at end of file diff --git a/data/okd/installer_image/scos-live-rootfs.x86_64.img b/data/okd/installer_image/scos-live-rootfs.x86_64.img new file mode 120000 index 0000000..ae3a74b --- /dev/null +++ b/data/okd/installer_image/scos-live-rootfs.x86_64.img @@ -0,0 +1 @@ +scos-9.0.20250510-0-live-rootfs.x86_64.img \ No newline at end of file diff --git a/examples/nanodc/src/main.rs b/examples/nanodc/src/main.rs index aa355a9..993a8fe 100644 --- a/examples/nanodc/src/main.rs +++ b/examples/nanodc/src/main.rs @@ -129,6 +129,7 @@ async fn main() { "./data/watchguard/pxe-http-files".to_string(), )), files: vec![], + remote_path: None, }; let kickstart_filename = "inventory.kickstart".to_string(); diff --git a/examples/okd_installation/env.sh b/examples/okd_installation/env.sh new file mode 100644 index 0000000..2df3da6 --- /dev/null +++ b/examples/okd_installation/env.sh @@ -0,0 +1,4 @@ +export HARMONY_SECRET_NAMESPACE=example-vms +export HARMONY_SECRET_STORE=file +export HARMONY_DATABASE_URL=sqlite://harmony_vms.sqlite RUST_LOG=info +export RUST_LOG=info diff --git a/examples/okd_installation/src/topology.rs b/examples/okd_installation/src/topology.rs index 3c7de8e..8a78c93 100644 --- a/examples/okd_installation/src/topology.rs +++ b/examples/okd_installation/src/topology.rs @@ -51,7 +51,7 @@ pub async fn get_topology() -> HAClusterTopology { dns_server: opnsense.clone(), control_plane: vec![LogicalHost { ip: ip!("192.168.1.20"), - name: "cp0".to_string(), + name: "master".to_string(), }], bootstrap_host: LogicalHost { ip: ip!("192.168.1.20"), diff --git a/examples/opnsense/src/main.rs b/examples/opnsense/src/main.rs index 465b0fa..298e25f 100644 --- a/examples/opnsense/src/main.rs +++ b/examples/opnsense/src/main.rs @@ -85,6 +85,7 @@ async fn main() { "./data/watchguard/pxe-http-files".to_string(), )), files: vec![], + remote_path: None, }; harmony_tui::run( diff --git a/harmony/src/domain/config/secret.rs b/harmony/src/domain/config/secret.rs index f334b75..0253869 100644 --- a/harmony/src/domain/config/secret.rs +++ b/harmony/src/domain/config/secret.rs @@ -14,3 +14,7 @@ pub struct SshKeyPair { pub public: String, } +#[derive(Secret, Serialize, Deserialize, Debug, PartialEq)] +pub struct RedhatSecret { + pub pull_secret: String, +} diff --git a/harmony/src/domain/interpret/mod.rs b/harmony/src/domain/interpret/mod.rs index 737bf28..4f1f209 100644 --- a/harmony/src/domain/interpret/mod.rs +++ b/harmony/src/domain/interpret/mod.rs @@ -142,6 +142,12 @@ impl From for InterpretError { } } +impl From for InterpretError { + fn from(value: harmony_secret::SecretStoreError) -> Self { + InterpretError::new(format!("Interpret error : {value}")) + } +} + impl From for InterpretError { fn from(value: ExecutorError) -> Self { Self { diff --git a/harmony/src/domain/topology/ha_cluster.rs b/harmony/src/domain/topology/ha_cluster.rs index 4fac60b..e277b19 100644 --- a/harmony/src/domain/topology/ha_cluster.rs +++ b/harmony/src/domain/topology/ha_cluster.rs @@ -69,6 +69,26 @@ impl K8sclient for HAClusterTopology { } impl HAClusterTopology { + // TODO this is a hack to avoid refactoring + pub fn get_cluster_name(&self) -> String { + self.domain_name + .split(".") + .next() + .expect("Cluster domain name must not be empty") + .to_string() + } + + pub fn get_cluster_base_domain(&self) -> String { + let base_domain = self + .domain_name + .strip_prefix(&self.get_cluster_name()) + .expect("cluster domain must start with cluster name"); + base_domain + .strip_prefix(".") + .unwrap_or(base_domain) + .to_string() + } + pub fn autoload() -> Self { let dummy_infra = Arc::new(DummyInfra {}); let dummy_host = LogicalHost { @@ -217,8 +237,8 @@ impl Router for HAClusterTopology { #[async_trait] impl HttpServer for HAClusterTopology { - async fn serve_files(&self, url: &Url) -> Result<(), ExecutorError> { - self.http_server.serve_files(url).await + async fn serve_files(&self, url: &Url, remote_path: &Option) -> Result<(), ExecutorError> { + self.http_server.serve_files(url, remote_path).await } async fn serve_file_content(&self, file: &FileContent) -> Result<(), ExecutorError> { @@ -377,7 +397,7 @@ impl TftpServer for DummyInfra { #[async_trait] impl HttpServer for DummyInfra { - async fn serve_files(&self, _url: &Url) -> Result<(), ExecutorError> { + async fn serve_files(&self, _url: &Url, _remote_path: &Option) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn serve_file_content(&self, _file: &FileContent) -> Result<(), ExecutorError> { diff --git a/harmony/src/domain/topology/http.rs b/harmony/src/domain/topology/http.rs index cc6c1f0..d7194c4 100644 --- a/harmony/src/domain/topology/http.rs +++ b/harmony/src/domain/topology/http.rs @@ -5,7 +5,7 @@ use harmony_types::net::IpAddress; use harmony_types::net::Url; #[async_trait] pub trait HttpServer: Send + Sync { - async fn serve_files(&self, url: &Url) -> Result<(), ExecutorError>; + async fn serve_files(&self, url: &Url, remote_path: &Option) -> Result<(), ExecutorError>; async fn serve_file_content(&self, file: &FileContent) -> Result<(), ExecutorError>; fn get_ip(&self) -> IpAddress; diff --git a/harmony/src/infra/opnsense/http.rs b/harmony/src/infra/opnsense/http.rs index fa6fe7d..70bbee1 100644 --- a/harmony/src/infra/opnsense/http.rs +++ b/harmony/src/infra/opnsense/http.rs @@ -10,13 +10,21 @@ const OPNSENSE_HTTP_ROOT_PATH: &str = "/usr/local/http"; #[async_trait] impl HttpServer for OPNSenseFirewall { - async fn serve_files(&self, url: &Url) -> Result<(), ExecutorError> { + async fn serve_files( + &self, + url: &Url, + remote_path: &Option, + ) -> Result<(), ExecutorError> { let config = self.opnsense_config.read().await; info!("Uploading files from url {url} to {OPNSENSE_HTTP_ROOT_PATH}"); + let remote_upload_path = remote_path + .clone() + .map(|r| format!("{OPNSENSE_HTTP_ROOT_PATH}/{r}")) + .unwrap_or(OPNSENSE_HTTP_ROOT_PATH.to_string()); match url { Url::LocalFolder(path) => { config - .upload_files(path, OPNSENSE_HTTP_ROOT_PATH) + .upload_files(path, &remote_upload_path) .await .map_err(|e| ExecutorError::UnexpectedError(e.to_string()))?; } diff --git a/harmony/src/modules/http.rs b/harmony/src/modules/http.rs index b0d1678..8d4f8a5 100644 --- a/harmony/src/modules/http.rs +++ b/harmony/src/modules/http.rs @@ -24,9 +24,11 @@ use harmony_types::{id::Id, net::MacAddress}; /// } /// ``` #[derive(Debug, new, Clone, Serialize)] -pub struct StaticFilesHttpScore { +pub struct StaticFilesHttpScore { // TODO this should be split in two scores, one for folder and + // other for files pub folder_to_serve: Option, pub files: Vec, + pub remote_path: Option, } impl Score for StaticFilesHttpScore { @@ -54,7 +56,7 @@ impl Interpret for StaticFilesHttpInterpret { http_server.ensure_initialized().await?; // http_server.set_ip(topology.router.get_gateway()).await?; if let Some(folder) = self.score.folder_to_serve.as_ref() { - http_server.serve_files(folder).await?; + http_server.serve_files(folder, &self.score.remote_path).await?; } for f in self.score.files.iter() { @@ -105,6 +107,7 @@ impl Score for IPxeMacBootFileScore { fn create_interpret(&self) -> Box> { StaticFilesHttpScore { + remote_path: None, folder_to_serve: None, files: self .mac_address diff --git a/harmony/src/modules/okd/installation.rs b/harmony/src/modules/okd/installation.rs index 9cdf294..d245fbe 100644 --- a/harmony/src/modules/okd/installation.rs +++ b/harmony/src/modules/okd/installation.rs @@ -47,14 +47,23 @@ //! - public_domain: External wildcard/apps domain (e.g., apps.example.com). //! - internal_domain: Internal cluster domain (e.g., cluster.local or harmony.mcd). +use std::{fmt::Write, path::PathBuf, process::ExitStatus}; + use async_trait::async_trait; use derive_new::new; -use harmony_types::id::Id; -use log::{error, info, warn}; +use harmony_secret::SecretManager; +use harmony_types::{id::Id, net::Url}; +use log::{debug, error, info, warn}; use serde::{Deserialize, Serialize}; +use tokio::{ + fs::File, + io::{AsyncReadExt, AsyncWriteExt}, + process::Command, +}; use crate::{ - data::Version, + config::secret::{RedhatSecret, SshKeyPair}, + data::{FileContent, FilePath, Version}, hardware::PhysicalHost, infra::inventory::InventoryRepositoryFactory, instrumentation::{HarmonyEvent, instrument}, @@ -64,7 +73,7 @@ use crate::{ dhcp::DhcpHostBindingScore, http::{IPxeMacBootFileScore, StaticFilesHttpScore}, inventory::LaunchDiscoverInventoryAgentScore, - okd::dns::OKDDnsScore, + okd::{dns::OKDDnsScore, templates::InstallConfigYaml}, }, score::Score, topology::{HAClusterTopology, HostBinding}, @@ -113,12 +122,9 @@ impl OKDInstallationInterpret { inventory: &Inventory, topology: &HAClusterTopology, ) -> Result<(), InterpretError> { - // 1) Prepare DNS and DHCP lease registration (optional) - - // 2) Serve default iPXE + Kickstart and poll discovery - let discovery_score = OKDSetup01InventoryScore::new(); - discovery_score.interpret(inventory, topology).await?; - + OKDSetup01InventoryScore::new() + .interpret(inventory, topology) + .await?; Ok(()) } @@ -127,9 +133,9 @@ impl OKDInstallationInterpret { inventory: &Inventory, topology: &HAClusterTopology, ) -> Result<(), InterpretError> { - // Select and provision bootstrap - let bootstrap_score = OKDSetup02BootstrapScore::new(); - bootstrap_score.interpret(inventory, topology).await?; + OKDSetup02BootstrapScore::new() + .interpret(inventory, topology) + .await?; Ok(()) } @@ -201,7 +207,7 @@ impl Interpret for OKDInstallationInterpret { info!("Starting OKD installation pipeline",); - self.run_inventory_phase(inventory, topology).await?; + // self.run_inventory_phase(inventory, topology).await?; self.run_bootstrap_phase(inventory, topology).await?; @@ -407,12 +413,179 @@ impl OKDSetup02BootstrapInterpret { inventory: &Inventory, topology: &HAClusterTopology, ) -> Result<(), InterpretError> { + let okd_bin_path = PathBuf::from("./data/okd/bin"); + let okd_installation_path_str = "./data/okd/installation_files"; + let okd_images_path = &PathBuf::from("./data/okd/installer_image/"); + let okd_installation_path = &PathBuf::from(okd_installation_path_str); + + let exit_status = Command::new("mkdir") + .arg("-p") + .arg(okd_installation_path) + .spawn() + .expect("Command failed to start") + .wait() + .await + .map_err(|e| { + InterpretError::new(format!("Failed to create okd installation directory : {e}")) + })?; + if !exit_status.success() { + return Err(InterpretError::new(format!( + "Failed to create okd installation directory" + ))); + } else { + info!( + "Created OKD installation directory {}", + okd_installation_path.to_string_lossy() + ); + } + + let redhat_secret = SecretManager::get::().await?; + let ssh_key = SecretManager::get::().await?; + + let install_config_yaml = InstallConfigYaml { + cluster_name: &topology.get_cluster_name(), + cluster_domain: &topology.get_cluster_base_domain(), + pull_secret: &redhat_secret.pull_secret, + ssh_public_key: &ssh_key.public, + } + .to_string(); + + let install_config_file_path = &okd_installation_path.join("install-config.yaml"); + + self.create_file(install_config_file_path, install_config_yaml.as_bytes()) + .await?; + + let install_config_backup_extension = install_config_file_path + .extension() + .map(|e| format!("{}.bak", e.to_string_lossy())) + .unwrap_or("bak".to_string()); + + let mut install_config_backup = install_config_file_path.clone(); + install_config_backup.set_extension(install_config_backup_extension); + + self.create_file(&install_config_backup, install_config_yaml.as_bytes()) + .await?; + + info!("Creating manifest files with openshift-install"); + let output = Command::new(okd_bin_path.join("openshift-install")) + .args([ + "create", + "manifests", + "--dir", + okd_installation_path.to_str().unwrap(), + ]) + .output() + .await + .map_err(|e| InterpretError::new(format!("Failed to create okd manifest : {e}")))?; + let stdout = String::from_utf8(output.stdout).unwrap(); + info!("openshift-install stdout :\n\n{}", stdout); + let stderr = String::from_utf8(output.stderr).unwrap(); + info!("openshift-install stderr :\n\n{}", stderr); + info!("openshift-install exit status : {}", output.status); + if !output.status.success() { + return Err(InterpretError::new(format!( + "Failed to create okd manifest, exit code {} : {}", + output.status, stderr + ))); + } + + info!("Creating ignition files with openshift-install"); + let output = Command::new(okd_bin_path.join("openshift-install")) + .args([ + "create", + "ignition-configs", + "--dir", + okd_installation_path.to_str().unwrap(), + ]) + .output() + .await + .map_err(|e| { + InterpretError::new(format!("Failed to create okd ignition config : {e}")) + })?; + let stdout = String::from_utf8(output.stdout).unwrap(); + info!("openshift-install stdout :\n\n{}", stdout); + let stderr = String::from_utf8(output.stderr).unwrap(); + info!("openshift-install stderr :\n\n{}", stderr); + info!("openshift-install exit status : {}", output.status); + if !output.status.success() { + return Err(InterpretError::new(format!( + "Failed to create okd manifest, exit code {} : {}", + output.status, stderr + ))); + } + + let ignition_files_http_path = PathBuf::from("okd_ignition_files"); + let prepare_file_content = async |filename: &str| -> Result { + let local_path = okd_installation_path.join(filename); + let remote_path = ignition_files_http_path.join(filename); + + info!( + "Preparing file content for local file : {} to remote : {}", + local_path.to_string_lossy(), + remote_path.to_string_lossy() + ); + + let content = tokio::fs::read_to_string(&local_path).await.map_err(|e| { + InterpretError::new(format!( + "Could not read file content {} : {e}", + local_path.to_string_lossy() + )) + })?; + + Ok(FileContent { + path: FilePath::Relative(remote_path.to_string_lossy().to_string()), + content, + }) + }; + StaticFilesHttpScore { + remote_path: None, folder_to_serve: None, - files: todo!(), + files: vec![ + prepare_file_content("bootstrap.ign").await?, + prepare_file_content("master.ign").await?, + prepare_file_content("worker.ign").await?, + prepare_file_content("metadata.json").await?, + ], } .interpret(inventory, topology) .await?; + + let run_command = + async |cmd: &str, args: Vec<&str>| -> Result { + let output = Command::new(cmd).args(&args).output().await.map_err(|e| { + InterpretError::new(format!("Failed to launch command {cmd} : {e}")) + })?; + let stdout = String::from_utf8(output.stdout.clone()).unwrap(); + info!("{cmd} stdout :\n\n{}", stdout); + let stderr = String::from_utf8(output.stderr.clone()).unwrap(); + info!("{cmd} stderr :\n\n{}", stderr); + info!("{cmd} exit status : {}", output.status); + if !output.status.success() { + return Err(InterpretError::new(format!( + "Command execution failed, exit code {} : {} {}", + output.status, + cmd, + args.join(" ") + ))); + } + Ok(output) + }; + + // ignition_files_http_path // = PathBuf::from("okd_ignition_files"); + let scos_http_path = PathBuf::from("scos"); + info!( + r#"Uploading images, they can be refreshed with a command similar to this one: openshift-install coreos print-stream-json | grep -Eo '"https.*(kernel.|initramfs.|rootfs.)\w+(\.img)?"' | grep x86_64 | xargs -n 1 curl -LO"# + ); + StaticFilesHttpScore { + folder_to_serve: Some(Url::LocalFolder(okd_images_path.to_string_lossy().to_string())), + remote_path: Some(scos_http_path.to_string_lossy().to_string()), + files: vec![], + } + .interpret(inventory, topology) + .await?; + + todo!("What's up next?") } async fn configure_host_binding( @@ -465,12 +638,28 @@ impl OKDSetup02BootstrapInterpret { async fn reboot_target(&self) -> Result<(), InterpretError> { // Placeholder: ssh reboot using the inventory ephemeral key info!("[Bootstrap] Rebooting bootstrap node via SSH"); - Ok(()) + todo!("[Bootstrap] Rebooting bootstrap node via SSH") } async fn wait_for_bootstrap_complete(&self) -> Result<(), InterpretError> { // Placeholder: wait-for bootstrap-complete info!("[Bootstrap] Waiting for bootstrap-complete …"); + todo!("[Bootstrap] Waiting for bootstrap-complete …") + } + + async fn create_file(&self, path: &PathBuf, content: &[u8]) -> Result<(), InterpretError> { + let mut install_config_file = File::create(path).await.map_err(|e| { + InterpretError::new(format!( + "Could not create file {} : {e}", + path.to_string_lossy() + )) + })?; + install_config_file.write(content).await.map_err(|e| { + InterpretError::new(format!( + "Could not write file {} : {e}", + path.to_string_lossy() + )) + })?; Ok(()) } } diff --git a/harmony/src/modules/okd/ipxe.rs b/harmony/src/modules/okd/ipxe.rs index 7964093..968ec41 100644 --- a/harmony/src/modules/okd/ipxe.rs +++ b/harmony/src/modules/okd/ipxe.rs @@ -71,6 +71,7 @@ impl Interpret f 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 // diff --git a/harmony/src/modules/okd/mod.rs b/harmony/src/modules/okd/mod.rs index b5ba462..96e45cd 100644 --- a/harmony/src/modules/okd/mod.rs +++ b/harmony/src/modules/okd/mod.rs @@ -6,3 +6,4 @@ pub mod installation; pub mod ipxe; pub mod load_balancer; pub mod upgrade; +pub mod templates; diff --git a/harmony/src/modules/okd/templates.rs b/harmony/src/modules/okd/templates.rs new file mode 100644 index 0000000..da7524f --- /dev/null +++ b/harmony/src/modules/okd/templates.rs @@ -0,0 +1,10 @@ +use askama::Template; + +#[derive(Template)] +#[template(path = "okd/install-config.yaml.j2")] +pub struct InstallConfigYaml<'a> { + pub cluster_domain: &'a str, + pub pull_secret: &'a str, + pub ssh_public_key: &'a str, + pub cluster_name: &'a str, +} diff --git a/harmony/templates/okd/install-config.yaml.j2 b/harmony/templates/okd/install-config.yaml.j2 new file mode 100644 index 0000000..91ce3e7 --- /dev/null +++ b/harmony/templates/okd/install-config.yaml.j2 @@ -0,0 +1,24 @@ +# Built from https://docs.okd.io/latest/installing/installing_bare_metal/upi/installing-bare-metal.html#installation-bare-metal-config-yaml_installing-bare-metal +apiVersion: v1 +baseDomain: {{ cluster_domain }} +compute: +- hyperthreading: Enabled + name: worker + replicas: 0 +controlPlane: + hyperthreading: Enabled + name: master + replicas: 3 +metadata: + name: {{ cluster_name }} +networking: + clusterNetwork: + - cidr: 10.128.0.0/14 + hostPrefix: 23 + networkType: OVNKubernetes + serviceNetwork: + - 172.30.0.0/16 +platform: + none: {} +pullSecret: '{{ pull_secret|safe }}' +sshKey: '{{ ssh_public_key }}' diff --git a/harmony_secret/src/store/local_file.rs b/harmony_secret/src/store/local_file.rs index c277335..b71e7dc 100644 --- a/harmony_secret/src/store/local_file.rs +++ b/harmony_secret/src/store/local_file.rs @@ -29,12 +29,20 @@ impl SecretStore for LocalFileSecretStore { file_path.display() ); - tokio::fs::read(&file_path) - .await - .map_err(|_| SecretStoreError::NotFound { - namespace: ns.to_string(), - key: key.to_string(), - }) + let content = + tokio::fs::read(&file_path) + .await + .map_err(|_| SecretStoreError::NotFound { + namespace: ns.to_string(), + key: key.to_string(), + })?; + info!( + "Sum of all vec get {ns} {key} {:?}", + content + .iter() + .fold(0, |acc: u64, val: &u8| { acc + *val as u64 }) + ); + Ok(content) } async fn set_raw(&self, ns: &str, key: &str, val: &[u8]) -> Result<(), SecretStoreError> { @@ -56,6 +64,12 @@ impl SecretStore for LocalFileSecretStore { .map_err(|e| SecretStoreError::Store(Box::new(e)))?; } + info!( + "Sum of all vec set {ns} {key} {:?}", + val.iter() + .fold(0, |acc: u64, val: &u8| { acc + *val as u64 }) + ); + tokio::fs::write(&file_path, val) .await .map_err(|e| SecretStoreError::Store(Box::new(e)))