Skip to content

Commit

Permalink
Factor out the enterprise init service setup into its own module
Browse files Browse the repository at this point in the history
  • Loading branch information
grahamc committed Apr 5, 2024
1 parent 845b9af commit 073855c
Show file tree
Hide file tree
Showing 4 changed files with 223 additions and 73 deletions.
188 changes: 188 additions & 0 deletions src/action/common/configure_enterprise_edition_init_service.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
use std::path::PathBuf;

#[cfg(target_os = "macos")]
use serde::{Deserialize, Serialize};
#[cfg(target_os = "macos")]
use tokio::io::AsyncWriteExt;
use tokio::process::Command;
use tracing::{span, Span};

use crate::action::{ActionError, ActionErrorKind, ActionTag, StatefulAction};
use crate::execute_command;

use crate::action::{Action, ActionDescription};

#[cfg(target_os = "macos")]
const DARWIN_ENTERPRISE_EDITION_DAEMON_DEST: &str =
"/Library/LaunchDaemons/systems.determinate.nix-daemon.plist";
/**
Configure the init to run the Nix daemon
*/
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct ConfigureEnterpriseEditionInitService {
start_daemon: bool,
}

impl ConfigureEnterpriseEditionInitService {
#[tracing::instrument(level = "debug", skip_all)]
pub async fn plan(start_daemon: bool) -> Result<StatefulAction<Self>, ActionError> {
Ok(Self { start_daemon }.into())
}
}

#[async_trait::async_trait]
#[typetag::serde(name = "configure_enterprise_edition_init_service")]
impl Action for ConfigureEnterpriseEditionInitService {
fn action_tag() -> ActionTag {
ActionTag("configure_enterprise_edition_init_service")
}
fn tracing_synopsis(&self) -> String {
"Configure the Determinate Nix Enterprise Edition daemon related settings with launchctl"
.to_string()
}

fn tracing_span(&self) -> Span {
span!(
tracing::Level::DEBUG,
"configure_enterprise_edition_init_service"
)
}

fn execute_description(&self) -> Vec<ActionDescription> {
let mut explanation = vec![format!("Create `{DARWIN_ENTERPRISE_EDITION_DAEMON_DEST}`")];
if self.start_daemon {
explanation.push(format!(
"Run `launchctl load {DARWIN_ENTERPRISE_EDITION_DAEMON_DEST}`"
));
}

vec![ActionDescription::new(self.tracing_synopsis(), explanation)]
}

#[tracing::instrument(level = "debug", skip_all)]
async fn execute(&mut self) -> Result<(), ActionError> {
let Self { start_daemon } = self;

let daemon_file = DARWIN_ENTERPRISE_EDITION_DAEMON_DEST;
let domain = "system";
let service = "systems.determinate.nix-daemon";

let generated_plist = generate_plist();

let mut options = tokio::fs::OpenOptions::new();
options.create(true).write(true).read(true);

let mut file = options
.open(&daemon_file)
.await
.map_err(|e| Self::error(ActionErrorKind::Open(PathBuf::from(daemon_file), e)))?;

let mut buf = Vec::new();
plist::to_writer_xml(&mut buf, &generated_plist).map_err(Self::error)?;
file.write_all(&buf)
.await
.map_err(|e| Self::error(ActionErrorKind::Write(PathBuf::from(daemon_file), e)))?;

execute_command(
Command::new("launchctl")
.process_group(0)
.args(["load", "-w"])
.arg(daemon_file)
.stdin(std::process::Stdio::null()),
)
.await
.map_err(Self::error)?;

let is_disabled = crate::action::macos::service_is_disabled(domain, service)
.await
.map_err(Self::error)?;
if is_disabled {
execute_command(
Command::new("launchctl")
.process_group(0)
.arg("enable")
.arg(&format!("{domain}/{service}"))
.stdin(std::process::Stdio::null()),
)
.await
.map_err(Self::error)?;
}

if *start_daemon {
execute_command(
Command::new("launchctl")
.process_group(0)
.arg("kickstart")
.arg("-k")
.arg(&format!("{domain}/{service}"))
.stdin(std::process::Stdio::null()),
)
.await
.map_err(Self::error)?;
}

Ok(())
}

fn revert_description(&self) -> Vec<ActionDescription> {
vec![ActionDescription::new(
"Unconfigure Nix daemon related settings with launchctl".to_string(),
vec![format!(
"Run `launchctl unload {DARWIN_ENTERPRISE_EDITION_DAEMON_DEST}`"
)],
)]
}

#[tracing::instrument(level = "debug", skip_all)]
async fn revert(&mut self) -> Result<(), ActionError> {
execute_command(
Command::new("launchctl")
.process_group(0)
.arg("unload")
.arg(DARWIN_ENTERPRISE_EDITION_DAEMON_DEST),
)
.await
.map_err(Self::error)?;

Ok(())
}
}

#[non_exhaustive]
#[derive(Debug, thiserror::Error)]
pub enum ConfigureEnterpriseEditionNixDaemonServiceError {}

#[cfg(target_os = "macos")]
#[derive(Deserialize, Clone, Debug, Serialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct DeterminateNixDaemonPlist {
label: String,
program: String,
keep_alive: bool,
run_at_load: bool,
standard_error_path: String,
standard_out_path: String,
soft_resource_limits: ResourceLimits,
}

#[cfg(target_os = "macos")]
#[derive(Deserialize, Clone, Debug, Serialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct ResourceLimits {
number_of_files: usize,
}

#[cfg(target_os = "macos")]
fn generate_plist() -> DeterminateNixDaemonPlist {
DeterminateNixDaemonPlist {
keep_alive: true,
run_at_load: true,
label: "systems.determinate.nix-daemon".into(),
program: "/usr/local/bin/determinate-nix-ee".into(),
standard_error_path: "/var/log/determinate-nix-daemon.log".into(),
standard_out_path: "/var/log/determinate-nix-daemon.log".into(),
soft_resource_limits: ResourceLimits {
number_of_files: 1048576,
},
}
}
80 changes: 14 additions & 66 deletions src/action/common/configure_init_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use std::path::PathBuf;
#[cfg(target_os = "macos")]
use serde::{Deserialize, Serialize};
#[cfg(target_os = "macos")]
use tokio::io::AsyncWriteExt;
use tokio::process::Command;
use tracing::{span, Span};

Expand All @@ -28,9 +27,6 @@ const TMPFILES_SRC: &str = "/nix/var/nix/profiles/default/lib/tmpfiles.d/nix-dae
#[cfg(target_os = "linux")]
const TMPFILES_DEST: &str = "/etc/tmpfiles.d/nix-daemon.conf";
#[cfg(target_os = "macos")]
const DARWIN_ENTERPRISE_EDITION_DAEMON_DEST: &str =
"/Library/LaunchDaemons/systems.determinate.nix-daemon.plist";
#[cfg(target_os = "macos")]
const DARWIN_NIX_DAEMON_DEST: &str = "/Library/LaunchDaemons/org.nixos.nix-daemon.plist";
#[cfg(target_os = "macos")]
const DARWIN_NIX_DAEMON_SOURCE: &str =
Expand All @@ -41,7 +37,6 @@ Configure the init to run the Nix daemon
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct ConfigureInitService {
init: InitSystem,
enterprise_edition: bool,
start_daemon: bool,
}

Expand Down Expand Up @@ -79,7 +74,6 @@ impl ConfigureInitService {
#[tracing::instrument(level = "debug", skip_all)]
pub async fn plan(
init: InitSystem,
enterprise_edition: bool,
start_daemon: bool,
) -> Result<StatefulAction<Self>, ActionError> {
match init {
Expand Down Expand Up @@ -116,12 +110,7 @@ impl ConfigureInitService {
},
};

Ok(Self {
init,
enterprise_edition,
start_daemon,
}
.into())
Ok(Self { init, start_daemon }.into())
}
}

Expand All @@ -145,7 +134,7 @@ impl Action for ConfigureInitService {
}

fn tracing_span(&self) -> Span {
span!(tracing::Level::DEBUG, "configure_init_service",)
span!(tracing::Level::DEBUG, "configure_init_service")
}

fn execute_description(&self) -> Vec<ActionDescription> {
Expand All @@ -167,7 +156,7 @@ impl Action for ConfigureInitService {
#[cfg(target_os = "macos")]
InitSystem::Launchd => {
let mut explanation = vec![format!(
"Copy `{DARWIN_NIX_DAEMON_SOURCE}` to `DARWIN_NIX_DAEMON_DEST`"
"Copy `{DARWIN_NIX_DAEMON_SOURCE}` to `{DARWIN_NIX_DAEMON_DEST}`"
)];
if self.start_daemon {
explanation.push(format!("Run `launchctl load {DARWIN_NIX_DAEMON_DEST}`"));
Expand All @@ -182,49 +171,23 @@ impl Action for ConfigureInitService {

#[tracing::instrument(level = "debug", skip_all)]
async fn execute(&mut self) -> Result<(), ActionError> {
let Self {
init,
enterprise_edition,
start_daemon,
} = self;
let Self { init, start_daemon } = self;

match init {
#[cfg(target_os = "macos")]
InitSystem::Launchd => {
let daemon_file: &str;
let daemon_file = DARWIN_NIX_DAEMON_DEST;
let domain = "system";
let service: &str;

if *enterprise_edition {
daemon_file = DARWIN_ENTERPRISE_EDITION_DAEMON_DEST;
service = "systems.determinate.nix-daemon";

let generated_plist = generate_plist();
let service = "org.nixos.nix-daemon";
let src = std::path::Path::new(DARWIN_NIX_DAEMON_SOURCE);

let mut options = tokio::fs::OpenOptions::new();
options.create(true).write(true).read(true);

let mut file = options.open(&daemon_file).await.map_err(|e| {
Self::error(ActionErrorKind::Open(PathBuf::from(daemon_file), e))
})?;

let mut buf = Vec::new();
plist::to_writer_xml(&mut buf, &generated_plist).map_err(Self::error)?;
file.write_all(&buf).await.map_err(|e| {
Self::error(ActionErrorKind::Write(PathBuf::from(daemon_file), e))
})?;
} else {
let src = std::path::Path::new(DARWIN_NIX_DAEMON_SOURCE);
daemon_file = DARWIN_NIX_DAEMON_DEST;
service = "org.nixos.nix-daemon";
tokio::fs::copy(src, daemon_file).await.map_err(|e| {
Self::error(ActionErrorKind::Copy(
src.to_path_buf(),
PathBuf::from(daemon_file),
e,
))
})?;
}
tokio::fs::copy(src, daemon_file).await.map_err(|e| {
Self::error(ActionErrorKind::Copy(
src.to_path_buf(),
PathBuf::from(daemon_file),
e,
))
})?;

execute_command(
Command::new("launchctl")
Expand Down Expand Up @@ -585,21 +548,6 @@ pub struct ResourceLimits {
number_of_files: usize,
}

#[cfg(target_os = "macos")]
fn generate_plist() -> DeterminateNixDaemonPlist {
DeterminateNixDaemonPlist {
keep_alive: true,
run_at_load: true,
label: "systems.determinate.nix-daemon".into(),
program: "/usr/local/bin/determinate-nix-ee".into(),
standard_error_path: "/var/log/determinate-nix-daemon.log".into(),
standard_out_path: "/var/log/determinate-nix-daemon.log".into(),
soft_resource_limits: ResourceLimits {
number_of_files: 1048576,
},
}
}

#[cfg(target_os = "linux")]
async fn stop(unit: &str) -> Result<(), ActionErrorKind> {
let mut command = Command::new("systemctl");
Expand Down
2 changes: 2 additions & 0 deletions src/action/common/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! [`Action`](crate::action::Action)s which only call other base plugins
pub(crate) mod configure_enterprise_edition_init_service;
pub(crate) mod configure_init_service;
pub(crate) mod configure_nix;
pub(crate) mod configure_shell_profile;
Expand All @@ -9,6 +10,7 @@ pub(crate) mod delete_users;
pub(crate) mod place_nix_configuration;
pub(crate) mod provision_nix;

pub use configure_enterprise_edition_init_service::ConfigureEnterpriseEditionInitService;
pub use configure_init_service::{ConfigureInitService, ConfigureNixDaemonServiceError};
pub use configure_nix::ConfigureNix;
pub use configure_shell_profile::ConfigureShellProfile;
Expand Down
26 changes: 19 additions & 7 deletions src/planner/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ use crate::planner::HasExpectedErrors;
use crate::{
action::{
base::RemoveDirectory,
common::{ConfigureInitService, ConfigureNix, CreateUsersAndGroups, ProvisionNix},
common::{
ConfigureEnterpriseEditionInitService, ConfigureInitService, ConfigureNix,
CreateUsersAndGroups, ProvisionNix,
},
macos::{
ConfigureRemoteBuilding, CreateEnterpriseEditionVolume, CreateNixHookService,
CreateNixVolume, SetTmutilExclusions,
Expand Down Expand Up @@ -214,12 +217,21 @@ impl Planner for Macos {
);
}

plan.push(
ConfigureInitService::plan(InitSystem::Launchd, self.enterprise_edition, true)
.await
.map_err(PlannerError::Action)?
.boxed(),
);
if self.enterprise_edition {
plan.push(
ConfigureInitService::plan(InitSystem::Launchd, true)
.await
.map_err(PlannerError::Action)?
.boxed(),
);
} else {
plan.push(
ConfigureEnterpriseEditionInitService::plan(true)
.await
.map_err(PlannerError::Action)?
.boxed(),
);
}
plan.push(
RemoveDirectory::plan(crate::settings::SCRATCH_DIR)
.await
Expand Down

0 comments on commit 073855c

Please sign in to comment.