332 lines
12 KiB
YAML
332 lines
12 KiB
YAML
---
|
|
- 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
|