Sanitized mirror from private repository - 2026-03-18 10:31:50 UTC
This commit is contained in:
331
ansible/automation/playbooks/service_inventory.yml
Normal file
331
ansible/automation/playbooks/service_inventory.yml
Normal file
@@ -0,0 +1,331 @@
|
||||
---
|
||||
- name: Service Inventory and Documentation Generator
|
||||
hosts: all
|
||||
gather_facts: yes
|
||||
vars:
|
||||
inventory_timestamp: "{{ ansible_date_time.iso8601 }}"
|
||||
inventory_dir: "/tmp/service_inventory"
|
||||
documentation_dir: "/tmp/service_docs"
|
||||
|
||||
tasks:
|
||||
- name: Create inventory directories
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
loop:
|
||||
- "{{ inventory_dir }}"
|
||||
- "{{ documentation_dir }}"
|
||||
delegate_to: localhost
|
||||
run_once: true
|
||||
|
||||
- name: Check if Docker is available
|
||||
shell: command -v docker >/dev/null 2>&1
|
||||
register: docker_available
|
||||
changed_when: false
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Skip Docker tasks if not available
|
||||
set_fact:
|
||||
skip_docker: "{{ docker_available.rc != 0 }}"
|
||||
|
||||
- name: Discover running services
|
||||
shell: |
|
||||
echo "=== SERVICE DISCOVERY ==="
|
||||
|
||||
# System services (systemd)
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
echo "SYSTEMD_SERVICES:"
|
||||
systemctl list-units --type=service --state=active --no-legend | head -20 | while read service rest; do
|
||||
port_info=""
|
||||
# Try to extract port information from service files
|
||||
if systemctl show "$service" --property=ExecStart 2>/dev/null | grep -qE ":[0-9]+"; then
|
||||
port_info=$(systemctl show "$service" --property=ExecStart 2>/dev/null | grep -oE ":[0-9]+" | head -1)
|
||||
fi
|
||||
echo "$service$port_info"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Synology services (if available)
|
||||
if command -v synoservice >/dev/null 2>&1; then
|
||||
echo "SYNOLOGY_SERVICES:"
|
||||
synoservice --list 2>/dev/null | grep -E "^\[.*\].*running" | head -20
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Network services (listening ports)
|
||||
echo "NETWORK_SERVICES:"
|
||||
if command -v netstat >/dev/null 2>&1; then
|
||||
netstat -tuln 2>/dev/null | grep LISTEN | head -20
|
||||
elif command -v ss >/dev/null 2>&1; then
|
||||
ss -tuln 2>/dev/null | grep LISTEN | head -20
|
||||
fi
|
||||
echo ""
|
||||
register: system_services
|
||||
changed_when: false
|
||||
|
||||
- name: Discover Docker services
|
||||
shell: |
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
echo "Docker not available"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "=== DOCKER SERVICE DISCOVERY ==="
|
||||
|
||||
# Get detailed container information
|
||||
docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}" 2>/dev/null | while IFS=$'\t' read name image status ports; do
|
||||
if [ "$name" != "NAMES" ]; then
|
||||
echo "CONTAINER: $name"
|
||||
echo " Image: $image"
|
||||
echo " Status: $status"
|
||||
echo " Ports: $ports"
|
||||
|
||||
# Try to get more details
|
||||
labels=$(docker inspect "$name" --format '{{range $key, $value := .Config.Labels}}{{$key}}={{$value}}{{"\n"}}{{end}}' 2>/dev/null | head -5)
|
||||
if [ -n "$labels" ]; then
|
||||
echo " Labels:"
|
||||
echo "$labels" | sed 's/^/ /'
|
||||
fi
|
||||
|
||||
# Check for health status
|
||||
health=$(docker inspect "$name" --format '{{.State.Health.Status}}' 2>/dev/null)
|
||||
if [ "$health" != "<no value>" ] && [ -n "$health" ]; then
|
||||
echo " Health: $health"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
fi
|
||||
done
|
||||
register: docker_services
|
||||
changed_when: false
|
||||
when: not skip_docker
|
||||
|
||||
- name: Analyze service configurations
|
||||
shell: |
|
||||
echo "=== CONFIGURATION ANALYSIS ==="
|
||||
|
||||
# Find common configuration directories
|
||||
config_dirs="/etc /opt /home/*/config /volume1/docker"
|
||||
|
||||
echo "Configuration directories found:"
|
||||
for dir in $config_dirs; do
|
||||
if [ -d "$dir" ]; then
|
||||
# Look for common config files
|
||||
find "$dir" -maxdepth 3 -name "*.conf" -o -name "*.yaml" -o -name "*.yml" -o -name "*.json" -o -name "*.env" 2>/dev/null | head -10 | while read config_file; do
|
||||
if [ -r "$config_file" ]; then
|
||||
echo " $config_file"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
|
||||
# Docker Compose files
|
||||
echo "Docker Compose files:"
|
||||
find /opt /home -name "docker-compose*.yml" -o -name "compose*.yml" 2>/dev/null | head -10 | while read compose_file; do
|
||||
echo " $compose_file"
|
||||
# Extract service names
|
||||
services=$(grep -E "^ [a-zA-Z0-9_-]+:" "$compose_file" 2>/dev/null | sed 's/://g' | sed 's/^ //' | head -5)
|
||||
if [ -n "$services" ]; then
|
||||
echo " Services: $(echo $services | tr '\n' ' ')"
|
||||
fi
|
||||
done
|
||||
register: config_analysis
|
||||
changed_when: false
|
||||
|
||||
- name: Detect web interfaces and APIs
|
||||
shell: |
|
||||
echo "=== WEB INTERFACE DETECTION ==="
|
||||
|
||||
# Common web interface ports
|
||||
web_ports="80 443 8080 8443 3000 5000 8000 9000 9090 3001 8081 8082 8083 8084 8085"
|
||||
|
||||
for port in $web_ports; do
|
||||
# Check if port is listening
|
||||
if netstat -tuln 2>/dev/null | grep -q ":$port " || ss -tuln 2>/dev/null | grep -q ":$port "; then
|
||||
echo "Port $port is active"
|
||||
|
||||
# Try to detect service type
|
||||
if curl -s -m 3 -I "http://localhost:$port" 2>/dev/null | head -1 | grep -q "200\|301\|302"; then
|
||||
server_header=$(curl -s -m 3 -I "http://localhost:$port" 2>/dev/null | grep -i "server:" | head -1)
|
||||
title=$(curl -s -m 3 "http://localhost:$port" 2>/dev/null | grep -i "<title>" | head -1 | sed 's/<[^>]*>//g' | xargs)
|
||||
|
||||
echo " HTTP Response: OK"
|
||||
if [ -n "$server_header" ]; then
|
||||
echo " $server_header"
|
||||
fi
|
||||
if [ -n "$title" ]; then
|
||||
echo " Title: $title"
|
||||
fi
|
||||
|
||||
# Check for common API endpoints
|
||||
for endpoint in /api /health /status /metrics /version; do
|
||||
if curl -s -m 2 "http://localhost:$port$endpoint" >/dev/null 2>&1; then
|
||||
echo " API endpoint: http://localhost:$port$endpoint"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
done
|
||||
register: web_interfaces
|
||||
changed_when: false
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Generate service catalog
|
||||
set_fact:
|
||||
service_catalog:
|
||||
timestamp: "{{ inventory_timestamp }}"
|
||||
hostname: "{{ inventory_hostname }}"
|
||||
system_info:
|
||||
os: "{{ ansible_distribution }} {{ ansible_distribution_version }}"
|
||||
kernel: "{{ ansible_kernel }}"
|
||||
architecture: "{{ ansible_architecture }}"
|
||||
services:
|
||||
system: "{{ system_services.stdout }}"
|
||||
docker: "{{ docker_services.stdout if not skip_docker else 'Docker not available' }}"
|
||||
configurations: "{{ config_analysis.stdout }}"
|
||||
web_interfaces: "{{ web_interfaces.stdout }}"
|
||||
|
||||
- name: Display service inventory
|
||||
debug:
|
||||
msg: |
|
||||
|
||||
==========================================
|
||||
📋 SERVICE INVENTORY - {{ inventory_hostname }}
|
||||
==========================================
|
||||
|
||||
🖥️ SYSTEM INFO:
|
||||
- OS: {{ service_catalog.system_info.os }}
|
||||
- Kernel: {{ service_catalog.system_info.kernel }}
|
||||
- Architecture: {{ service_catalog.system_info.architecture }}
|
||||
|
||||
🔧 SYSTEM SERVICES:
|
||||
{{ service_catalog.services.system }}
|
||||
|
||||
🐳 DOCKER SERVICES:
|
||||
{{ service_catalog.services.docker }}
|
||||
|
||||
⚙️ CONFIGURATIONS:
|
||||
{{ service_catalog.services.configurations }}
|
||||
|
||||
🌐 WEB INTERFACES:
|
||||
{{ service_catalog.services.web_interfaces }}
|
||||
|
||||
==========================================
|
||||
|
||||
- name: Generate JSON service inventory
|
||||
copy:
|
||||
content: |
|
||||
{
|
||||
"timestamp": "{{ service_catalog.timestamp }}",
|
||||
"hostname": "{{ service_catalog.hostname }}",
|
||||
"system_info": {
|
||||
"os": "{{ service_catalog.system_info.os }}",
|
||||
"kernel": "{{ service_catalog.system_info.kernel }}",
|
||||
"architecture": "{{ service_catalog.system_info.architecture }}"
|
||||
},
|
||||
"services": {
|
||||
"system": {{ service_catalog.services.system | to_json }},
|
||||
"docker": {{ service_catalog.services.docker | to_json }},
|
||||
"configurations": {{ service_catalog.services.configurations | to_json }},
|
||||
"web_interfaces": {{ service_catalog.services.web_interfaces | to_json }}
|
||||
}
|
||||
}
|
||||
dest: "{{ inventory_dir }}/{{ inventory_hostname }}_inventory_{{ ansible_date_time.epoch }}.json"
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Generate Markdown documentation
|
||||
copy:
|
||||
content: |
|
||||
# Service Documentation - {{ inventory_hostname }}
|
||||
|
||||
**Generated:** {{ inventory_timestamp }}
|
||||
**System:** {{ service_catalog.system_info.os }} ({{ service_catalog.system_info.architecture }})
|
||||
|
||||
## 🔧 System Services
|
||||
|
||||
```
|
||||
{{ service_catalog.services.system }}
|
||||
```
|
||||
|
||||
## 🐳 Docker Services
|
||||
|
||||
```
|
||||
{{ service_catalog.services.docker }}
|
||||
```
|
||||
|
||||
## ⚙️ Configuration Files
|
||||
|
||||
```
|
||||
{{ service_catalog.services.configurations }}
|
||||
```
|
||||
|
||||
## 🌐 Web Interfaces & APIs
|
||||
|
||||
```
|
||||
{{ service_catalog.services.web_interfaces }}
|
||||
```
|
||||
|
||||
## 📊 Quick Stats
|
||||
|
||||
- **Hostname:** {{ inventory_hostname }}
|
||||
- **OS:** {{ service_catalog.system_info.os }}
|
||||
- **Kernel:** {{ service_catalog.system_info.kernel }}
|
||||
- **Architecture:** {{ service_catalog.system_info.architecture }}
|
||||
- **Docker Available:** {{ 'Yes' if not skip_docker else 'No' }}
|
||||
|
||||
---
|
||||
|
||||
*Auto-generated by Ansible service_inventory.yml playbook*
|
||||
dest: "{{ documentation_dir }}/{{ inventory_hostname }}_services.md"
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Generate consolidated inventory (run once)
|
||||
shell: |
|
||||
cd "{{ inventory_dir }}"
|
||||
|
||||
echo "# Homelab Service Inventory" > consolidated_inventory.md
|
||||
echo "" >> consolidated_inventory.md
|
||||
echo "**Generated:** {{ inventory_timestamp }}" >> consolidated_inventory.md
|
||||
echo "" >> consolidated_inventory.md
|
||||
|
||||
# Process all JSON files
|
||||
for json_file in *_inventory_*.json; do
|
||||
if [ -f "$json_file" ]; then
|
||||
hostname=$(basename "$json_file" | cut -d'_' -f1)
|
||||
echo "## 🖥️ $hostname" >> consolidated_inventory.md
|
||||
echo "" >> consolidated_inventory.md
|
||||
|
||||
# Extract key information using basic tools
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
os=$(jq -r '.system_info.os' "$json_file" 2>/dev/null || echo "Unknown")
|
||||
echo "- **OS:** $os" >> consolidated_inventory.md
|
||||
echo "- **File:** [$json_file](./$json_file)" >> consolidated_inventory.md
|
||||
echo "- **Documentation:** [${hostname}_services.md](../service_docs/${hostname}_services.md)" >> consolidated_inventory.md
|
||||
else
|
||||
echo "- **File:** [$json_file](./$json_file)" >> consolidated_inventory.md
|
||||
fi
|
||||
echo "" >> consolidated_inventory.md
|
||||
fi
|
||||
done
|
||||
|
||||
echo "---" >> consolidated_inventory.md
|
||||
echo "*Auto-generated by Ansible service_inventory.yml playbook*" >> consolidated_inventory.md
|
||||
delegate_to: localhost
|
||||
run_once: true
|
||||
|
||||
- name: Summary message
|
||||
debug:
|
||||
msg: |
|
||||
|
||||
📋 Service inventory complete for {{ inventory_hostname }}
|
||||
📄 JSON Report: {{ inventory_dir }}/{{ inventory_hostname }}_inventory_{{ ansible_date_time.epoch }}.json
|
||||
📖 Markdown Doc: {{ documentation_dir }}/{{ inventory_hostname }}_services.md
|
||||
📚 Consolidated: {{ inventory_dir }}/consolidated_inventory.md
|
||||
|
||||
💡 Use this playbook regularly to maintain up-to-date service documentation
|
||||
💡 JSON files can be consumed by monitoring systems or dashboards
|
||||
Reference in New Issue
Block a user