From 0ad10c690e36540c2221982b90f3807d4ba06a0c Mon Sep 17 00:00:00 2001 From: Ayomide Korede Date: Wed, 1 Apr 2026 23:05:40 +0100 Subject: [PATCH 1/2] feat: complete bash toolkit scripts --- README.md | 66 ++++++++++++++++++++++++ logs/app.log | 1 + run_all.sh | 64 ++++++++++++++++++++++++ scripts/backup.sh | 38 ++++++++++++++ scripts/file_manager.sh | 100 +++++++++++++++++++++++++++++++++++++ scripts/process_monitor.sh | 43 ++++++++++++++++ scripts/system_check.sh | 43 ++++++++++++++++ scripts/user_info.sh | 37 ++++++++++++++ 8 files changed, 392 insertions(+) create mode 100644 logs/app.log create mode 100755 run_all.sh create mode 100755 scripts/backup.sh create mode 100755 scripts/file_manager.sh create mode 100755 scripts/process_monitor.sh create mode 100755 scripts/system_check.sh create mode 100755 scripts/user_info.sh diff --git a/README.md b/README.md index 07a3112..03e6586 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ + # 🚀 DevOps Bash Toolkit Assessment ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/your-username/devops-bash-toolkit/grade.yml) @@ -228,3 +229,68 @@ logs/app.log * Handle script failures gracefully **Submission link:** [CLICK HERE](https://forms.gle/jrhpKjXsQXZxLopN6) +# DevOps Bash Toolkit Assessment + +## Overview +This project contains Bash scripts that demonstrate DevOps fundamentals including: +- Bash scripting +- System monitoring +- Logging +- File management +- Backup automation +- Git workflow + +## Scripts + +### 1. user_info.sh +Prompts the user for name, age, and country. +Validates age input and classifies user as Minor, Adult, or Senior. +Logs output to `logs/user_info.log`. + +### 2. system_check.sh +Displays: +- Disk usage +- Memory usage +- CPU load +- Disk usage warnings above 80% +- Total running processes +- Top 5 memory-consuming processes + +Logs output to `logs/system_report_.log`. + +### 3. file_manager.sh +Supports: +- create +- delete +- list +- rename + +Logs actions to `logs/file_manager.log`. + +### 4. backup.sh +Creates compressed backups of a given directory in `backups/`. +Keeps only the latest 5 backups. +Logs actions to `logs/backup.log`. + +### 5. process_monitor.sh +Optional bonus script. +Checks if a monitored process is running and simulates restart if not. +Logs actions to `logs/process_monitor.log`. + +### 6. run_all.sh +Optional bonus script with interactive menu. +Uses `set -euo pipefail` and logs actions to `logs/app.log`. + +## How to Run + +```bash +./scripts/user_info.sh +./scripts/system_check.sh +./scripts/file_manager.sh create test.txt +./scripts/file_manager.sh list +./scripts/file_manager.sh rename test.txt new.txt +./scripts/file_manager.sh delete new.txt +./scripts/backup.sh scripts +./scripts/process_monitor.sh nginx +./run_all.sh + diff --git a/logs/app.log b/logs/app.log new file mode 100644 index 0000000..7ae4316 --- /dev/null +++ b/logs/app.log @@ -0,0 +1 @@ +[2026-04-01 23:04:25] Exiting application. diff --git a/run_all.sh b/run_all.sh new file mode 100755 index 0000000..d8f20f5 --- /dev/null +++ b/run_all.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +set -euo pipefail + +mkdir -p logs +LOG_FILE="logs/app.log" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" +} + +run_system_check() { + log "Running system check..." + if ./scripts/system_check.sh; then + log "System check completed successfully." + else + log "System check failed." + fi +} + +run_backup() { + read -rp "Enter directory to back up: " dir + log "Running backup for directory: $dir" + if ./scripts/backup.sh "$dir"; then + log "Backup completed successfully." + else + log "Backup failed." + fi +} + +run_all_scripts() { + log "Running all available scripts..." + ./scripts/system_check.sh || log "system_check.sh failed" + ./scripts/user_info.sh || log "user_info.sh failed" + + read -rp "Enter directory to back up for run all: " dir + ./scripts/backup.sh "$dir" || log "backup.sh failed" +} + +show_menu() { + echo + echo "===== DevOps Bash Toolkit =====" + echo "1. Run all" + echo "2. System check" + echo "3. Backup" + echo "4. Exit" +} + +while true; do + show_menu + read -rp "Choose an option: " choice + + case "$choice" in + 1) run_all_scripts ;; + 2) run_system_check ;; + 3) run_backup ;; + 4) + log "Exiting application." + exit 0 + ;; + *) + echo "Invalid option. Try again." + ;; + esac +done diff --git a/scripts/backup.sh b/scripts/backup.sh new file mode 100755 index 0000000..504b458 --- /dev/null +++ b/scripts/backup.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +mkdir -p logs backups +LOG_FILE="logs/backup.log" + +if [[ $# -ne 1 ]]; then + echo "Usage: $0 " + exit 1 +fi + +source_dir="$1" +timestamp="$(date '+%Y-%m-%d_%H-%M-%S')" + +if [[ ! -d "$source_dir" ]]; then + message="[$(date '+%Y-%m-%d %H:%M:%S')] Error: Directory '$source_dir' does not exist." + echo "$message" + echo "$message" >> "$LOG_FILE" + exit 1 +fi + +base_name="$(basename "$source_dir")" +backup_file="backups/backup_${base_name}_${timestamp}.tar.gz" + +if tar -czf "$backup_file" "$source_dir"; then + message="[$(date '+%Y-%m-%d %H:%M:%S')] Backup created: $backup_file" + echo "$message" + echo "$message" >> "$LOG_FILE" +else + message="[$(date '+%Y-%m-%d %H:%M:%S')] Backup failed for: $source_dir" + echo "$message" + echo "$message" >> "$LOG_FILE" + exit 1 +fi + +ls -1t backups/backup_*.tar.gz 2>/dev/null | tail -n +6 | while read -r old_backup; do + rm -f "$old_backup" + echo "[$(date '+%Y-%m-%d %H:%M:%S')] Deleted old backup: $old_backup" >> "$LOG_FILE" +done diff --git a/scripts/file_manager.sh b/scripts/file_manager.sh new file mode 100755 index 0000000..9935072 --- /dev/null +++ b/scripts/file_manager.sh @@ -0,0 +1,100 @@ +#!/usr/bin/env bash +mkdir -p logs +LOG_FILE="logs/file_manager.log" + +usage() { + echo "Usage:" + echo " $0 create " + echo " $0 delete " + echo " $0 list" + echo " $0 rename " +} + +log_action() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE" +} + +if [[ $# -lt 1 ]]; then + usage + exit 1 +fi + +command="$1" + +case "$command" in + create) + if [[ $# -ne 2 ]]; then + usage + exit 1 + fi + + file="$2" + + if [[ -e "$file" ]]; then + echo "Error: '$file' already exists. Will not overwrite." + log_action "CREATE FAILED: '$file' already exists." + exit 1 + fi + + touch "$file" + echo "File '$file' created successfully." + log_action "CREATED: '$file'" + ;; + + delete) + if [[ $# -ne 2 ]]; then + usage + exit 1 + fi + + file="$2" + + if [[ ! -e "$file" ]]; then + echo "Error: '$file' does not exist." + log_action "DELETE FAILED: '$file' does not exist." + exit 1 + fi + + rm -f "$file" + echo "File '$file' deleted successfully." + log_action "DELETED: '$file'" + ;; + + list) + ls -lah + log_action "LIST executed." + ;; + + rename) + if [[ $# -ne 3 ]]; then + usage + exit 1 + fi + + oldname="$2" + newname="$3" + + if [[ ! -e "$oldname" ]]; then + echo "Error: '$oldname' does not exist." + log_action "RENAME FAILED: '$oldname' does not exist." + exit 1 + fi + + if [[ -e "$newname" ]]; then + echo "Error: '$newname' already exists. Will not overwrite." + log_action "RENAME FAILED: '$newname' already exists." + exit 1 + fi + + mv "$oldname" "$newname" + echo "Renamed '$oldname' to '$newname'." + log_action "RENAMED: '$oldname' -> '$newname'" + ;; + + *) + usage + exit 1 + ;; +esac + + diff --git a/scripts/process_monitor.sh b/scripts/process_monitor.sh new file mode 100755 index 0000000..569f018 --- /dev/null +++ b/scripts/process_monitor.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +mkdir -p logs +LOG_FILE="logs/process_monitor.log" +services=("nginx" "ssh" "docker") + +if [[ $# -ne 1 ]]; then + echo "Usage: $0 " + echo "Allowed examples: ${services[*]}" + exit 1 +fi + +process_name="$1" +timestamp="$(date '+%Y-%m-%d %H:%M:%S')" + +is_allowed=false +for service in "${services[@]}"; do + if [[ "$service" == "$process_name" ]]; then + is_allowed=true + break + fi +done + +if [[ "$is_allowed" == false ]]; then + message="[$timestamp] '$process_name' is not in the monitored services list: ${services[*]}" + echo "$message" + echo "$message" >> "$LOG_FILE" + exit 1 +fi + +if pgrep -x "$process_name" >/dev/null 2>&1; then + message="[$timestamp] $process_name: Running" + echo "$message" + echo "$message" >> "$LOG_FILE" +else + message="[$timestamp] $process_name: Stopped. Simulating restart..." + echo "$message" + echo "$message" >> "$LOG_FILE" + + restart_message="[$timestamp] $process_name: Restarted" + echo "$restart_message" + echo "$restart_message" >> "$LOG_FILE" +fi diff --git a/scripts/system_check.sh b/scripts/system_check.sh new file mode 100755 index 0000000..2f9a91c --- /dev/null +++ b/scripts/system_check.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +mkdir -p logs +DATE_STAMP="$(date '+%Y-%m-%d_%H-%M-%S')" +LOG_FILE="logs/system_report_${DATE_STAMP}.log" + +{ + echo "===== SYSTEM CHECK REPORT =====" + echo "Generated at: $(date)" + echo + + echo "----- Disk Usage -----" + df -h + echo + + echo "----- Memory Usage -----" + free -m + echo + + echo "----- CPU Load -----" + uptime + echo + + echo "----- Disk Usage Warnings (>80%) -----" + df -hP | awk 'NR>1 { + gsub("%","",$5) + if ($5 > 80) { + print "WARNING: Filesystem " $1 " is at " $5 "% usage." + } + }' + echo + + echo "----- Total Running Processes -----" + ps -e --no-headers | wc -l + echo + + echo "----- Top 5 Memory-Consuming Processes -----" + ps -eo pid,comm,%mem,%cpu --sort=-%mem | head -n 6 + echo +} | tee "$LOG_FILE" + + + + diff --git a/scripts/user_info.sh b/scripts/user_info.sh new file mode 100755 index 0000000..2270e12 --- /dev/null +++ b/scripts/user_info.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +mkdir -p logs +LOG_FILE="logs/user_info.log" + +read -rp "Enter your name: " name +read -rp "Enter your age: " age +read -rp "Enter your country: " country + +timestamp="$(date '+%Y-%m-%d %H:%M:%S')" + +if [[ -z "$name" || -z "$age" || -z "$country" ]]; then + message="[$timestamp] Error: Missing input. Name, age, and country are required." + echo "$message" + echo "$message" >> "$LOG_FILE" + exit 1 +fi + +if ! [[ "$age" =~ ^[0-9]+$ ]]; then + message="[$timestamp] Error: Age must be numeric." + echo "$message" + echo "$message" >> "$LOG_FILE" + exit 1 +fi + +if (( age < 18 )); then + category="Minor" +elif (( age <= 65 )); then + category="Adult" +else + category="Senior" +fi + +message="[$timestamp] Hello, $name from $country. You are $age years old and classified as: $category." +echo "$message" +echo "$message" >> "$LOG_FILE" + From b7f2598ef0d9958f994cf44ebd4788348a954c08 Mon Sep 17 00:00:00 2001 From: Ayomide Korede Date: Thu, 2 Apr 2026 01:29:57 +0100 Subject: [PATCH 2/2] fix: ignore logs directory --- .gitignore | 3 +++ logs/app.log | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 .gitignore delete mode 100644 logs/app.log diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5f87a76 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +logs/ +backups/ +*.log diff --git a/logs/app.log b/logs/app.log deleted file mode 100644 index 7ae4316..0000000 --- a/logs/app.log +++ /dev/null @@ -1 +0,0 @@ -[2026-04-01 23:04:25] Exiting application.