server_forge/
updates.rs

1//! # Updates Module
2//!
3//! This module provides functionality for setting up and configuring automatic updates
4//! on Linux servers. It supports different update mechanisms for Ubuntu, CentOS, and Fedora,
5//! ensuring that the server stays up-to-date with the latest security patches and software versions.
6//!
7//! The module includes functions for configuring unattended-upgrades on Ubuntu,
8//! yum-cron on CentOS, and dnf-automatic on Fedora.
9use crate::config::Config;
10use crate::distro::get_package_manager;
11use crate::rollback::RollbackManager;
12use crate::utils::run_command;
13use log::info;
14use std::error::Error;
15
16/// Sets up automatic updates based on the Linux distribution specified in the configuration.
17///
18/// This function determines the appropriate update mechanism based on the Linux distribution
19/// and calls the corresponding setup function. It creates a snapshot before starting the setup
20/// process for potential rollback.
21///
22/// # Arguments
23///
24/// * `config` - A reference to the `Config` struct containing the Linux distribution information
25/// * `rollback` - A reference to the `RollbackManager` for creating snapshots
26///
27/// # Returns
28///
29/// Returns `Ok(())` if automatic updates are set up successfully, or an error if setup fails.
30pub fn setup_automatic_updates(
31    config: &Config,
32    rollback: &RollbackManager,
33) -> Result<(), Box<dyn Error>> {
34    info!("Setting up automatic updates...");
35
36    let snapshot = rollback.create_snapshot()?;
37
38    match config.linux_distro.as_str() {
39        "ubuntu" => setup_ubuntu_updates(config)?,
40        "centos" => setup_centos_updates(config)?,
41        "fedora" => setup_fedora_updates(config)?,
42        _ => return Err("Unsupported Linux distribution".into()),
43    }
44
45    rollback.commit_snapshot(snapshot)?;
46
47    info!("Automatic updates configured");
48    Ok(())
49}
50
51/// Sets up automatic updates for Ubuntu using unattended-upgrades.
52///
53/// This function installs unattended-upgrades, configures it to automatically install
54/// security updates, and sets up the update schedule based on the configuration.
55///
56/// # Arguments
57///
58/// * `config` - A reference to the `Config` struct containing update schedule information
59///
60/// # Returns
61///
62/// Returns `Ok(())` if unattended-upgrades is set up successfully, or an error if setup fails.
63fn setup_ubuntu_updates(config: &Config) -> Result<(), Box<dyn Error>> {
64    run_command(
65        "apt",
66        &["install", "-y", "unattended-upgrades", "apt-listchanges"],
67    )?;
68
69    let unattended_upgrades_conf = "/etc/apt/apt.conf.d/50unattended-upgrades";
70    let conf_content = r#"
71Unattended-Upgrade::Allowed-Origins {
72    "${distro_id}:${distro_codename}";
73    "${distro_id}:${distro_codename}-security";
74};
75Unattended-Upgrade::Package-Blacklist {
76};
77Unattended-Upgrade::AutoFixInterruptedDpkg "true";
78Unattended-Upgrade::MinimalSteps "true";
79Unattended-Upgrade::InstallOnShutdown "false";
80Unattended-Upgrade::Mail "root";
81Unattended-Upgrade::MailReport "on-change";
82Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
83Unattended-Upgrade::Remove-Unused-Dependencies "true";
84Unattended-Upgrade::Automatic-Reboot "false";
85"#;
86    std::fs::write(unattended_upgrades_conf, conf_content)?;
87
88    let auto_upgrades_conf = "/etc/apt/apt.conf.d/20auto-upgrades";
89    let auto_upgrades_content = match config.update_schedule.as_str() {
90        "daily" => {
91            "APT::Periodic::Update-Package-Lists \"1\";\nAPT::Periodic::Unattended-Upgrade \"1\";\n"
92        }
93        "weekly" => {
94            "APT::Periodic::Update-Package-Lists \"7\";\nAPT::Periodic::Unattended-Upgrade \"7\";\n"
95        }
96        _ => {
97            "APT::Periodic::Update-Package-Lists \"1\";\nAPT::Periodic::Unattended-Upgrade \"1\";\n"
98        }
99    };
100    std::fs::write(auto_upgrades_conf, auto_upgrades_content)?;
101
102    run_command("systemctl", &["enable", "unattended-upgrades"])?;
103    run_command("systemctl", &["start", "unattended-upgrades"])?;
104
105    Ok(())
106}
107
108/// Sets up automatic updates for CentOS using yum-cron.
109///
110/// This function installs yum-cron, configures it to automatically apply updates,
111/// and enables the yum-cron service.
112///
113/// # Arguments
114///
115/// * `config` - A reference to the `Config` struct (unused in the current implementation)
116///
117/// # Returns
118///
119/// Returns `Ok(())` if yum-cron is set up successfully, or an error if setup fails.
120fn setup_centos_updates(config: &Config) -> Result<(), Box<dyn Error>> {
121    run_command("yum", &["install", "-y", "yum-cron"])?;
122
123    let yum_cron_conf = "/etc/yum/yum-cron.conf";
124    let mut conf_content = std::fs::read_to_string(yum_cron_conf)?;
125    conf_content = conf_content.replace("apply_updates = no", "apply_updates = yes");
126    std::fs::write(yum_cron_conf, conf_content)?;
127
128    run_command("systemctl", &["enable", "yum-cron"])?;
129    run_command("systemctl", &["start", "yum-cron"])?;
130
131    Ok(())
132}
133
134/// Sets up automatic updates for Fedora using dnf-automatic.
135///
136/// This function installs dnf-automatic, configures it to automatically apply updates,
137/// and enables the dnf-automatic timer.
138///
139/// # Arguments
140///
141/// * `config` - A reference to the `Config` struct (unused in the current implementation)
142///
143/// # Returns
144///
145/// Returns `Ok(())` if dnf-automatic is set up successfully, or an error if setup fails.
146fn setup_fedora_updates(config: &Config) -> Result<(), Box<dyn Error>> {
147    run_command("dnf", &["install", "-y", "dnf-automatic"])?;
148
149    let dnf_automatic_conf = "/etc/dnf/automatic.conf";
150    let mut conf_content = std::fs::read_to_string(dnf_automatic_conf)?;
151    conf_content = conf_content.replace("apply_updates = no", "apply_updates = yes");
152    std::fs::write(dnf_automatic_conf, conf_content)?;
153
154    run_command("systemctl", &["enable", "dnf-automatic.timer"])?;
155    run_command("systemctl", &["start", "dnf-automatic.timer"])?;
156
157    Ok(())
158}