commti after qwen start

This commit is contained in:
mariano
2026-05-22 13:55:01 +02:00
parent ba2293102d
commit ad42773519
15 changed files with 2503 additions and 0 deletions
@@ -0,0 +1,199 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
GLPI Agent Task: netconfig_backup
Recupera configurazione da apparati di rete e invia a GLPI plugin netconfig
Requisiti: netmiko, requests, pyyaml
Install: pip3 install netmiko requests pyyaml
"""
import os
import sys
import json
import hashlib
import logging
import requests
from datetime import datetime
from typing import Optional, Dict, List
from netmiko import ConnectHandler, NetmikoTimeoutException, NetmikoAuthenticationException
import yaml
# Configurazione logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('/var/log/glpi_agent_netconfig.log'),
logging.StreamHandler(sys.stdout)
]
)
logger = logging.getLogger('netconfig_backup')
# Configurazione da file YAML esterno (sicuro, non hardcodato)
CONFIG_FILE = os.getenv('NETCONFIG_CONFIG', '/etc/glpi-agent/netconfig_devices.yaml')
GLPI_URL = os.getenv('GLPI_URL', 'http://localhost/glpi')
GLPI_TOKEN = os.getenv('GLPI_APP_TOKEN', '')
AGENT_TOKEN = os.getenv('NETCONFIG_AGENT_TOKEN', 'change_me_in_production')
TIMEOUT = int(os.getenv('NETCONFIG_TIMEOUT', '30'))
RETRIES = int(os.getenv('NETCONFIG_RETRIES', '2'))
def load_devices_config(path: str) -> List[Dict]:
"""Carica configurazione dispositivi da YAML"""
if not os.path.exists(path):
logger.error(f"Config file not found: {path}")
return []
try:
with open(path, 'r') as f:
data = yaml.safe_load(f)
return data.get('devices', [])
except Exception as e:
logger.error(f"Error loading config: {e}")
return []
def get_device_connection_params(device: Dict) -> Dict:
"""Prepara parametri di connessione per netmiko"""
device_type_map = {
'cisco_ios': 'cisco_ios',
'cisco_nxos': 'cisco_nxos',
'hp_comware': 'hp_comware',
'juniper_junos': 'juniper_junos',
'arista_eos': 'arista_eos',
'paloalto_panos': 'paloalto_panos',
}
return {
'device_type': device_type_map.get(device['platform'], 'cisco_ios'),
'host': device['ip'],
'username': device.get('username', os.getenv('NETCONFIG_DEFAULT_USER')),
'password': device.get('password', os.getenv('NETCONFIG_DEFAULT_PASS')),
'secret': device.get('enable_password', os.getenv('NETCONFIG_ENABLE_PASS')),
'port': device.get('port', 22),
'timeout': TIMEOUT,
'session_log': None,
'global_delay_factor': device.get('delay_factor', 1),
}
def fetch_config(device: Dict) -> Optional[str]:
"""Recupera configurazione via SSH con netmiko"""
params = get_device_connection_params(device)
for attempt in range(RETRIES + 1):
try:
logger.info(f"Connecting to {device['name']} ({params['host']}) [attempt {attempt+1}]")
connection = ConnectHandler(**params)
# Abilita modalità enable se necessaria
if params.get('secret'):
connection.enable()
# Comando di show config (personalizzabile per piattaforma)
command = device.get('command', 'show running-config')
config = connection.send_command(command, expect_string=r'#|\$', max_loops=150)
connection.disconnect()
# Pulizia output da caratteri di controllo
config = config.strip()
config = '\n'.join(line.rstrip() for line in config.splitlines())
logger.info(f"Config fetched successfully for {device['name']}")
return config
except NetmikoAuthenticationException as e:
logger.error(f"Auth failed for {device['name']}: {e}")
break # Non ritentare se auth fallisce
except NetmikoTimeoutException as e:
logger.warning(f"Timeout for {device['name']}: {e}")
except Exception as e:
logger.error(f"Unexpected error for {device['name']}: {e}")
return None
def send_to_glpi(device_id: int, config: str) -> bool:
"""Invia configurazione a GLPI plugin endpoint"""
url = f"{GLPI_URL}/plugins/netconfig/ajax/agent_receive.php"
payload = {
'device_id': device_id,
'config': config,
'token': AGENT_TOKEN,
'timestamp': datetime.utcnow().isoformat(),
'agent_version': '1.0.0'
}
headers = {
'Content-Type': 'application/json',
'App-Token': GLPI_TOKEN, # Opzionale: autenticazione API GLPI
}
try:
response = requests.post(
url,
json=payload,
headers=headers,
timeout=30,
verify=os.getenv('SSL_VERIFY', 'true').lower() == 'true'
)
if response.status_code == 200:
result = response.json()
logger.info(f"GLPI response: {result.get('message', 'OK')}")
return result.get('status') == 'ok'
else:
logger.error(f"GLPI HTTP {response.status_code}: {response.text}")
return False
except requests.RequestException as e:
logger.error(f"Request to GLPI failed: {e}")
return False
def calculate_hash(config: str) -> str:
"""Calcola SHA256 della configurazione"""
return hashlib.sha256(config.encode('utf-8')).hexdigest()
def run_task():
"""Entry point della task"""
logger.info("=== NetConfig Backup Task Started ===")
devices = load_devices_config(CONFIG_FILE)
if not devices:
logger.warning("No devices configured, exiting")
return
success_count = 0
for device in devices:
try:
device_name = device.get('name', 'unknown')
device_id = device.get('glpi_id') # ID in glpi_networkdevices
if not device_id:
logger.warning(f"Skipping {device_name}: missing glpi_id")
continue
config = fetch_config(device)
if not config:
logger.warning(f"Failed to fetch config for {device_name}")
continue
# Invia a GLPI solo se diverso dall'ultimo (controllo lato server, ma ottimizzazione client)
if send_to_glpi(device_id, config):
success_count += 1
logger.info(f"{device_name} - Config saved")
else:
logger.error(f"{device_name} - Failed to save to GLPI")
except Exception as e:
logger.exception(f"Unhandled error for device {device.get('name')}")
logger.info(f"=== Task Completed: {success_count}/{len(devices)} devices processed ===")
if __name__ == '__main__':
run_task()
@@ -0,0 +1,25 @@
devices:
- name: "SW-Core-01"
ip: "10.0.0.1"
platform: "cisco_ios"
glpi_id: 123 # ID in glpi_networkdevices
username: "backup_user"
# password: "xxx" # Meglio usare variabili d'ambiente o vault
enable_password: "enable_secret"
command: "show running-config"
delay_factor: 2
- name: "SW-Access-05"
ip: "10.0.0.5"
platform: "hp_comware"
glpi_id: 124
username: "admin"
command: "display current-configuration"
# 🔐 Best Practice: Non inserire password nel YAML. Usa:
# Variabili d'ambiente: NETCONFIG_DEFAULT_PASS
# Vault esterno (HashiCorp Vault, AWS Secrets Manager)
# File con permessi 600 leggibile solo dall'utente dell'agent
@@ -0,0 +1,22 @@
#!/usr/bin/env php
<?php
// /usr/share/glpi_agent/plugins/netconfig_backup.php
require_once '/path/to/glpi/vendor/autoload.php';
use PluginNetconfig\Api\GlpiApiClient;
// Carica config da YAML/JSON
$devices = yaml_parse_file('/etc/glpi-agent/netconfig_devices.yaml')['devices'] ?? [];
$api = new GlpiApiClient(
baseUrl: getenv('GLPI_URL') ?: 'http://localhost/glpi',
appToken: getenv('GLPI_APP_TOKEN'),
userToken: getenv('GLPI_USER_TOKEN') // Più sicuro di username/password
);
foreach ($devices as $device) {
$config = fetchConfigViaNetmikoPhp($device); // Funzione custom con phpseclib3
if ($config) {
$api->sendConfig($device['glpi_id'], $config, getenv('NETCONFIG_AGENT_TOKEN'));
}
}
@@ -0,0 +1,9 @@
# Ricarica configurazione supervisor
sudo supervisorctl reread
sudo supervisorctl update
# Esegui manualmente la task
sudo supervisorctl start glpi-netconfig
# Monitora log in tempo reale
sudo tail -f /var/log/glpi_netconfig_supervisor.log
@@ -0,0 +1,11 @@
# /etc/supervisor/conf.d/glpi-netconfig.conf
[program:glpi-netconfig]
command=/usr/bin/python3 /usr/share/glpi_agent/plugins/netconfig_backup.py
directory=/usr/share/glpi_agent/plugins
user=glpi-agent
autostart=false # Non partire all'avvio, esegui solo on-demand
autorestart=false
startsecs=0
stdout_logfile=/var/log/glpi_netconfig_supervisor.log
stderr_logfile=/var/log/glpi_netconfig_supervisor_err.log
environment=NETCONFIG_CONFIG="/etc/glpi-agent/netconfig_devices.yaml",GLPI_URL="https://glpi.example.com",NETCONFIG_AGENT_TOKEN="your_secure_token"
@@ -0,0 +1,48 @@
# /etc/systemd/system/glpi-netconfig.service
[Unit]
Description=GLPI NetConfig Backup Task
After=network.target
[Service]
Type=oneshot
User=glpi-agent
ExecStart=/usr/bin/python3 /usr/share/glpi_agent/plugins/netconfig_backup.py
Environment="NETCONFIG_CONFIG=/etc/glpi-agent/netconfig_devices.yaml"
Environment="GLPI_URL=https://glpi.example.com"
Environment="NETCONFIG_AGENT_TOKEN=your_secure_token"
StandardOutput=journal
StandardError=journal
- altro ini (bho)
# /etc/systemd/system/glpi-netconfig.timer
[Unit]
Description=Run GLPI NetConfig Backup every 6 hours
Requires=glpi-netconfig.service
[Timer]
OnCalendar=*-*-* 02/6:00:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.target
---
# attivazioen disattivazioen timer
# Attiva e avvia il timer
sudo systemctl daemon-reload
sudo systemctl enable --now glpi-netconfig.timer
# Verifica stato
systemctl list-timers | grep netconfig
journalctl -u glpi-netconfig.service -f
@@ -0,0 +1,3 @@
# /etc/cron.d/glpi-netconfig
# Esegui backup ogni 6 ore alle 02:00, 08:00, 14:00, 20:00
0 2,8,14,20 * * * glpi-agent /usr/bin/python3 /usr/share/glpi_agent/plugins/netconfig_backup.py >> /var/log/glpi_netconfig_cron.log 2>&1