|
|
@@ -0,0 +1,114 @@
|
|
|
+import os
|
|
|
+import subprocess
|
|
|
+import toml
|
|
|
+from datetime import datetime, timedelta
|
|
|
+import shutil
|
|
|
+
|
|
|
+# Read configuration from a TOML file
|
|
|
+def read_config(file_path):
|
|
|
+ with open(file_path, 'r') as f:
|
|
|
+ config = toml.load(f)
|
|
|
+ return config
|
|
|
+
|
|
|
+# Create a new snapshot with the current date and time
|
|
|
+def create_snapshot(config):
|
|
|
+ date_str = datetime.now().strftime("%Y%m%d-%H%M%S")
|
|
|
+ snapshot_name = f"{config['snapshot']['snapshot_prefix']}{date_str}"
|
|
|
+ snapshot_path = os.path.join(config['snapshot']['snapshot_dir'], snapshot_name)
|
|
|
+
|
|
|
+ # Run the Btrfs snapshot command
|
|
|
+ cmd = ["btrfs", "subvolume", "snapshot",
|
|
|
+ os.path.join(config['snapshot']['btrfs_mount_point'], config['snapshot']['root_subvolume']),
|
|
|
+ snapshot_path]
|
|
|
+ result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
|
+
|
|
|
+ if result.returncode == 0:
|
|
|
+ print(f"Created snapshot: {snapshot_name}")
|
|
|
+ add_elilo_entry(config, snapshot_name)
|
|
|
+ return snapshot_name
|
|
|
+ else:
|
|
|
+ raise Exception(f"Failed to create snapshot: {result.stderr.decode()}")
|
|
|
+
|
|
|
+# Add an entry for the snapshot in elilo.conf
|
|
|
+def add_elilo_entry(config, snapshot):
|
|
|
+ entry = f"""
|
|
|
+image=vmlinuz
|
|
|
+ label={snapshot}
|
|
|
+ root={config['elilo']['root_partition']}
|
|
|
+ append="rootflags=subvol={config['snapshot']['snapshot_dir']}/{snapshot} ro"
|
|
|
+ initrd=initrd.gz
|
|
|
+"""
|
|
|
+
|
|
|
+ # Append to elilo.conf if the entry doesn't already exist
|
|
|
+ elilo_conf = config['elilo']['elilo_conf']
|
|
|
+ with open(elilo_conf, 'r+') as f:
|
|
|
+ content = f.read()
|
|
|
+ if snapshot not in content:
|
|
|
+ print(f"Adding entry for snapshot: {snapshot}")
|
|
|
+ f.write(entry)
|
|
|
+
|
|
|
+# Remove an entry for a deleted snapshot from elilo.conf
|
|
|
+def remove_elilo_entry(config, snapshot):
|
|
|
+ elilo_conf = config['elilo']['elilo_conf']
|
|
|
+ with open(elilo_conf, 'r') as f:
|
|
|
+ lines = f.readlines()
|
|
|
+
|
|
|
+ with open(elilo_conf, 'w') as f:
|
|
|
+ for line in lines:
|
|
|
+ if snapshot not in line:
|
|
|
+ f.write(line)
|
|
|
+
|
|
|
+ print(f"Removed entry for snapshot: {snapshot}")
|
|
|
+
|
|
|
+# List all current snapshots
|
|
|
+def list_snapshots(config):
|
|
|
+ snapshots = []
|
|
|
+ for entry in os.listdir(config['snapshot']['snapshot_dir']):
|
|
|
+ entry_path = os.path.join(config['snapshot']['snapshot_dir'], entry)
|
|
|
+ if os.path.isdir(entry_path) and entry.startswith(config['snapshot']['snapshot_prefix']):
|
|
|
+ snapshots.append(entry)
|
|
|
+ return snapshots
|
|
|
+
|
|
|
+# Remove snapshots older than the retention period
|
|
|
+def remove_old_snapshots(config):
|
|
|
+ retention_days = config['snapshot']['retention_days']
|
|
|
+ now = datetime.now()
|
|
|
+
|
|
|
+ for snapshot in list_snapshots(config):
|
|
|
+ snapshot_path = os.path.join(config['snapshot']['snapshot_dir'], snapshot)
|
|
|
+ created_time = datetime.fromtimestamp(os.path.getctime(snapshot_path))
|
|
|
+ if (now - created_time).days > retention_days:
|
|
|
+ # Remove snapshot
|
|
|
+ cmd = ["btrfs", "subvolume", "delete", snapshot_path]
|
|
|
+ subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
|
+ remove_elilo_entry(config, snapshot)
|
|
|
+ print(f"Removed snapshot: {snapshot}")
|
|
|
+
|
|
|
+# Function to wrap slackpkg upgrade
|
|
|
+def slackpkg_upgrade(config):
|
|
|
+ print("Preparing to run slackpkg upgrade...")
|
|
|
+ create_snapshot(config)
|
|
|
+ print("Running slackpkg upgrade...")
|
|
|
+ subprocess.run(["/usr/sbin/slackpkg", "upgrade-all"])
|
|
|
+
|
|
|
+# Function to wrap sbopkg -i
|
|
|
+def sbopkg_install(config, package):
|
|
|
+ print(f"Preparing to install package using sbopkg: {package}")
|
|
|
+ create_snapshot(config)
|
|
|
+ print(f"Running sbopkg -i {package}...")
|
|
|
+ subprocess.run(["/usr/sbin/sbopkg", "-i", package])
|
|
|
+
|
|
|
+def main():
|
|
|
+ # Load configuration from config.toml
|
|
|
+ config = read_config("config.toml")
|
|
|
+
|
|
|
+ # Step 1: Get list of current snapshots and add them to elilo.conf if needed
|
|
|
+ snapshots = list_snapshots(config)
|
|
|
+ for snapshot in snapshots:
|
|
|
+ add_elilo_entry(config, snapshot)
|
|
|
+
|
|
|
+ # Step 2: Remove snapshots older than retention period
|
|
|
+ remove_old_snapshots(config)
|
|
|
+
|
|
|
+if __name__ == "__main__":
|
|
|
+ main()
|