mod bootstrap;
pub mod cache;
mod cleanup_helpers;
mod cluster;
mod env;
mod error;
mod fs;
#[cfg(all(test, feature = "loom-tests"))]
mod loom_model;
mod observability;
#[cfg(all(
unix,
any(
target_os = "linux",
target_os = "android",
target_os = "freebsd",
target_os = "openbsd",
target_os = "dragonfly",
),
))]
mod privileges;
#[doc(hidden)]
pub mod test_support;
#[doc(hidden)]
pub mod worker;
pub(crate) mod worker_process;
#[doc(hidden)]
pub mod worker_process_test_api {
use crate::worker_process;
#[cfg(all(
unix,
any(
target_os = "linux",
target_os = "android",
target_os = "freebsd",
target_os = "openbsd",
target_os = "dragonfly",
),
any(test, doc, feature = "privileged-tests"),
))]
use crate::worker_process::PrivilegeDropGuard as InnerPrivilegeDropGuard;
pub use crate::{cluster::WorkerOperation, worker_process::WorkerRequestArgs};
pub struct WorkerRequest<'a>(worker_process::WorkerRequest<'a>);
impl<'a> WorkerRequest<'a> {
#[must_use]
pub const fn new(args: WorkerRequestArgs<'a>) -> Self {
Self(worker_process::WorkerRequest::new(args))
}
pub(crate) const fn inner(&self) -> &worker_process::WorkerRequest<'a> { &self.0 }
}
pub fn run(request: &WorkerRequest<'_>) -> crate::BootstrapResult<()> {
worker_process::run(request.inner())
}
#[cfg(all(
unix,
any(
target_os = "linux",
target_os = "android",
target_os = "freebsd",
target_os = "openbsd",
target_os = "dragonfly",
),
any(test, doc, feature = "privileged-tests"),
))]
pub struct PrivilegeDropGuard {
_inner: InnerPrivilegeDropGuard,
}
#[cfg(all(
unix,
any(
target_os = "linux",
target_os = "android",
target_os = "freebsd",
target_os = "openbsd",
target_os = "dragonfly",
),
any(test, doc, feature = "privileged-tests"),
))]
#[must_use]
pub fn disable_privilege_drop_for_tests() -> PrivilegeDropGuard {
PrivilegeDropGuard {
_inner: worker_process::disable_privilege_drop_for_tests(),
}
}
#[must_use]
pub fn render_failure_for_tests(
context: &str,
output: &std::process::Output,
) -> crate::BootstrapError {
worker_process::render_failure_for_tests(context, output)
}
}
use std::ffi::OsString;
pub use bootstrap::{
CleanupMode,
ExecutionMode,
ExecutionPrivileges,
TestBootstrapEnvironment,
TestBootstrapSettings,
bootstrap_for_tests,
detect_execution_privileges,
find_timezone_dir,
run,
};
use camino::Utf8PathBuf;
#[cfg(any(doc, test, feature = "cluster-unit-tests", feature = "dev-worker"))]
#[doc(hidden)]
pub use cluster::WorkerInvoker;
#[cfg(any(test, feature = "cluster-unit-tests"))]
#[doc(hidden)]
pub use cluster::WorkerOperation;
pub use cluster::{
ClusterGuard,
ClusterHandle,
ConnectionMetadata,
DatabaseName,
TemporaryDatabase,
TestCluster,
TestClusterConnection,
};
use color_eyre::eyre::{Context, eyre};
#[doc(hidden)]
pub use error::BootstrapResult;
pub use error::{
BootstrapError,
BootstrapErrorKind,
PgEmbeddedError as Error,
PgEmbeddedError,
PrivilegeError,
PrivilegeResult,
Result,
};
use ortho_config::OrthoConfig;
use postgresql_embedded::{Settings, VersionReq};
#[cfg(feature = "privileged-tests")]
#[cfg(all(
unix,
any(
target_os = "linux",
target_os = "android",
target_os = "freebsd",
target_os = "openbsd",
target_os = "dragonfly",
),
))]
#[expect(
deprecated,
reason = "with_temp_euid() remains exported for backward compatibility whilst deprecated"
)]
pub use privileges::with_temp_euid;
#[cfg(all(
unix,
any(
target_os = "linux",
target_os = "android",
target_os = "freebsd",
target_os = "openbsd",
target_os = "dragonfly",
),
))]
pub use privileges::{default_paths_for, make_data_dir_private, make_dir_accessible, nobody_uid};
use serde::{Deserialize, Serialize};
#[doc(hidden)]
pub use crate::env::ScopedEnv;
use crate::error::{ConfigError, ConfigResult};
pub use crate::fs::ambient_dir_and_path;
#[derive(Debug, Clone, Serialize, Deserialize, OrthoConfig, Default)]
#[ortho_config(prefix = "PG")]
pub struct PgEnvCfg {
pub version_req: Option<String>,
pub port: Option<u16>,
pub superuser: Option<String>,
pub password: Option<String>,
pub data_dir: Option<Utf8PathBuf>,
pub runtime_dir: Option<Utf8PathBuf>,
pub locale: Option<String>,
pub encoding: Option<String>,
pub binary_cache_dir: Option<Utf8PathBuf>,
}
impl PgEnvCfg {
pub fn load() -> ConfigResult<Self> {
let args = [OsString::from("pg-embedded-setup-unpriv")];
Self::load_from_iter(args).map_err(|err| ConfigError::from(eyre!(err)))
}
pub fn to_settings(&self) -> Result<Settings> { self.to_settings_with_context(false) }
pub fn to_settings_for_tests(&self) -> Result<Settings> { self.to_settings_with_context(true) }
pub fn to_settings_with_context(&self, for_tests: bool) -> Result<Settings> {
let mut s = Settings {
timeout: None,
..Settings::default()
};
self.apply_version(&mut s)?;
self.apply_connection(&mut s);
self.apply_paths(&mut s);
self.apply_locale(&mut s);
if for_tests {
Self::apply_worker_limits(&mut s);
}
Ok(s)
}
fn apply_version(&self, settings: &mut Settings) -> ConfigResult<()> {
if let Some(ref vr) = self.version_req {
settings.version =
VersionReq::parse(vr).context("PG_VERSION_REQ invalid semver spec")?;
}
Ok(())
}
fn apply_connection(&self, settings: &mut Settings) {
if let Some(p) = self.port {
settings.port = p;
}
if let Some(ref u) = self.superuser {
settings.username.clone_from(u);
}
if let Some(ref pw) = self.password {
settings.password.clone_from(pw);
}
}
fn apply_paths(&self, settings: &mut Settings) {
if let Some(ref dir) = self.data_dir {
settings.data_dir = dir.clone().into_std_path_buf();
}
if let Some(ref dir) = self.runtime_dir {
settings.installation_dir = dir.clone().into_std_path_buf();
}
}
fn apply_locale(&self, settings: &mut Settings) {
if let Some(ref loc) = self.locale {
settings.configuration.insert("locale".into(), loc.clone());
}
if let Some(ref enc) = self.encoding {
settings
.configuration
.insert("encoding".into(), enc.clone());
}
}
fn apply_worker_limits(settings: &mut Settings) {
for (key, value) in WORKER_LIMIT_DEFAULTS {
settings
.configuration
.entry(key.to_owned())
.or_insert_with(|| value.to_owned());
}
}
}
const WORKER_LIMIT_DEFAULTS: [(&str, &str); 8] = [
("max_connections", "20"),
("max_worker_processes", "2"),
("max_parallel_workers", "0"),
("max_parallel_workers_per_gather", "0"),
("max_parallel_maintenance_workers", "0"),
("autovacuum", "off"),
("max_wal_senders", "0"),
("max_replication_slots", "0"),
];