Compare commits
8 Commits
e7c1154372
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ca26e79b6 | |||
|
|
7ff660ba90 | ||
| 830dc7cdc3 | |||
|
|
042f0871d2 | ||
|
|
c5c55e156f | ||
|
|
383cd7e975 | ||
|
|
c48b65a253 | ||
|
|
397d480141 |
41
README.md
Normal file
41
README.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
### **📌 How to Use**
|
||||||
|
|
||||||
|
#### **1️⃣ Create the Directory List File**
|
||||||
|
|
||||||
|
Example: `/opt/AZURE/dir2sync_list`
|
||||||
|
|
||||||
|
```plaintext
|
||||||
|
/opt/AZURE/BLOB > testcontainer115
|
||||||
|
/opt/AZURE/OTHERBLOB > testcontainer115b
|
||||||
|
/opt/AZURE/EXTRABLOB > testcontainer_extra
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### **2️⃣ Run the Script**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./run_azcopy.sh /opt/AZURE/dir2sync_list true 20
|
||||||
|
```
|
||||||
|
|
||||||
|
- `true` → Enables logging.
|
||||||
|
- `20` → Limits bandwidth to **20 Mbps**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### **3️⃣ Cron Job (Runs Every Hour)**
|
||||||
|
```bash
|
||||||
|
0 * * * * /opt/AZURE/run_azcopy.sh /opt/AZURE/dir2sync_list true 20
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **✅ Key Features**
|
||||||
|
✅ **Prevents multiple instances** using a lock file (`/tmp/run_azcopy.lock`).
|
||||||
|
✅ **Reads a file with directory-to-container mappings.**
|
||||||
|
✅ **Validates each source directory before syncing.**
|
||||||
|
✅ **Checks if the destination container exists** (test write).
|
||||||
|
✅ **Stops immediately on any error** (clean runs only).
|
||||||
|
✅ **Monitors `azcopy` every 30 seconds** and stops if business hours begin.
|
||||||
|
✅ **Processes all directories sequentially using an array (fixing loop issue).**
|
||||||
|
✅ **Uses one log file for the entire run.**
|
||||||
1
dir2sync_list
Normal file
1
dir2sync_list
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/opt/AZURE/BLOB > testcontainer115
|
||||||
90
howto.md
90
howto.md
@@ -1,90 +0,0 @@
|
|||||||
# **Azure Blob Sync Script - How To Use**
|
|
||||||
|
|
||||||
This script syncs a directory to **Azure Blob Storage** using `azcopy` while:
|
|
||||||
✅ **Avoiding business hours** (default: 9 AM - 5 PM, configurable).
|
|
||||||
✅ **Preventing duplicate instances** (via a lock file).
|
|
||||||
✅ **Automatically resuming** unfinished jobs.
|
|
||||||
✅ **Logging progress & generating reports**.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## **📌 1. Script Usage**
|
|
||||||
Run the script manually:
|
|
||||||
```bash
|
|
||||||
./run_azcopy.sh <directory> [log=true|false] [bandwidth_mbps]
|
|
||||||
```
|
|
||||||
### **Example Commands**
|
|
||||||
- **Basic sync with no bandwidth limit:**
|
|
||||||
```bash
|
|
||||||
./run_azcopy.sh /opt/AZURE/ false
|
|
||||||
```
|
|
||||||
- **Enable logging & limit bandwidth to 10 Mbps:**
|
|
||||||
```bash
|
|
||||||
./run_azcopy.sh /opt/AZURE/ true 10
|
|
||||||
```
|
|
||||||
- **Run in the background & detach from terminal:**
|
|
||||||
```bash
|
|
||||||
nohup ./run_azcopy.sh /opt/AZURE/ true 10 & disown
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## **⏲️ 2. Automating with Cron**
|
|
||||||
Schedule the script to **run every hour**:
|
|
||||||
```bash
|
|
||||||
crontab -e
|
|
||||||
```
|
|
||||||
Add this line:
|
|
||||||
```bash
|
|
||||||
0 * * * * /path/to/run_azcopy.sh /opt/AZURE/ true 10
|
|
||||||
```
|
|
||||||
### **How It Works**
|
|
||||||
- Runs at **00 minutes past every hour** (e.g., 1:00, 2:00, 3:00, etc.).
|
|
||||||
- If already running, the **next cron execution exits** to prevent duplicates.
|
|
||||||
- If interrupted (e.g., business hours), the **next run resumes**.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## **🔍 3. Checking If the Script Is Running**
|
|
||||||
Check if `azcopy` or the script is running:
|
|
||||||
```bash
|
|
||||||
pgrep -fl run_azcopy.sh
|
|
||||||
pgrep -fl azcopy
|
|
||||||
```
|
|
||||||
To **stop it manually**:
|
|
||||||
```bash
|
|
||||||
pkill -f azcopy
|
|
||||||
pkill -f run_azcopy.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## **📄 4. Checking Logs & Reports**
|
|
||||||
- **Sync Log (if enabled)**:
|
|
||||||
```bash
|
|
||||||
tail -f azcopy_log_*.txt
|
|
||||||
```
|
|
||||||
- **Completion Report**:
|
|
||||||
```bash
|
|
||||||
cat completion_report_*.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## **⚙️ 5. Customizing Business Hours**
|
|
||||||
Modify the script to change business hours:
|
|
||||||
```bash
|
|
||||||
BUSINESS_HOURS_START=9
|
|
||||||
BUSINESS_HOURS_END=17
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## **✅ 6. Expected Behavior**
|
|
||||||
| Scenario | What Happens? |
|
|
||||||
|----------|--------------|
|
|
||||||
| **Cron runs script inside business hours** | Script exits immediately. |
|
|
||||||
| **Script is running when cron starts again** | Second instance exits to prevent duplicates. |
|
|
||||||
| **Sync job interrupted by business hours** | Next run resumes automatically. |
|
|
||||||
| **Sync completes normally** | Report logs all transferred files. |
|
|
||||||
|
|
||||||
11
notes
Normal file
11
notes
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
cron job using the users cron tab.
|
||||||
|
|
||||||
|
#0 * * * * /usr/bin/env bash -lc '/opt/AZURE/run_azcopy.sh /opt/AZURE/dir2sync_list true 20'
|
||||||
|
|
||||||
|
the baove runs every hour using a bash login shell this is needed so all VARIABLE expansions work correctly.
|
||||||
|
|
||||||
|
We run everything as the user no root.
|
||||||
|
|
||||||
|
there are checks and error hadling was created for some cases but motsliukly not all. So logs should be checked on a regular basis.
|
||||||
|
|
||||||
|
tested on a smal set of files.
|
||||||
59
run_azcopy-multi-dir-multi-container.sh
Normal file → Executable file
59
run_azcopy-multi-dir-multi-container.sh
Normal file → Executable file
@@ -4,29 +4,35 @@
|
|||||||
cd /opt/AZURE || exit 1
|
cd /opt/AZURE || exit 1
|
||||||
|
|
||||||
# Configurable variables
|
# Configurable variables
|
||||||
BUSINESS_HOURS_START=9
|
# Basic variables need for this scrip[t to operate correctly.
|
||||||
BUSINESS_HOURS_END=17
|
BUSINESS_HOURS_START=16
|
||||||
|
BUSINESS_HOURS_END=20
|
||||||
AZURE_ACCOUNT=""
|
AZURE_ACCOUNT=""
|
||||||
AZURE_SAS=""
|
AZURE_SAS=""
|
||||||
|
|
||||||
LOCK_FILE="/tmp/run_azcopy.lock"
|
LOCK_FILE="/tmp/run_azcopy.lock"
|
||||||
|
|
||||||
# Arguments
|
# Arguments
|
||||||
|
# From the comand line. the first is mandatory. There is a check for it if its not provided.
|
||||||
SOURCE_LIST_FILE="$1"
|
SOURCE_LIST_FILE="$1"
|
||||||
LOGGING="${2:-false}" # Default to false
|
LOGGING="${2:-false}" # Default to false
|
||||||
BANDWIDTH_CAP="${3:-0}" # Default is 0 (no cap)
|
BANDWIDTH_CAP="${3:-0}" # Default is 0 (no cap)
|
||||||
|
|
||||||
# Report files
|
# Report files
|
||||||
|
# A bunch of temp files used to generate logs and a simple completion report.
|
||||||
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
|
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
|
||||||
LOG_FILE="azcopy_log_$TIMESTAMP.txt"
|
LOG_FILE="azcopy_log_$TIMESTAMP.txt"
|
||||||
COMPLETION_REPORT="completion_report_$TIMESTAMP.txt"
|
COMPLETION_REPORT="completion_report_$TIMESTAMP.txt"
|
||||||
|
|
||||||
# Ensure source list file is provided
|
# Ensure source list file is provided
|
||||||
|
# This the check for source files no ne3ed to run if that is not present.
|
||||||
if [[ -z "$SOURCE_LIST_FILE" || ! -f "$SOURCE_LIST_FILE" ]]; then
|
if [[ -z "$SOURCE_LIST_FILE" || ! -f "$SOURCE_LIST_FILE" ]]; then
|
||||||
echo "Usage: $0 <directory_list_file> [log=true|false] [bandwidth_mbps]"
|
echo "Usage: $0 <directory_list_file> [log=true|false] [bandwidth_mbps]"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Lock file to prevent multiple instances
|
# Lock file to prevent multiple instances
|
||||||
|
# Part of checks to prevent doubling of running proccesses.
|
||||||
if [[ -f "$LOCK_FILE" ]]; then
|
if [[ -f "$LOCK_FILE" ]]; then
|
||||||
PID=$(cat "$LOCK_FILE")
|
PID=$(cat "$LOCK_FILE")
|
||||||
if kill -0 "$PID" 2>/dev/null; then
|
if kill -0 "$PID" 2>/dev/null; then
|
||||||
@@ -40,12 +46,15 @@ fi
|
|||||||
echo $$ > "$LOCK_FILE"
|
echo $$ > "$LOCK_FILE"
|
||||||
|
|
||||||
# Function to check business hours
|
# Function to check business hours
|
||||||
|
# This will ensure we do not run at times when the server might need to do other things.
|
||||||
is_business_hours() {
|
is_business_hours() {
|
||||||
HOUR=$(printf "%d" "$(date +%H)") # Convert to decimal safely
|
HOUR=$(date +%H | sed 's/^0*//') # Remove leading zeros causing errors at morning times
|
||||||
|
#HOUR=$(printf "%d" "$(date +%H)") # Convert to decimal safely / this had an issue for some reason not working
|
||||||
[[ $HOUR -ge $BUSINESS_HOURS_START && $HOUR -lt $BUSINESS_HOURS_END ]]
|
[[ $HOUR -ge $BUSINESS_HOURS_START && $HOUR -lt $BUSINESS_HOURS_END ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
# Stop if running during business hours
|
# Stop if running during business hours
|
||||||
|
# Uses the previous funcion to kill the procces if needed.
|
||||||
if is_business_hours; then
|
if is_business_hours; then
|
||||||
echo "Business hours detected ($BUSINESS_HOURS_START:00 - $BUSINESS_HOURS_END:00). Exiting..."
|
echo "Business hours detected ($BUSINESS_HOURS_START:00 - $BUSINESS_HOURS_END:00). Exiting..."
|
||||||
rm -f "$LOCK_FILE"
|
rm -f "$LOCK_FILE"
|
||||||
@@ -54,8 +63,16 @@ fi
|
|||||||
|
|
||||||
echo "Starting sync job at $(date)" | tee -a "$LOG_FILE"
|
echo "Starting sync job at $(date)" | tee -a "$LOG_FILE"
|
||||||
|
|
||||||
# Loop through directories in the list
|
# Read the directory list file into an array
|
||||||
while IFS=">" read -r SOURCE_DIR DEST_CONTAINER; do
|
# This is used like that becouse of how cron uses a seperate shell enviroment.
|
||||||
|
mapfile -t SYNC_JOBS < "$SOURCE_LIST_FILE"
|
||||||
|
|
||||||
|
# The actual part of the script that does the job.
|
||||||
|
# Loops through the array and process each entry
|
||||||
|
# This also does a check to kill the process if it does not complete before the restriction window apply.
|
||||||
|
# Also checks if a given container exists will stop if it does not.
|
||||||
|
for LINE in "${SYNC_JOBS[@]}"; do
|
||||||
|
IFS=">" read -r SOURCE_DIR DEST_CONTAINER <<< "$LINE"
|
||||||
SOURCE_DIR=$(echo "$SOURCE_DIR" | xargs) # Trim spaces
|
SOURCE_DIR=$(echo "$SOURCE_DIR" | xargs) # Trim spaces
|
||||||
DEST_CONTAINER=$(echo "$DEST_CONTAINER" | xargs) # Trim spaces
|
DEST_CONTAINER=$(echo "$DEST_CONTAINER" | xargs) # Trim spaces
|
||||||
|
|
||||||
@@ -72,49 +89,41 @@ while IFS=">" read -r SOURCE_DIR DEST_CONTAINER; do
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
DEST_URL="$AZURE_ACCOUNT/$DEST_CONTAINER"
|
DEST_URL="$AZURE_ACCOUNT/$DEST_CONTAINER"
|
||||||
|
|
||||||
echo "Syncing $SOURCE_DIR to container: $DEST_CONTAINER" | tee -a "$LOG_FILE"
|
echo "Syncing $SOURCE_DIR to container: $DEST_CONTAINER" | tee -a "$LOG_FILE"
|
||||||
|
|
||||||
# Check if the container exists by attempting to write a small test file
|
# Run azcopy in the background (one directory at a time)
|
||||||
TEST_FILE="$SOURCE_DIR/.azcopy_test_file"
|
|
||||||
touch "$TEST_FILE"
|
|
||||||
azcopy cp "$TEST_FILE" "$DEST_URL?$AZURE_SAS" > /dev/null 2>&1
|
|
||||||
if [[ $? -ne 0 ]]; then
|
|
||||||
echo "ERROR: Destination container $DEST_CONTAINER does not exist or is inaccessible. Exiting." | tee -a "$LOG_FILE"
|
|
||||||
rm -f "$TEST_FILE"
|
|
||||||
rm -f "$LOCK_FILE"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
rm -f "$TEST_FILE"
|
|
||||||
|
|
||||||
# Run azcopy for actual sync in the background
|
|
||||||
if [[ "$LOGGING" == "true" ]]; then
|
if [[ "$LOGGING" == "true" ]]; then
|
||||||
azcopy sync "$SOURCE_DIR" "$DEST_URL?$AZURE_SAS" --recursive --cap-mbps "$BANDWIDTH_CAP" | tee -a "$LOG_FILE" &
|
# @05-03-2025 testing copy instead of sync due to issues after archiving files in the blob
|
||||||
|
# azcopy sync "$SOURCE_DIR" "$DEST_URL?$AZURE_SAS" --recursive --cap-mbps "$BANDWIDTH_CAP" | tee -a "$LOG_FILE" &
|
||||||
|
azcopy copy "$SOURCE_DIR" "$DEST_URL?$AZURE_SAS" --overwrite false --recursive --cap-mbps "$BANDWIDTH_CAP" | tee -a "$LOG_FILE" &
|
||||||
else
|
else
|
||||||
azcopy sync "$SOURCE_DIR" "$DEST_URL?$AZURE_SAS" --recursive --cap-mbps "$BANDWIDTH_CAP" > /dev/null 2>&1 &
|
# @05-03-2025 testing copy instead of sync due to issues after archiving files in the blob
|
||||||
|
# azcopy sync "$SOURCE_DIR" "$DEST_URL?$AZURE_SAS" --recursive --cap-mbps "$BANDWIDTH_CAP" > /dev/null 2>&1 &
|
||||||
|
azcopy copy "$SOURCE_DIR" "$DEST_URL?$AZURE_SAS" --overwrite false --recursive --cap-mbps "$BANDWIDTH_CAP" > /dev/null 2>&1 &
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AZCOPY_PID=$!
|
AZCOPY_PID=$!
|
||||||
|
|
||||||
# Monitor the process
|
# Monitor the process every 30 seconds
|
||||||
while kill -0 $AZCOPY_PID 2>/dev/null; do
|
while kill -0 $AZCOPY_PID 2>/dev/null; do
|
||||||
if is_business_hours; then
|
if is_business_hours; then
|
||||||
echo -e "\nBusiness hours started! Stopping azcopy..." | tee -a "$LOG_FILE"
|
echo -e "\nBusiness hours started! Stopping azcopy..." | tee -a "$LOG_FILE"
|
||||||
kill $AZCOPY_PID
|
kill $AZCOPY_PID
|
||||||
wait $AZCOPY_PID 2>/dev/null # Ensure the process is fully stopped
|
wait $AZCOPY_PID 2>/dev/null # Ensure process stops completely
|
||||||
rm -f "$LOCK_FILE"
|
rm -f "$LOCK_FILE"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
sleep 30 # Check every 30 seconds
|
sleep 30 # Check every 30 seconds
|
||||||
done
|
done
|
||||||
|
|
||||||
# Check for sync failure
|
# Check if sync failed
|
||||||
if [[ $? -ne 0 ]]; then
|
if [[ $? -ne 0 ]]; then
|
||||||
echo "ERROR: Sync failed for $SOURCE_DIR to $DEST_CONTAINER. Stopping script." | tee -a "$LOG_FILE"
|
echo "ERROR: Sync failed for $SOURCE_DIR to $DEST_CONTAINER. Stopping script." | tee -a "$LOG_FILE"
|
||||||
rm -f "$LOCK_FILE"
|
rm -f "$LOCK_FILE"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
done < "$SOURCE_LIST_FILE"
|
done
|
||||||
|
|
||||||
echo "All directories synced successfully!" | tee -a "$LOG_FILE"
|
echo "All directories synced successfully!" | tee -a "$LOG_FILE"
|
||||||
|
|
||||||
|
|||||||
55
run_azcopy-rotae-log.md
Normal file
55
run_azcopy-rotae-log.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
##Log rotate
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# /etc/logrotate.d/azure_logs
|
||||||
|
|
||||||
|
/opt/AZURE/*.txt {
|
||||||
|
weekly
|
||||||
|
missingok
|
||||||
|
rotate 4
|
||||||
|
compress
|
||||||
|
delaycompress
|
||||||
|
notifempty
|
||||||
|
create 0644 root root
|
||||||
|
}
|
||||||
|
|
||||||
|
~/.azcopy/*.log {
|
||||||
|
weekly
|
||||||
|
missingok
|
||||||
|
rotate 4
|
||||||
|
compress
|
||||||
|
delaycompress
|
||||||
|
notifempty
|
||||||
|
create 0644 root root
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explanation:
|
||||||
|
- **weekly**: Rotate the logs on a weekly basis.
|
||||||
|
- **missingok**: If the log file is missing, go on to the next one without issuing an error message.
|
||||||
|
- **rotate 4**: Keep only the last 4 weeks of logs.
|
||||||
|
- **compress**: Compress the rotated logs using gzip.
|
||||||
|
- **delaycompress**: Delay compression until the next rotation cycle. This means the current log file will not be compressed immediately after rotation, but the previous log files will be.
|
||||||
|
- **notifempty**: Do not rotate the log if it is empty.
|
||||||
|
- **create 0644 root root**: Create new log files with owner `root` and group `root`, and permissions `0644`.
|
||||||
|
|
||||||
|
### Steps to Apply the Configuration:
|
||||||
|
1. Save the above configuration in `/etc/logrotate.d/azure_logs`.
|
||||||
|
2. Ensure that the `logrotate` service is enabled and running on your system.
|
||||||
|
3. Test the logrotate configuration with the following command to ensure there are no syntax errors:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo logrotate -d /etc/logrotate.d/azure_logs
|
||||||
|
```
|
||||||
|
|
||||||
|
The `-d` option runs logrotate in debug mode, which will show you what actions would be taken without actually performing them.
|
||||||
|
|
||||||
|
4. If everything looks good, you can force a rotation to test it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo logrotate -f /etc/logrotate.d/azure_logs
|
||||||
|
```
|
||||||
|
|
||||||
|
This will rotate the logs immediately according to the specified configuration.
|
||||||
|
|
||||||
|
By following these steps, your logs in `/opt/AZURE` and `~/.azcopy` should be rotated weekly, compressed, and kept for only the last 4 weeks.
|
||||||
13
run_azcopy-single-dir.sh
Executable file → Normal file
13
run_azcopy-single-dir.sh
Executable file → Normal file
@@ -1,15 +1,18 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Enter the specific 'work directory'Ensure we collect logs and other files in the one place.
|
||||||
|
cd /opt/AZURE || exit 1
|
||||||
|
|
||||||
# Configurable variables
|
# Configurable variables
|
||||||
BUSINESS_HOURS_START=7
|
BUSINESS_HOURS_START=9
|
||||||
BUSINESS_HOURS_END=15
|
BUSINESS_HOURS_END=20
|
||||||
AZURE_URL="https://<>.core.windows.net/<container>"
|
AZURE_URL=""
|
||||||
AZURE_SAS="<add key here>"
|
AZURE_SAS=""
|
||||||
|
|
||||||
# Arguments
|
# Arguments
|
||||||
SOURCE_DIR="$1"
|
SOURCE_DIR="$1"
|
||||||
LOGGING="${2:-false}" # Default to no logs
|
LOGGING="${2:-false}" # Default to no logs
|
||||||
BANDWIDTH_CAP="${3:-0}" # Default is 0 (no cap)
|
BANDWIDTH_CAP="${3:-0}" # Default is 0 (no bw limit)
|
||||||
|
|
||||||
# Report files
|
# Report files
|
||||||
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
|
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
|
||||||
|
|||||||
Reference in New Issue
Block a user