ソースを参照

add logging to grafana

subDesTagesMitExtraKaese 3 ヶ月 前
コミット
363c2fff1e
6 ファイル変更574 行追加4 行削除
  1. 8 2
      .env.example
  2. 120 0
      README.md
  3. 401 0
      grafana_dashboard.json
  4. 37 0
      log_to_influx.sh
  5. 2 2
      run_backup.sh
  6. 6 0
      run_backup_process.sh

+ 8 - 2
.env.example

@@ -17,5 +17,11 @@ MOUNT_POINT="/mnt/external_hdd"
 
 # Borg Backup Details
 REPOSITORY="/mnt/external_hdd/backup_repo"
-SOURCE_DIRECTORIES="/path/to/your/data"
-PASSPHRASE="your_borg_passphrase"
+SOURCE_DIRECTORIES="/home /etc /var /usr /opt /srv /root /boot"
+PASSPHRASE="your_borg_passphrase"
+
+# Logging Details
+INFLUXDB_URL="http://your_server_ip:8086"
+INFLUXDB_ORG="org"
+INFLUXDB_BUCKET="borg"
+INFLUXDB_TOKEN="your_influx_token"

+ 120 - 0
README.md

@@ -0,0 +1,120 @@
+# Borg Backup Automation
+
+This project automates the process of running Borg backups on a Linux server. It includes scripts for managing external HDD power, mounting and unmounting the HDD, running the backup, and logging the results to InfluxDB. 
+
+## Table of Contents
+
+- [Project Structure](#project-structure)
+- [Installation](#installation)
+- [Configuration](#configuration)
+- [Usage](#usage)
+- [Scripts Overview](#scripts-overview)
+- [Contributing](#contributing)
+- [License](#license)
+
+## Project Structure
+
+```
+.
+├── power_on_hdd.sh            # Script to power on the external HDD
+├── power_off_hdd.sh           # Script to power off the external HDD
+├── mount_hdd.sh               # Script to mount the external HDD
+├── unmount_hdd.sh             # Script to unmount the external HDD
+├── check_battery.sh           # Script to check battery level before running the backup
+├── run_backup.sh              # Script to execute the Borg backup
+├── run_backup_process.sh      # Main script to automate the backup process
+├── log_to_influx.sh           # Script to log the backup results to InfluxDB
+├── grafana_dashboard.json     # Example Grafana dashboard for monitoring
+├── .env                       # Environment variables (ignored by Git)
+├── .env.example               # Example environment variables file
+├── .gitignore                 # Files and directories to be ignored by Git
+└── keys/                      # Directory for SSH keys (ignored by Git)
+```
+
+## Installation
+
+1. **Clone the repository:**
+   ```bash
+   git clone https://github.com/yourusername/borg-backup-automation.git
+   cd borg-backup-automation
+   ```
+
+2. **Set up your environment:**
+   - Copy the example `.env` file:
+     ```bash
+     cp .env.example .env
+     ```
+   - Edit `.env` with your specific configuration.
+
+3. **Ensure all scripts have executable permissions:**
+   ```bash
+   chmod +x *.sh
+   ```
+
+## Configuration
+
+The configuration is managed via the `.env` file. Below are the key variables you need to configure:
+
+- **Home Assistant Details:**
+  - `HA_URL`: URL of your Home Assistant instance.
+  - `HA_TOKEN`: Long-lived access token for Home Assistant.
+  - `HDD_SWITCH_ENTITY`: Home Assistant entity ID for controlling HDD power.
+  - `BATTERY_SENSOR_ENTITY`: Home Assistant entity ID for battery level monitoring.
+  - `MIN_BATTERY_LEVEL`: Minimum battery percentage required to run the backup.
+
+- **Server Details:**
+  - `SERVER_USER`: SSH user for the remote server.
+  - `SERVER_IP`: IP address of the remote server.
+  - `SSH_KEY`: Path to the SSH private key.
+  - `SSH_PORT`: SSH port (default: 22).
+
+- **HDD Mount Details:**
+  - `HDD_DEVICE`: Device path for the external HDD (e.g., `/dev/sdb1`).
+  - `MOUNT_POINT`: Mount point for the external HDD (e.g., `/mnt/external_hdd`).
+
+- **Borg Backup Details:**
+  - `REPOSITORY`: Path to the Borg backup repository on the mounted HDD.
+  - `SOURCE_DIRECTORIES`: Directories to back up.
+  - `PASSPHRASE`: Passphrase for the Borg repository.
+
+- **Logging Details:**
+  - `INFLUXDB_URL`: URL of your InfluxDB instance.
+  - `INFLUXDB_ORG`: Organization name for InfluxDB.
+  - `INFLUXDB_BUCKET`: InfluxDB bucket for storing backup logs.
+  - `INFLUXDB_TOKEN`: Authentication token for InfluxDB.
+
+## Usage
+
+Run the main backup process script:
+
+```bash
+./run_backup_process.sh
+```
+
+This script will:
+
+1. Check the battery level.
+2. Power on the external HDD.
+3. Mount the external HDD.
+4. Run the Borg backup.
+5. Log the backup results to InfluxDB.
+6. Unmount and power off the external HDD.
+
+## Scripts Overview
+
+- **power_on_hdd.sh:** Turns on the external HDD via Home Assistant.
+- **power_off_hdd.sh:** Turns off the external HDD via Home Assistant.
+- **mount_hdd.sh:** Mounts the external HDD to a specified mount point.
+- **unmount_hdd.sh:** Unmounts the external HDD.
+- **check_battery.sh:** Checks the battery level and exits if it’s below the specified threshold.
+- **run_backup.sh:** Executes the Borg backup using the configured source directories and repository.
+- **log_to_influx.sh:** Logs backup statistics to InfluxDB.
+- **run_backup_process.sh:** Main automation script that ties all the steps together.
+
+## Contributing
+
+Contributions are welcome! Please submit pull requests or open issues to suggest changes or report bugs.
+
+## License
+
+This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.

+ 401 - 0
grafana_dashboard.json

@@ -0,0 +1,401 @@
+{
+  "__inputs": [
+    {
+      "name": "DS_INFLUXDB",
+      "label": "InfluxDB",
+      "description": "",
+      "type": "datasource",
+      "pluginId": "influxdb",
+      "pluginName": "InfluxDB"
+    }
+  ],
+  "__elements": {},
+  "__requires": [
+    {
+      "type": "grafana",
+      "id": "grafana",
+      "name": "Grafana",
+      "version": "11.1.3"
+    },
+    {
+      "type": "datasource",
+      "id": "influxdb",
+      "name": "InfluxDB",
+      "version": "1.0.0"
+    },
+    {
+      "type": "panel",
+      "id": "stat",
+      "name": "Stat",
+      "version": ""
+    }
+  ],
+  "annotations": {
+    "list": [
+      {
+        "builtIn": 1,
+        "datasource": {
+          "type": "grafana",
+          "uid": "-- Grafana --"
+        },
+        "enable": true,
+        "hide": true,
+        "iconColor": "rgba(0, 211, 255, 1)",
+        "name": "Annotations & Alerts",
+        "type": "dashboard"
+      }
+    ]
+  },
+  "editable": true,
+  "fiscalYearStartMonth": 0,
+  "graphTooltip": 0,
+  "id": null,
+  "links": [],
+  "liveNow": false,
+  "panels": [
+    {
+      "collapsed": false,
+      "gridPos": {
+        "h": 1,
+        "w": 24,
+        "x": 0,
+        "y": 0
+      },
+      "id": 2,
+      "panels": [],
+      "repeat": "hostname",
+      "repeatDirection": "h",
+      "title": "${hostname}",
+      "type": "row"
+    },
+    {
+      "datasource": {
+        "type": "influxdb",
+        "uid": "${DS_INFLUXDB}"
+      },
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "fixedColor": "green",
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "red",
+                "value": null
+              },
+              {
+                "color": "orange",
+                "value": -604800
+              },
+              {
+                "color": "yellow",
+                "value": -172800
+              },
+              {
+                "color": "green",
+                "value": -86400
+              }
+            ]
+          },
+          "unit": "dtdurations"
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 7,
+        "w": 6,
+        "x": 0,
+        "y": 1
+      },
+      "id": 1,
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "auto",
+        "percentChangeColorMode": "standard",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "",
+          "values": false
+        },
+        "showPercentChange": false,
+        "textMode": "auto",
+        "wideLayout": true
+      },
+      "pluginVersion": "11.1.3",
+      "targets": [
+        {
+          "datasource": {
+            "type": "influxdb",
+            "uid": "${DS_INFLUXDB}"
+          },
+          "query": "from(bucket: \"borg\")\n  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n  |> filter(fn: (r) => r[\"_measurement\"] == \"info\")\n  |> filter(fn: (r) => r[\"hostname\"] == \"${hostname}\")\n  |> filter(fn: (r) => r[\"_field\"] == \"name\")\n  |> last()\n  |> map(fn: (r) => ({r with _value: (int(v: r[\"_time\"]) - int(v: now())) / 1000000000}))\n  |> yield(name: \"last\")",
+          "refId": "A"
+        }
+      ],
+      "title": "Last Backup",
+      "transparent": true,
+      "type": "stat"
+    },
+    {
+      "datasource": {
+        "type": "influxdb",
+        "uid": "${DS_INFLUXDB}"
+      },
+      "description": "",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "yellow",
+                "value": 109951162778
+              },
+              {
+                "color": "orange",
+                "value": 549755813888
+              },
+              {
+                "color": "red",
+                "value": 879609302231
+              }
+            ]
+          },
+          "unit": "bytes"
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 7,
+        "w": 10,
+        "x": 6,
+        "y": 1
+      },
+      "id": 3,
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "auto",
+        "percentChangeColorMode": "standard",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "",
+          "values": false
+        },
+        "showPercentChange": false,
+        "textMode": "auto",
+        "wideLayout": true
+      },
+      "pluginVersion": "11.1.3",
+      "targets": [
+        {
+          "datasource": {
+            "type": "influxdb",
+            "uid": "${DS_INFLUXDB}"
+          },
+          "query": "from(bucket: \"borg\")\n  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n  |> filter(fn: (r) => r[\"_measurement\"] == \"info\")\n  |> filter(fn: (r) => r[\"hostname\"] == \"${hostname}\")\n  |> filter(fn: (r) => r[\"_field\"] == \"original_size\" or r[\"_field\"] == \"deduplicated_size\" or r[\"_field\"] == \"compressed_size\")\n  |> drop(columns: [\"hostname\", \"repo_location\"])\n  |> yield(name: \"last\")",
+          "refId": "A"
+        }
+      ],
+      "title": "Size",
+      "transparent": true,
+      "type": "stat"
+    },
+    {
+      "datasource": {
+        "type": "influxdb",
+        "uid": "${DS_INFLUXDB}"
+      },
+      "description": "",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              },
+              {
+                "color": "yellow",
+                "value": 300
+              },
+              {
+                "color": "orange",
+                "value": 600
+              },
+              {
+                "color": "red",
+                "value": 1800
+              }
+            ]
+          },
+          "unit": "s"
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 7,
+        "w": 4,
+        "x": 16,
+        "y": 1
+      },
+      "id": 4,
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "auto",
+        "percentChangeColorMode": "standard",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "",
+          "values": false
+        },
+        "showPercentChange": false,
+        "textMode": "auto",
+        "wideLayout": true
+      },
+      "pluginVersion": "11.1.3",
+      "targets": [
+        {
+          "datasource": {
+            "type": "influxdb",
+            "uid": "${DS_INFLUXDB}"
+          },
+          "query": "from(bucket: \"borg\")\n  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n  |> filter(fn: (r) => r[\"_measurement\"] == \"info\")\n  |> filter(fn: (r) => r[\"hostname\"] == \"${hostname}\")\n  |> filter(fn: (r) => r[\"_field\"] == \"duration\")\n  |> drop(columns: [\"hostname\", \"repo_location\"])\n  |> yield(name: \"last\")",
+          "refId": "A"
+        }
+      ],
+      "title": "Duration",
+      "transparent": true,
+      "type": "stat"
+    },
+    {
+      "datasource": {
+        "type": "influxdb",
+        "uid": "${DS_INFLUXDB}"
+      },
+      "description": "",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "thresholds"
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              }
+            ]
+          },
+          "unit": "none"
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 7,
+        "w": 4,
+        "x": 20,
+        "y": 1
+      },
+      "id": 9,
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "auto",
+        "percentChangeColorMode": "standard",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "",
+          "values": false
+        },
+        "showPercentChange": false,
+        "textMode": "auto",
+        "wideLayout": true
+      },
+      "pluginVersion": "11.1.3",
+      "targets": [
+        {
+          "datasource": {
+            "type": "influxdb",
+            "uid": "${DS_INFLUXDB}"
+          },
+          "query": "from(bucket: \"borg\")\n  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n  |> filter(fn: (r) => r[\"_measurement\"] == \"info\")\n  |> filter(fn: (r) => r[\"hostname\"] == \"${hostname}\")\n  |> filter(fn: (r) => r[\"_field\"] == \"nfiles\")\n  |> drop(columns: [\"hostname\", \"repo_location\"])\n  |> yield(name: \"last\")",
+          "refId": "A"
+        }
+      ],
+      "title": "File count",
+      "transparent": true,
+      "type": "stat"
+    }
+  ],
+  "refresh": "",
+  "schemaVersion": 39,
+  "tags": [],
+  "templating": {
+    "list": [
+      {
+        "current": {},
+        "datasource": {
+          "type": "influxdb",
+          "uid": "${DS_INFLUXDB}"
+        },
+        "definition": "import \"influxdata/influxdb/schema\"\nschema.tagValues(\n    bucket: \"borg\",\n    tag: \"hostname\"\n)",
+        "hide": 0,
+        "includeAll": false,
+        "label": "Hostname",
+        "multi": true,
+        "name": "hostname",
+        "options": [],
+        "query": "import \"influxdata/influxdb/schema\"\nschema.tagValues(\n    bucket: \"borg\",\n    tag: \"hostname\"\n)",
+        "refresh": 1,
+        "regex": "",
+        "skipUrlSync": false,
+        "sort": 0,
+        "type": "query"
+      }
+    ]
+  },
+  "time": {
+    "from": "now-90d",
+    "to": "now"
+  },
+  "timepicker": {},
+  "timezone": "",
+  "title": "Backups",
+  "uid": "f75cc020-f0e2-4877-a276-b4aafe9c4a8b",
+  "version": 6,
+  "weekStart": ""
+}

+ 37 - 0
log_to_influx.sh

@@ -0,0 +1,37 @@
+#!/bin/bash
+
+# Load environment variables from .env file
+source .env
+
+# Export Borg passphrase
+export BORG_PASSPHRASE=$PASSPHRASE
+export BORG_RSH="ssh -i $SSH_KEY -p $SSH_PORT"
+
+json=`sudo -E borg info "$SERVER_USER@$SERVER_IP:$REPOSITORY" --last 1 --json` || exit 1
+
+count=`echo "$json" | jq '.archives | length'`
+data=""
+i=0
+while [ $i -lt $count ]; do
+  name=`echo "$json" | jq ".archives[$i].name"`
+  comment=`echo "$json" | jq ".archives[$i].comment"`
+  duration=`echo "$json" | jq ".archives[$i].duration"`
+  start=`echo "$json" | jq -r ".archives[$i].start"`
+  end=`echo "$json" | jq -r ".archives[$i].end"`
+  hostname=`echo "$json" | jq -r ".archives[$i].hostname"`
+  compressed_size=`echo "$json" | jq ".archives[$i].stats.compressed_size"`
+  deduplicated_size=`echo "$json" | jq ".archives[$i].stats.deduplicated_size"`
+  nfiles=`echo "$json" | jq ".archives[$i].stats.nfiles"`
+  original_size=`echo "$json" | jq ".archives[$i].stats.original_size"`
+  repo_location=`echo "$json" | jq -r '.repository.location'`
+
+  timestamp=`date --date="$start" +"%s"`
+  data="info,repo_location=$repo_location,hostname=$hostname name=$name,comment=$comment,duration=$duration,compressed_size=$compressed_size,deduplicated_size=$deduplicated_size,nfiles=$nfiles,original_size=$original_size $timestamp"
+  curl --request POST \
+    "$INFLUXDB_URL/api/v2/write?org=$INFLUXDB_ORG&bucket=$INFLUXDB_BUCKET&precision=s" \
+    --header "Authorization: Token $INFLUXDB_TOKEN" \
+    --header "Content-Type: text/plain; charset=utf-8" \
+    --header "Accept: application/json" \
+    --data-binary "$data"
+  i=$(($i+1))
+done

+ 2 - 2
run_backup.sh

@@ -19,7 +19,7 @@ done)
 # If we have valid directories, run the backup
 if [ -n "$EXISTING_DIRECTORIES" ]; then
     echo "Backing up directories: $EXISTING_DIRECTORIES"
-    sudo -E borg create --stats "$SERVER_USER@$SERVER_IP:$REPOSITORY::{hostname}-{now:%Y-%m-%d}" $EXISTING_DIRECTORIES
+    sudo -E borg create --stats "$SERVER_USER@$SERVER_IP:$REPOSITORY::{hostname}-{now}" $EXISTING_DIRECTORIES
     if [ $? -ne 0 ]; then
         echo "Borg backup failed."
         exit 1
@@ -30,7 +30,7 @@ else
 fi
 
 # Prune old backups using a custom SSH port
-borg prune --keep-daily=7 --keep-weekly=4 --keep-monthly=6 "$SERVER_USER@$SERVER_IP:$REPOSITORY"
+sudo -E borg prune --keep-daily=7 --keep-weekly=4 --keep-monthly=6 "$SERVER_USER@$SERVER_IP:$REPOSITORY"
 
 if [ $? -ne 0 ]; then
     echo "Borg prune failed."

+ 6 - 0
run_backup_process.sh

@@ -6,6 +6,8 @@ source .env
 # Function to handle errors
 handle_error() {
     echo "Error occurred in script: $1"
+    echo "Waiting before unmounting HDD..."
+    sleep 10
     # Trigger the cleanup process
     cleanup
     exit 1
@@ -43,6 +45,10 @@ echo "Mounting HDD..."
 echo "Running backup..."
 ./run_backup.sh || handle_error "run_backup.sh"
 
+# Log stats to influxdb
+echo "Logging backup to influxdb..."
+./log_to_influxdb.sh || handle_error "log_to_influxdb.sh"
+
 # Delay before unmounting
 echo "Waiting before unmounting HDD..."
 sleep 5