pub struct EnvironmentContext {
pub created_at: DateTime<Utc>,
pub user_inputs: UserInputs,
pub internal_config: InternalConfig,
pub runtime_outputs: RuntimeOutputs,
}Expand description
Complete environment context composed of three semantic types
The context is split into three logical categories:
- User Inputs (
user_inputs): Configuration provided by users - Internal Config (
internal_config): Derived paths for organizing artifacts - Runtime Outputs (
runtime_outputs): Data generated during deployment
This separation makes it clear where each piece of information comes from and helps developers understand where to add new fields.
§Design Rationale
By separating state-independent data from the state machine and organizing it into three semantic categories, we:
- Eliminate repetitive pattern matching in
AnyEnvironmentState - Make it clear which data is constant vs. state-dependent
- Provide semantic clarity about the purpose of each field
- Guide developers where to add new fields based on their purpose
- Simplify state transitions (only the state field changes)
- Enable easier extension of environment configuration
§Three Semantic Categories
- User Inputs: Immutable user configuration (name, SSH credentials, port)
- Internal Config: Derived paths (
build_dir,data_dir) - Runtime Outputs: Generated during deployment (
instance_ip, future metrics)
§Examples
EnvironmentContext is typically created internally by Environment::new():
use torrust_tracker_deployer_lib::domain::environment::{Environment, EnvironmentName};
use torrust_tracker_deployer_lib::domain::provider::{LxdConfig, ProviderConfig};
use torrust_tracker_deployer_lib::domain::ProfileName;
use torrust_tracker_deployer_lib::shared::Username;
use torrust_tracker_deployer_lib::adapters::ssh::SshCredentials;
use std::path::PathBuf;
use chrono::{TimeZone, Utc};
let env_name = EnvironmentName::new("production".to_string())?;
let ssh_username = Username::new("torrust".to_string())?;
let ssh_credentials = SshCredentials::new(
PathBuf::from("keys/prod_rsa"),
PathBuf::from("keys/prod_rsa.pub"),
ssh_username,
);
let provider_config = ProviderConfig::Lxd(LxdConfig {
profile_name: ProfileName::new(format!("lxd-{}", env_name.as_str())).unwrap(),
});
// Environment::new() creates the EnvironmentContext internally
let created_at = Utc.with_ymd_and_hms(2025, 1, 1, 0, 0, 0).unwrap();
let environment = Environment::new(env_name, provider_config, ssh_credentials, 22, created_at);
// Access the context through the environment
let context = environment.context();
// Context holds all state-independent data for the environment
Fields§
§created_at: DateTime<Utc>Timestamp when the environment was created
This field records the exact moment when the environment was first created
using the create environment command. It never changes throughout the
environment lifecycle.
user_inputs: UserInputsUser-provided configuration
internal_config: InternalConfigInternal paths and derived configuration
runtime_outputs: RuntimeOutputsRuntime outputs from deployment operations
Implementations§
Source§impl EnvironmentContext
impl EnvironmentContext
Sourcepub fn new(
name: &EnvironmentName,
provider_config: ProviderConfig,
ssh_credentials: SshCredentials,
ssh_port: u16,
created_at: DateTime<Utc>,
) -> Self
pub fn new( name: &EnvironmentName, provider_config: ProviderConfig, ssh_credentials: SshCredentials, ssh_port: u16, created_at: DateTime<Utc>, ) -> Self
Creates a new EnvironmentContext with auto-generated names and paths
§Arguments
name- The validated environment nameprovider_config- Provider-specific configuration (LXD, Hetzner, etc.)ssh_credentials- SSH credentials for connecting to instancesssh_port- SSH port for connecting to instances
§Returns
A new EnvironmentContext with:
- Auto-generated instance name:
torrust-tracker-vm-{env_name} - Provider configuration with validated settings
- Auto-generated data and build directories
- Empty runtime outputs
§Examples
use torrust_tracker_deployer_lib::domain::environment::{EnvironmentContext, EnvironmentName};
use torrust_tracker_deployer_lib::domain::provider::{ProviderConfig, LxdConfig};
use torrust_tracker_deployer_lib::domain::ProfileName;
use torrust_tracker_deployer_lib::shared::Username;
use torrust_tracker_deployer_lib::adapters::ssh::SshCredentials;
use std::path::PathBuf;
use chrono::{TimeZone, Utc};
let env_name = EnvironmentName::new("production".to_string())?;
let ssh_username = Username::new("torrust".to_string())?;
let ssh_credentials = SshCredentials::new(
PathBuf::from("keys/prod_rsa"),
PathBuf::from("keys/prod_rsa.pub"),
ssh_username,
);
let provider_config = ProviderConfig::Lxd(LxdConfig {
profile_name: ProfileName::new("torrust-profile-production".to_string())?,
});
let created_at = Utc.with_ymd_and_hms(2025, 1, 1, 0, 0, 0).unwrap();
let context = EnvironmentContext::new(&env_name, provider_config, ssh_credentials, 22, created_at);
assert_eq!(context.user_inputs.instance_name().as_str(), "torrust-tracker-vm-production");
let lxd_config = context.user_inputs.provider_config().as_lxd().unwrap();
assert_eq!(lxd_config.profile_name.as_str(), "torrust-profile-production");
assert_eq!(context.internal_config.data_dir, PathBuf::from("./data/production"));
assert_eq!(context.internal_config.build_dir, PathBuf::from("./build/production"));
§Panics
This function does not panic. All name generation is guaranteed to succeed for valid environment names.
Sourcepub fn create(
params: EnvironmentParams,
working_dir: &Path,
created_at: DateTime<Utc>,
) -> Result<Self, UserInputsError>
pub fn create( params: EnvironmentParams, working_dir: &Path, created_at: DateTime<Utc>, ) -> Result<Self, UserInputsError>
Creates a new environment context from validated parameters
This creates absolute paths for data and build directories by using the provided working directory as the base.
§Arguments
params- Validated environment parameters (domain value object)working_dir- Base directory for data and build directoriescreated_at- Timestamp for context creation
§Errors
Returns UserInputsError if cross-service invariant validation fails:
GrafanaRequiresPrometheusif Grafana is configured without PrometheusHttpsSectionWithoutTlsServicesif HTTPS section exists but no service uses TLSTlsServicesWithoutHttpsSectionif a service uses TLS but HTTPS section is missing
Sourcepub fn ssh_username(&self) -> &Username
pub fn ssh_username(&self) -> &Username
Returns the SSH username for this environment
Sourcepub fn ssh_private_key_path(&self) -> &PathBuf
pub fn ssh_private_key_path(&self) -> &PathBuf
Returns the SSH private key path for this environment
Sourcepub fn ssh_public_key_path(&self) -> &PathBuf
pub fn ssh_public_key_path(&self) -> &PathBuf
Returns the SSH public key path for this environment
Sourcepub fn templates_dir(&self) -> PathBuf
pub fn templates_dir(&self) -> PathBuf
Returns the templates directory for this environment
Path: data/{env_name}/templates/
Sourcepub fn traces_dir(&self) -> PathBuf
pub fn traces_dir(&self) -> PathBuf
Returns the traces directory for this environment
Path: data/{env_name}/traces/
Sourcepub fn ansible_build_dir(&self) -> PathBuf
pub fn ansible_build_dir(&self) -> PathBuf
Returns the ansible build directory
Path: build/{env_name}/ansible
Sourcepub fn tofu_build_dir(&self) -> PathBuf
pub fn tofu_build_dir(&self) -> PathBuf
Returns the tofu build directory for the environment’s provider
Path: build/{env_name}/tofu/{provider_name}
The provider is determined from the environment’s provider configuration (e.g., LXD, Hetzner).
Sourcepub fn ansible_templates_dir(&self) -> PathBuf
pub fn ansible_templates_dir(&self) -> PathBuf
Returns the ansible templates directory
Path: data/{env_name}/templates/ansible
Sourcepub fn tofu_templates_dir(&self) -> PathBuf
pub fn tofu_templates_dir(&self) -> PathBuf
Returns the tofu templates directory
Path: data/{env_name}/templates/tofu
Sourcepub fn name(&self) -> &EnvironmentName
pub fn name(&self) -> &EnvironmentName
Returns the environment name
Sourcepub fn instance_name(&self) -> &InstanceName
pub fn instance_name(&self) -> &InstanceName
Returns the instance name
Sourcepub fn provider_config(&self) -> &ProviderConfig
pub fn provider_config(&self) -> &ProviderConfig
Returns the provider configuration
Sourcepub fn ssh_credentials(&self) -> &SshCredentials
pub fn ssh_credentials(&self) -> &SshCredentials
Returns the SSH credentials
Sourcepub fn database_config(&self) -> &DatabaseConfig
pub fn database_config(&self) -> &DatabaseConfig
Returns the database configuration
Sourcepub fn tracker_config(&self) -> &TrackerConfig
pub fn tracker_config(&self) -> &TrackerConfig
Returns the tracker configuration
Sourcepub fn admin_token(&self) -> &str
pub fn admin_token(&self) -> &str
Returns the admin token
Sourcepub fn prometheus_config(&self) -> Option<&PrometheusConfig>
pub fn prometheus_config(&self) -> Option<&PrometheusConfig>
Returns the Prometheus configuration if enabled
Sourcepub fn grafana_config(&self) -> Option<&GrafanaConfig>
pub fn grafana_config(&self) -> Option<&GrafanaConfig>
Returns the Grafana configuration if enabled
Sourcepub fn backup_config(&self) -> Option<&BackupConfig>
pub fn backup_config(&self) -> Option<&BackupConfig>
Returns the Backup configuration if enabled
Sourcepub fn instance_ip(&self) -> Option<IpAddr>
pub fn instance_ip(&self) -> Option<IpAddr>
Returns the instance IP address if available
Sourcepub fn provision_method(&self) -> Option<ProvisionMethod>
pub fn provision_method(&self) -> Option<ProvisionMethod>
Returns the provision method
Sourcepub fn created_at(&self) -> DateTime<Utc>
pub fn created_at(&self) -> DateTime<Utc>
Returns the creation timestamp
Trait Implementations§
Source§impl Clone for EnvironmentContext
impl Clone for EnvironmentContext
Source§impl Debug for EnvironmentContext
impl Debug for EnvironmentContext
Source§impl<'de> Deserialize<'de> for EnvironmentContext
impl<'de> Deserialize<'de> for EnvironmentContext
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Auto Trait Implementations§
impl Freeze for EnvironmentContext
impl RefUnwindSafe for EnvironmentContext
impl Send for EnvironmentContext
impl Sync for EnvironmentContext
impl Unpin for EnvironmentContext
impl UnsafeUnpin for EnvironmentContext
impl UnwindSafe for EnvironmentContext
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request