Skip to content

Commit

Permalink
wip: move molds module (again)
Browse files Browse the repository at this point in the history
  • Loading branch information
cilki committed Dec 23, 2023
1 parent f38ab97 commit 15e1219
Show file tree
Hide file tree
Showing 55 changed files with 205 additions and 233 deletions.
2 changes: 1 addition & 1 deletion goldboot-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ fn impl_prompt(ast: &syn::DeriveInput) -> TokenStream {
impl Prompt for #name {
fn prompt(
&mut self,
config: &BuildConfig,
_: &Foundry,
theme: impl dialoguer::theme::Theme,
) -> anyhow::Result<()> {
todo!()
Expand Down
1 change: 1 addition & 0 deletions goldboot/src/cli/cmd/image.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::library::ImageLibrary;
use anyhow::Result;
use chrono::TimeZone;
use console::Style;
Expand Down
2 changes: 1 addition & 1 deletion goldboot/src/cli/cmd/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use goldboot_image::ImageArch;
use std::{error::Error, path::Path};
use strum::IntoEnumIterator;

use crate::foundry::{mold::builtins::ImageMold, Foundry, FoundryConfig};
use crate::foundry::{molds::ImageMold, Foundry, FoundryConfig};

fn print_banner() {
if console::colors_enabled() {
Expand Down
13 changes: 7 additions & 6 deletions goldboot/src/cli/prompt.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use anyhow::Result;
use dialoguer::theme::Theme;

use crate::foundry::Foundry;

/// Prompt the user for additional information on the command line.
pub trait Prompt {
fn prompt(
&mut self,
config: &BuildConfig,
theme: Box<dyn dialoguer::theme::Theme>,
) -> Result<()>;
fn prompt(&mut self, foundry: &Foundry, theme: Box<dyn Theme>) -> Result<()>;
}

/// Prompt the user for additional information on the command line.
pub trait PromptNew {
fn prompt(config: &BuildConfig, theme: Box<dyn dialoguer::theme::Theme>) -> Result<Self>
fn prompt(foundry: &Foundry, theme: Box<dyn Theme>) -> Result<Self>
where
Self: Sized;
}
8 changes: 3 additions & 5 deletions goldboot/src/foundry/fabricators/ansible.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::foundry::Foundry;
use crate::{cli::prompt::Prompt, foundry::ssh::SshConnection};
use anyhow::bail;
use anyhow::Result;
use dialoguer::theme::Theme;
use log::info;
use serde::{Deserialize, Serialize};
use std::{error::Error, path::Path, process::Command};
Expand Down Expand Up @@ -46,11 +48,7 @@ impl Ansible {
}

impl Prompt for Ansible {
fn prompt(
&mut self,
config: &BuildConfig,
theme: Box<dyn dialoguer::theme::Theme>,
) -> Result<()> {
fn prompt(&mut self, _: &Foundry, theme: Box<dyn Theme>) -> Result<()> {
self.playbook = dialoguer::Input::with_theme(&theme)
.with_prompt("Enter the playbook path relative to the current directory")
.interact()?;
Expand Down
8 changes: 3 additions & 5 deletions goldboot/src/foundry/fabricators/exe.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use super::Fabricate;
use crate::foundry::Foundry;
use crate::{cli::prompt::Prompt, foundry::ssh::SshConnection};
use anyhow::bail;
use anyhow::Result;
use dialoguer::theme::Theme;
use log::info;
use serde::{Deserialize, Serialize};
use std::{error::Error, path::Path};
Expand All @@ -26,11 +28,7 @@ impl Fabricate for HostExecutable {
}

impl Prompt for HostExecutable {
fn prompt(
&mut self,
config: &BuildConfig,
theme: Box<dyn dialoguer::theme::Theme>,
) -> Result<()> {
fn prompt(&mut self, _: &Foundry, theme: Box<dyn Theme>) -> Result<()> {
self.path = dialoguer::Input::with_theme(&theme)
.with_prompt("Enter the script path relative to the current directory")
.interact()?;
Expand Down
91 changes: 34 additions & 57 deletions goldboot/src/foundry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ use validator::Validate;

use crate::{foundry::sources::SourceCache, library::ImageLibrary};

use self::{fabricators::Fabricator, mold::builtins::ImageMold, sources::Source};
use self::{fabricators::Fabricator, molds::ImageMold, sources::Source};

pub mod fabricators;
pub mod mold;
pub mod molds;
pub mod options;
pub mod ovmf;
pub mod qemu;
pub mod sources;
Expand All @@ -31,49 +32,49 @@ pub mod vnc;
#[derive(Clone, Serialize, Deserialize, Validate, Default, Debug)]
#[validate(schema(function = "crate::foundry::custom_foundry_validator"))]
pub struct Foundry {
/// The image name
#[validate(length(min = 1, max = 64))]
pub name: String,
/// The system architecture
#[serde(flatten)]
pub arch: ImageArch,

/// When set, the run will pause before each step in the boot sequence
pub debug: bool,

/// An image description
#[validate(length(max = 4096))]
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,

/// The system architecture
#[serde(flatten)]
pub arch: ImageArch,
#[validate(length(min = 1))]
pub fabricators: Option<Vec<Fabricator>>,

/// The amount of memory to allocate to the VM
#[serde(skip_serializing_if = "Option::is_none")]
pub memory: Option<String>,

pub mold: Option<ImageMold>,

/// The image name
#[validate(length(min = 1, max = 64))]
pub name: String,

#[serde(skip_serializing_if = "Option::is_none")]
pub nvme: Option<bool>,

/// The path to an OVMF.fd file
pub ovmf_path: String,

/// The encryption password. This value can alternatively be specified on
/// the command line and will be cleared before the config is included in
/// an image file.
#[serde(skip_serializing_if = "Option::is_none")]
pub password: Option<String>,

// #[validate(length(min = 2))]
// pub alloy: Vec<Element>,
pub source: Option<Source>,

pub mold: Option<ImageMold>,

#[validate(length(min = 1))]
pub fabricators: Option<Vec<Fabricator>>,

/// The path to an OVMF.fd file
pub ovmf_path: String,

/// Whether screenshots will be generated during the run for debugging
pub record: bool,

/// When set, the run will pause before each step in the boot sequence
pub debug: bool,
// #[validate(length(min = 2))]
// pub alloy: Vec<Element>,
pub source: Option<Source>,
}

/// Handles more sophisticated validation of a [`Foundry`].
Expand All @@ -98,13 +99,21 @@ impl Foundry {
// Determine image path
let image_path = tmp.path().join("image.gb").to_string_lossy().to_string();

// Unpack included firmware
let ovmf_path = tmp.path().join("OVMF.fd").to_string_lossy().to_string();

crate::ovmf::write_to(&self.config.arch, &ovmf_path)?;

Check failure on line 105 in goldboot/src/foundry/mod.rs

View workflow job for this annotation

GitHub Actions / Build Windows

failed to resolve: could not find `ovmf` in the crate root

Check failure on line 105 in goldboot/src/foundry/mod.rs

View workflow job for this annotation

GitHub Actions / Build macOS

failed to resolve: could not find `ovmf` in the crate root

Check failure on line 105 in goldboot/src/foundry/mod.rs

View workflow job for this annotation

GitHub Actions / Build Linux

failed to resolve: could not find `ovmf` in the crate root

FoundryWorker {
tmp,
start_time: None,
end_time: None,
config,
record,
debug,
ssh_port: rand::thread_rng().gen_range(10000..11000),
vnc_port: if self.debug {
5900
} else {
rand::thread_rng().gen_range(5900..5999)
},
image_path,
}
}
Expand Down Expand Up @@ -172,38 +181,6 @@ impl Foundry {
}
}

impl BuildJob {
/// Create a new generic build context.
fn new_worker(&self, template: Box<dyn BuildTemplate>) -> Result<BuildWorker> {
// Obtain a temporary directory
let tmp = tempfile::tempdir().unwrap();

// Determine image path
let image_path = tmp.path().join("image.qcow2").to_string_lossy().to_string();

// Unpack included firmware
let ovmf_path = tmp.path().join("OVMF.fd").to_string_lossy().to_string();

crate::ovmf::write_to(&self.config.arch, &ovmf_path)?;

Ok(BuildWorker {
tmp,
image_path,
ovmf_path,
template,
ssh_port: rand::thread_rng().gen_range(10000..11000),
vnc_port: if self.debug {
5900
} else {
rand::thread_rng().gen_range(5900..5999)
},
config: self.config.clone(),
record: self.record,
debug: self.debug,
})
}
}

/// Manages the image casting process. Multiple workers can run in parallel
/// to speed up multiboot configurations.
pub struct FoundryWorker {
Expand Down
2 changes: 0 additions & 2 deletions goldboot/src/foundry/mold/mod.rs

This file was deleted.

4 changes: 0 additions & 4 deletions goldboot/src/foundry/mold/options/mod.rs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use super::CastImage;
use crate::foundry::mold::options::hostname::Hostname;
use crate::cli::prompt::Prompt;
use crate::foundry::options::hostname::Hostname;
use crate::foundry::options::unix_account::RootPassword;
use crate::foundry::qemu::QemuBuilder;
use crate::foundry::Foundry;
use crate::wait;
use crate::{
enter,
Expand All @@ -8,28 +12,27 @@ use crate::{
};
use anyhow::bail;
use anyhow::Result;
use goldboot_image::ImageArch;
use dialoguer::theme::Theme;
use log::{debug, info};
use serde::{Deserialize, Serialize};
use std::{
error::Error,
io::{BufRead, BufReader},
};
use std::io::{BufRead, BufReader};
use validator::Validate;

/// This `Mold` produces an [Arch Linux](https://archlinux.org) image.
#[derive(Clone, Serialize, Deserialize, Validate, Debug)]
pub struct ArchLinux {
pub root_password: Option<RootPassword>,
pub packages: Option<Packages>,
pub mirrorlist: Option<Mirrorlist>,
pub hostname: Option<Hostname>,
pub mirrorlist: Option<ArchLinuxMirrorlist>,
pub packages: Option<ArchLinuxPackages>,
pub root_password: Option<RootPassword>,
}

impl Default for ArchLinux {
fn default() -> Self {
Self {
root_password: RootPassword { plaintext: "root" },
root_password: Some(RootPassword {
plaintext: "root".to_string(),
}),
packages: None,
mirrorlist: None,
hostname: Some(Hostname {
Expand All @@ -40,11 +43,8 @@ impl Default for ArchLinux {
}

impl CastImage for ArchLinux {

Check failure on line 45 in goldboot/src/foundry/molds/arch_linux/mod.rs

View workflow job for this annotation

GitHub Actions / Build Windows

the trait bound `ArchLinux: prompt::Prompt` is not satisfied

Check failure on line 45 in goldboot/src/foundry/molds/arch_linux/mod.rs

View workflow job for this annotation

GitHub Actions / Build macOS

the trait bound `ArchLinux: prompt::Prompt` is not satisfied

Check failure on line 45 in goldboot/src/foundry/molds/arch_linux/mod.rs

View workflow job for this annotation

GitHub Actions / Build Linux

the trait bound `ArchLinux: prompt::Prompt` is not satisfied
fn cast(&self, context: &FoundryWorker) -> Result<()> {
let mut qemuargs = QemuArgs::new(&context);

// Start VM
let mut qemu = qemuargs.start_process()?;
fn cast(&self, worker: &FoundryWorker) -> Result<()> {
let mut qemu = QemuBuilder::new(&worker).start()?;

// Send boot command
#[rustfmt::skip]
Expand All @@ -63,7 +63,7 @@ impl CastImage for ArchLinux {
])?;

// Wait for SSH
let mut ssh = qemu.ssh_wait(context.ssh_port, "root", &self.root_password)?;
let mut ssh = qemu.ssh("root", &self.root_password)?;

// Run install script
info!("Running base installation");
Expand All @@ -90,13 +90,13 @@ impl CastImage for ArchLinux {

/// This provisioner configures the Archlinux mirror list.
#[derive(Clone, Serialize, Deserialize, Validate, Debug)]
pub struct Mirrorlist {
pub struct ArchLinuxMirrorlist {
pub mirrors: Vec<String>,
}

//https://archlinux.org/mirrorlist/?country=US&protocol=http&protocol=https&ip_version=4

impl Default for Mirrorlist {
impl Default for ArchLinuxMirrorlist {
fn default() -> Self {
Self {
mirrors: vec![
Expand All @@ -108,12 +108,8 @@ impl Default for Mirrorlist {
}
}

impl Prompt for Mirrorlist {
fn prompt(
&mut self,
config: &BuildConfig,
theme: Box<dyn dialoguer::theme::Theme>,
) -> Result<()> {
impl Prompt for ArchLinuxMirrorlist {
fn prompt(&mut self, _: &Foundry, theme: Box<dyn Theme>) -> Result<()> {
// Prompt mirror list
{
let mirror_index = dialoguer::Select::with_theme(&theme)
Expand All @@ -129,7 +125,7 @@ impl Prompt for Mirrorlist {
}
}

impl Mirrorlist {
impl ArchLinuxMirrorlist {
pub fn format_mirrorlist(&self) -> String {
self.mirrors
.iter()
Expand Down Expand Up @@ -160,6 +156,10 @@ fn fetch_latest_iso() -> Result<Source> {
bail!("Failed to request latest ISO");
}

pub struct ArchLinuxPackages {
packages: Vec<String>,
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::cli::prompt::Prompt;
use crate::{cli::prompt::Prompt, foundry::Foundry};
use anyhow::Result;
use dialoguer::theme::Theme;
use serde::{Deserialize, Serialize};
use validator::Validate;

Expand All @@ -19,14 +20,10 @@ impl Default for Hostname {
}

impl Prompt for Hostname {
fn prompt(
&mut self,
config: &BuildConfig,
theme: Box<dyn dialoguer::theme::Theme>,
) -> Result<()> {
fn prompt(&mut self, foundry: &Foundry, theme: Box<dyn Theme>) -> Result<()> {
self.hostname = dialoguer::Input::with_theme(&theme)
.with_prompt("Enter network hostname")
.default(config.name.clone())
.default(foundry.name.clone())
.interact()?;

self.validate()?;
Expand Down
Loading

0 comments on commit 15e1219

Please sign in to comment.