wip mac work

This commit is contained in:
Ana Hobden 2022-10-17 16:00:16 -07:00
parent 64e7423a0a
commit a29baa2b33
5 changed files with 299 additions and 22 deletions

View file

@ -0,0 +1,234 @@
use serde::Serialize;
use std::path::{Path, PathBuf};
use crate::actions::base::{
darwin::{
BootstrapVolume, BootstrapVolumeError, CreateSyntheticObjects, CreateSyntheticObjectsError,
CreateVolume, CreateVolumeError, EnableOwnership, EnableOwnershipError, EncryptVolume,
EncryptVolumeError, UnmountVolume, UnmountVolumeError,
},
CreateDirectory, CreateDirectoryError, CreateFile, CreateFileError, CreateOrAppendFile,
CreateOrAppendFileError,
};
use crate::actions::{Action, ActionDescription, ActionState, Actionable};
const NIX_VOLUME_MOUNTD_DEST: &str = "/Library/LaunchDaemons/org.nixos.darwin-store.plist";
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct CreateApfsVolume {
disk: PathBuf,
name: String,
case_sensitive: bool,
encrypt: Option<String>,
create_or_append_synthetic_conf: CreateOrAppendFile,
create_synthetic_objects: CreateSyntheticObjects,
unmount_volume: UnmountVolume,
create_volume: CreateVolume,
create_or_append_fstab: CreateOrAppendFile,
encrypt_volume: Option<EncryptVolume>,
bootstrap_volume: BootstrapVolume,
enable_ownership: EnableOwnership,
action_state: ActionState,
}
impl CreateApfsVolume {
#[tracing::instrument(skip_all)]
pub async fn plan(
disk: impl AsRef<Path>,
name: String,
case_sensitive: bool,
encrypt: Option<String>,
) -> Result<Self, CreateApfsVolumeError> {
let disk = disk.as_ref();
let create_or_append_synthetic_conf = CreateOrAppendFile::plan(
"/etc/synthetic.conf",
"root".into(),
"wheel".into(),
0o0655,
"nix".into(),
)
.await?;
let create_synthetic_objects = CreateSyntheticObjects::plan().await?;
let unmount_volume =
UnmountVolume::plan(disk, name.clone(), case_sensitive, encrypt).await?;
let create_volume = CreateVolume::plan(disk, name.clone(), case_sensitive, encrypt).await?;
let create_or_append_fstab = CreateOrAppendFile::plan(
"/etc/fstab",
"root".into(),
"root".into(),
0o0655,
"NAME={name} /nix apfs rw,noauto,nobrowse,suid,owners".into(),
)
.await?;
let encrypt_volume = if let Some(password) = encrypt {
Some(EncryptVolume::plan(disk, password).await)
} else {
None
};
let bootstrap_volume = BootstrapVolume::plan(NIX_VOLUME_MOUNTD_DEST).await?;
let enable_ownership = EnableOwnership::plan("/nix").await?;
Ok(Self {
disk: disk.to_path_buf(),
name,
case_sensitive,
encrypt,
create_or_append_synthetic_conf,
create_synthetic_objects,
unmount_volume,
create_volume,
create_or_append_fstab,
encrypt_volume,
bootstrap_volume,
enable_ownership,
action_state: ActionState::Uncompleted,
})
}
}
#[async_trait::async_trait]
impl Actionable for CreateApfsVolume {
type Error = CreateApfsVolumeError;
fn describe_execute(&self) -> Vec<ActionDescription> {
let Self {
disk,
name,
case_sensitive,
encrypt,
create_or_append_synthetic_conf,
create_synthetic_objects,
unmount_volume,
create_volume,
create_or_append_fstab,
encrypt_volume,
bootstrap_volume,
enable_ownership,
action_state: _,
} = &self;
if self.action_state == ActionState::Completed {
vec![]
} else {
vec![ActionDescription::new(
format!("Create an APFS volume", destination.display()),
vec![format!(
"Create a writable, persistent systemd system extension.",
)],
)]
}
}
#[tracing::instrument(skip_all, fields(destination,))]
async fn execute(&mut self) -> Result<(), Self::Error> {
let Self {
disk,
name,
case_sensitive,
encrypt,
create_or_append_synthetic_conf,
create_synthetic_objects,
unmount_volume,
create_volume,
create_or_append_fstab,
encrypt_volume,
bootstrap_volume,
enable_ownership,
action_state,
} = self;
if *action_state == ActionState::Completed {
tracing::trace!("Already completed: Creating sysext");
return Ok(());
}
tracing::debug!("Creating sysext");
for create_directory in create_directories {
create_directory.execute().await?;
}
create_extension_release.execute().await?;
create_bind_mount_unit.execute().await?;
tracing::trace!("Created sysext");
*action_state = ActionState::Completed;
Ok(())
}
fn describe_revert(&self) -> Vec<ActionDescription> {
let Self {
disk,
name,
case_sensitive,
encrypt,
create_or_append_synthetic_conf,
create_synthetic_objects,
unmount_volume,
create_volume,
create_or_append_fstab,
encrypt_volume,
bootstrap_volume,
enable_ownership,
action_state: _,
} = &self;
if self.action_state == ActionState::Uncompleted {
vec![]
} else {
vec![ActionDescription::new(
format!("Remove the sysext located at `{}`", destination.display()),
vec![],
)]
}
}
#[tracing::instrument(skip_all, fields(destination,))]
async fn revert(&mut self) -> Result<(), Self::Error> {
let Self {
disk,
name,
case_sensitive,
encrypt,
create_or_append_synthetic_conf,
create_synthetic_objects,
unmount_volume,
create_volume,
create_or_append_fstab,
encrypt_volume,
bootstrap_volume,
enable_ownership,
action_state,
} = self;
if *action_state == ActionState::Uncompleted {
tracing::trace!("Already reverted: Removing sysext");
return Ok(());
}
tracing::debug!("Removing sysext");
create_bind_mount_unit.revert().await?;
create_extension_release.revert().await?;
for create_directory in create_directories.iter_mut().rev() {
create_directory.revert().await?;
}
tracing::trace!("Removed sysext");
*action_state = ActionState::Uncompleted;
Ok(())
}
}
impl From<CreateApfsVolume> for Action {
fn from(v: CreateApfsVolume) -> Self {
Action::CreateApfsVolume(v)
}
}
#[derive(Debug, thiserror::Error, Serialize)]
pub enum CreateApfsVolumeError {
#[error(transparent)]
CreateOrAppendFile(#[from] CreateOrAppendFileError),
}

View file

@ -0,0 +1,2 @@
mod create_apfs_volume;
pub use create_apfs_volume::{CreateApfsVolume, CreateApfsVolumeError};

View file

@ -5,6 +5,7 @@ mod configure_shell_profile;
mod create_nix_tree;
mod create_systemd_sysext;
mod create_users_and_group;
pub mod darwin;
mod place_channel_configuration;
mod place_nix_configuration;
mod provision_nix;

View file

@ -10,6 +10,7 @@ use base::{
SystemdSysextMergeError,
};
use meta::{
darwin::{CreateApfsVolume, CreateApfsVolumeError},
ConfigureNix, ConfigureNixError, ConfigureShellProfile, ConfigureShellProfileError,
CreateNixTree, CreateNixTreeError, CreateSystemdSysext, CreateSystemdSysextError,
CreateUsersAndGroup, CreateUsersAndGroupError, PlaceChannelConfiguration,
@ -56,26 +57,27 @@ impl ActionDescription {
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub enum Action {
ConfigureNixDaemonService(ConfigureNixDaemonService),
ConfigureNix(ConfigureNix),
ConfigureNixDaemonService(ConfigureNixDaemonService),
ConfigureShellProfile(ConfigureShellProfile),
CreateApfsVolume(CreateApfsVolume),
CreateDirectory(CreateDirectory),
CreateSystemdSysext(CreateSystemdSysext),
CreateFile(CreateFile),
CreateGroup(CreateGroup),
CreateOrAppendFile(CreateOrAppendFile),
CreateNixTree(CreateNixTree),
CreateOrAppendFile(CreateOrAppendFile),
CreateSystemdSysext(CreateSystemdSysext),
CreateUser(CreateUser),
CreateUsersAndGroup(CreateUsersAndGroup),
FetchNix(FetchNix),
MoveUnpackedNix(MoveUnpackedNix),
PlaceChannelConfiguration(PlaceChannelConfiguration),
PlaceNixConfiguration(PlaceNixConfiguration),
ProvisionNix(ProvisionNix),
SetupDefaultProfile(SetupDefaultProfile),
StartNixDaemon(StartNixDaemon),
StartSystemdUnit(StartSystemdUnit),
SystemdSysextMerge(SystemdSysextMerge),
ProvisionNix(ProvisionNix),
}
#[derive(Debug, thiserror::Error, serde::Serialize)]
@ -87,6 +89,8 @@ pub enum ActionError {
#[error("Attempted to revert an already reverted action")]
AlreadyReverted(Action),
#[error(transparent)]
CreateApfsVolume(#[from] CreateApfsVolumeError),
#[error(transparent)]
ConfigureNixDaemonService(#[from] ConfigureNixDaemonServiceError),
#[error(transparent)]
ConfigureNix(#[from] ConfigureNixError),
@ -133,102 +137,106 @@ impl Actionable for Action {
type Error = ActionError;
fn describe_execute(&self) -> Vec<ActionDescription> {
match self {
Action::ConfigureNixDaemonService(i) => i.describe_execute(),
Action::ConfigureNix(i) => i.describe_execute(),
Action::ConfigureNixDaemonService(i) => i.describe_execute(),
Action::ConfigureShellProfile(i) => i.describe_execute(),
Action::CreateApfsVolume(i) => i.describe_execute(),
Action::CreateDirectory(i) => i.describe_execute(),
Action::CreateSystemdSysext(i) => i.describe_execute(),
Action::CreateFile(i) => i.describe_execute(),
Action::CreateGroup(i) => i.describe_execute(),
Action::CreateOrAppendFile(i) => i.describe_execute(),
Action::CreateNixTree(i) => i.describe_execute(),
Action::CreateOrAppendFile(i) => i.describe_execute(),
Action::CreateSystemdSysext(i) => i.describe_execute(),
Action::CreateUser(i) => i.describe_execute(),
Action::CreateUsersAndGroup(i) => i.describe_execute(),
Action::FetchNix(i) => i.describe_execute(),
Action::MoveUnpackedNix(i) => i.describe_execute(),
Action::PlaceChannelConfiguration(i) => i.describe_execute(),
Action::PlaceNixConfiguration(i) => i.describe_execute(),
Action::ProvisionNix(i) => i.describe_execute(),
Action::SetupDefaultProfile(i) => i.describe_execute(),
Action::StartNixDaemon(i) => i.describe_execute(),
Action::StartSystemdUnit(i) => i.describe_execute(),
Action::SystemdSysextMerge(i) => i.describe_execute(),
Action::ProvisionNix(i) => i.describe_execute(),
}
}
async fn execute(&mut self) -> Result<(), Self::Error> {
match self {
Action::ConfigureNixDaemonService(i) => i.execute().await?,
Action::ConfigureNix(i) => i.execute().await?,
Action::ConfigureNixDaemonService(i) => i.execute().await?,
Action::ConfigureShellProfile(i) => i.execute().await?,
Action::CreateApfsVolume(i) => i.execute().await?,
Action::CreateDirectory(i) => i.execute().await?,
Action::CreateSystemdSysext(i) => i.execute().await?,
Action::CreateFile(i) => i.execute().await?,
Action::CreateGroup(i) => i.execute().await?,
Action::CreateOrAppendFile(i) => i.execute().await?,
Action::CreateNixTree(i) => i.execute().await?,
Action::CreateOrAppendFile(i) => i.execute().await?,
Action::CreateSystemdSysext(i) => i.execute().await?,
Action::CreateUser(i) => i.execute().await?,
Action::CreateUsersAndGroup(i) => i.execute().await?,
Action::FetchNix(i) => i.execute().await?,
Action::MoveUnpackedNix(i) => i.execute().await?,
Action::PlaceChannelConfiguration(i) => i.execute().await?,
Action::PlaceNixConfiguration(i) => i.execute().await?,
Action::ProvisionNix(i) => i.execute().await?,
Action::SetupDefaultProfile(i) => i.execute().await?,
Action::StartNixDaemon(i) => i.execute().await?,
Action::StartSystemdUnit(i) => i.execute().await?,
Action::SystemdSysextMerge(i) => i.execute().await?,
Action::ProvisionNix(i) => i.execute().await?,
};
Ok(())
}
fn describe_revert(&self) -> Vec<ActionDescription> {
match self {
Action::ConfigureNixDaemonService(i) => i.describe_revert(),
Action::ConfigureNix(i) => i.describe_revert(),
Action::ConfigureNixDaemonService(i) => i.describe_revert(),
Action::ConfigureShellProfile(i) => i.describe_revert(),
Action::CreateApfsVolume(i) => i.describe_revert(),
Action::CreateDirectory(i) => i.describe_revert(),
Action::CreateSystemdSysext(i) => i.describe_revert(),
Action::CreateFile(i) => i.describe_revert(),
Action::CreateGroup(i) => i.describe_revert(),
Action::CreateOrAppendFile(i) => i.describe_revert(),
Action::CreateNixTree(i) => i.describe_revert(),
Action::CreateOrAppendFile(i) => i.describe_revert(),
Action::CreateSystemdSysext(i) => i.describe_revert(),
Action::CreateUser(i) => i.describe_revert(),
Action::CreateUsersAndGroup(i) => i.describe_revert(),
Action::FetchNix(i) => i.describe_revert(),
Action::MoveUnpackedNix(i) => i.describe_revert(),
Action::PlaceChannelConfiguration(i) => i.describe_revert(),
Action::PlaceNixConfiguration(i) => i.describe_revert(),
Action::ProvisionNix(i) => i.describe_revert(),
Action::SetupDefaultProfile(i) => i.describe_revert(),
Action::StartNixDaemon(i) => i.describe_revert(),
Action::StartSystemdUnit(i) => i.describe_revert(),
Action::SystemdSysextMerge(i) => i.describe_revert(),
Action::ProvisionNix(i) => i.describe_revert(),
}
}
async fn revert(&mut self) -> Result<(), Self::Error> {
match self {
Action::ConfigureNixDaemonService(i) => i.revert().await?,
Action::ConfigureNix(i) => i.revert().await?,
Action::ConfigureNixDaemonService(i) => i.revert().await?,
Action::ConfigureShellProfile(i) => i.revert().await?,
Action::CreateApfsVolume(i) => i.revert().await?,
Action::CreateDirectory(i) => i.revert().await?,
Action::CreateSystemdSysext(i) => i.revert().await?,
Action::CreateFile(i) => i.revert().await?,
Action::CreateGroup(i) => i.revert().await?,
Action::CreateOrAppendFile(i) => i.revert().await?,
Action::CreateNixTree(i) => i.revert().await?,
Action::CreateOrAppendFile(i) => i.revert().await?,
Action::CreateSystemdSysext(i) => i.revert().await?,
Action::CreateUser(i) => i.revert().await?,
Action::CreateUsersAndGroup(i) => i.revert().await?,
Action::FetchNix(i) => i.revert().await?,
Action::MoveUnpackedNix(i) => i.revert().await?,
Action::PlaceChannelConfiguration(i) => i.revert().await?,
Action::PlaceNixConfiguration(i) => i.revert().await?,
Action::ProvisionNix(i) => i.revert().await?,
Action::SetupDefaultProfile(i) => i.revert().await?,
Action::StartNixDaemon(i) => i.revert().await?,
Action::StartSystemdUnit(i) => i.revert().await?,
Action::SystemdSysextMerge(i) => i.revert().await?,
Action::ProvisionNix(i) => i.revert().await?,
}
Ok(())
}

View file

@ -1,4 +1,11 @@
use crate::{planner::Plannable, Planner};
use crate::{
actions::{
meta::{darwin::CreateApfsVolume, ConfigureNix, ProvisionNix, StartNixDaemon},
Action, ActionError,
},
planner::Plannable,
InstallPlan, Planner,
};
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
pub struct DarwinMultiUser;
@ -11,7 +18,32 @@ impl Plannable for DarwinMultiUser {
async fn plan(
settings: crate::InstallSettings,
) -> Result<crate::InstallPlan, crate::planner::PlannerError> {
todo!()
Ok(InstallPlan {
planner: Self.into(),
settings: settings.clone(),
actions: vec![
// Create Volume step:
//
// setup_Synthetic -> create_synthetic_objects
// Unmount -> create_volume -> Setup_fstab -> maybe encrypt_volume -> launchctl bootstrap -> launchctl kickstart -> await_volume -> maybe enableOwnership
CreateApfsVolume::plan(settings.clone())
.await
.map(Action::from)
.map_err(ActionError::from)?,
ProvisionNix::plan(settings.clone())
.await
.map(Action::from)
.map_err(ActionError::from)?,
ConfigureNix::plan(settings)
.await
.map(Action::from)
.map_err(ActionError::from)?,
StartNixDaemon::plan()
.await
.map(Action::from)
.map_err(ActionError::from)?,
],
})
}
}