Initial commit — Server_Monitorizare_v2
This commit is contained in:
324
app/services/device_service.py
Normal file
324
app/services/device_service.py
Normal file
@@ -0,0 +1,324 @@
|
||||
"""
|
||||
Device management service with CRUD operations and device monitoring
|
||||
"""
|
||||
import logging
|
||||
from typing import List, Optional, Dict, Any
|
||||
from datetime import datetime, timedelta
|
||||
from sqlalchemy.orm import Session, joinedload
|
||||
from sqlalchemy import desc, func, and_
|
||||
from app.models import Device, LogEntry, FileUpload, InventoryGroup
|
||||
from config.database_config import get_db
|
||||
|
||||
class DeviceService:
|
||||
"""Service for managing devices and device-related operations"""
|
||||
|
||||
def __init__(self):
|
||||
self.db = get_db()
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
# Basic CRUD Operations
|
||||
|
||||
def create_device(self, hostname: str, device_ip: str, nume_masa: str, **kwargs) -> Device:
|
||||
"""Create a new device"""
|
||||
try:
|
||||
with self.db.get_session() as session:
|
||||
# Check if device already exists
|
||||
existing = session.query(Device).filter(
|
||||
(Device.hostname == hostname) | (Device.device_ip == device_ip)
|
||||
).first()
|
||||
|
||||
if existing:
|
||||
raise ValueError(f"Device with hostname '{hostname}' or IP '{device_ip}' already exists")
|
||||
|
||||
device = Device(
|
||||
hostname=hostname,
|
||||
device_ip=device_ip,
|
||||
nume_masa=nume_masa,
|
||||
device_type=kwargs.get('device_type', 'unknown'),
|
||||
os_version=kwargs.get('os_version'),
|
||||
status=kwargs.get('status', 'active'),
|
||||
location=kwargs.get('location'),
|
||||
description=kwargs.get('description'),
|
||||
last_seen=datetime.utcnow()
|
||||
)
|
||||
|
||||
session.add(device)
|
||||
session.commit()
|
||||
session.refresh(device)
|
||||
|
||||
self.logger.info(f"Created device: {hostname} ({device_ip})")
|
||||
return device
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error creating device: {e}")
|
||||
raise
|
||||
|
||||
def get_device_by_id(self, device_id: int) -> Optional[Device]:
|
||||
"""Get device by ID with relationships loaded"""
|
||||
try:
|
||||
with self.db.get_session() as session:
|
||||
return session.query(Device).options(
|
||||
joinedload(Device.logs),
|
||||
joinedload(Device.files),
|
||||
joinedload(Device.inventory_groups)
|
||||
).filter(Device.id == device_id).first()
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error getting device {device_id}: {e}")
|
||||
return None
|
||||
|
||||
def get_device_by_hostname(self, hostname: str) -> Optional[Device]:
|
||||
"""Get device by hostname"""
|
||||
try:
|
||||
with self.db.get_session() as session:
|
||||
return session.query(Device).filter(Device.hostname == hostname).first()
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error getting device by hostname {hostname}: {e}")
|
||||
return None
|
||||
|
||||
def get_device_by_ip(self, device_ip: str) -> Optional[Device]:
|
||||
"""Get device by IP address"""
|
||||
try:
|
||||
with self.db.get_session() as session:
|
||||
return session.query(Device).filter(Device.device_ip == device_ip).first()
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error getting device by IP {device_ip}: {e}")
|
||||
return None
|
||||
|
||||
def get_all_devices(self, status: Optional[str] = None, limit: Optional[int] = None) -> List[Device]:
|
||||
"""Get all devices with optional filtering"""
|
||||
try:
|
||||
with self.db.get_session() as session:
|
||||
query = session.query(Device).order_by(desc(Device.last_seen))
|
||||
|
||||
if status:
|
||||
query = query.filter(Device.status == status)
|
||||
|
||||
if limit:
|
||||
query = query.limit(limit)
|
||||
|
||||
return query.all()
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error getting devices: {e}")
|
||||
return []
|
||||
|
||||
def update_device(self, device_id: int, **kwargs) -> Optional[Device]:
|
||||
"""Update device information"""
|
||||
try:
|
||||
with self.db.get_session() as session:
|
||||
device = session.query(Device).filter(Device.id == device_id).first()
|
||||
if not device:
|
||||
return None
|
||||
|
||||
# Update allowed fields
|
||||
allowed_fields = [
|
||||
'hostname', 'device_ip', 'nume_masa', 'device_type',
|
||||
'os_version', 'status', 'location', 'description'
|
||||
]
|
||||
|
||||
for field, value in kwargs.items():
|
||||
if field in allowed_fields and hasattr(device, field):
|
||||
setattr(device, field, value)
|
||||
|
||||
session.commit()
|
||||
session.refresh(device)
|
||||
|
||||
self.logger.info(f"Updated device {device_id}")
|
||||
return device
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error updating device {device_id}: {e}")
|
||||
raise
|
||||
|
||||
def delete_device(self, device_id: int) -> bool:
|
||||
"""Delete device (soft delete by setting status to inactive)"""
|
||||
try:
|
||||
with self.db.get_session() as session:
|
||||
device = session.query(Device).filter(Device.id == device_id).first()
|
||||
if not device:
|
||||
return False
|
||||
|
||||
# Soft delete - set status to inactive
|
||||
device.status = 'inactive'
|
||||
session.commit()
|
||||
|
||||
self.logger.info(f"Soft deleted device {device_id}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error deleting device {device_id}: {e}")
|
||||
return False
|
||||
|
||||
# Device Monitoring Functions
|
||||
|
||||
def update_device_last_seen(self, hostname: str = None, device_ip: str = None) -> Optional[Device]:
|
||||
"""Update device last seen timestamp"""
|
||||
try:
|
||||
with self.db.get_session() as session:
|
||||
device = None
|
||||
|
||||
if hostname:
|
||||
device = session.query(Device).filter(Device.hostname == hostname).first()
|
||||
elif device_ip:
|
||||
device = session.query(Device).filter(Device.device_ip == device_ip).first()
|
||||
|
||||
if device:
|
||||
device.last_seen = datetime.utcnow()
|
||||
session.commit()
|
||||
|
||||
return device
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error updating last seen: {e}")
|
||||
return None
|
||||
|
||||
def get_device_statistics(self, device_id: int) -> Dict[str, Any]:
|
||||
"""Get comprehensive statistics for a device"""
|
||||
try:
|
||||
with self.db.get_session() as session:
|
||||
device = session.query(Device).filter(Device.id == device_id).first()
|
||||
if not device:
|
||||
return {}
|
||||
|
||||
# Log statistics
|
||||
total_logs = session.query(LogEntry).filter(LogEntry.device_id == device_id).count()
|
||||
|
||||
# Logs by severity
|
||||
severity_counts = session.query(
|
||||
LogEntry.severity,
|
||||
func.count(LogEntry.id)
|
||||
).filter(
|
||||
LogEntry.device_id == device_id
|
||||
).group_by(LogEntry.severity).all()
|
||||
|
||||
# Recent activity (last 24 hours)
|
||||
last_24h = datetime.utcnow() - timedelta(hours=24)
|
||||
recent_logs = session.query(LogEntry).filter(
|
||||
and_(LogEntry.device_id == device_id, LogEntry.timestamp >= last_24h)
|
||||
).count()
|
||||
|
||||
# File uploads
|
||||
total_files = session.query(FileUpload).filter(
|
||||
FileUpload.device_id == device_id
|
||||
).count()
|
||||
|
||||
# Last log
|
||||
last_log = session.query(LogEntry).filter(
|
||||
LogEntry.device_id == device_id
|
||||
).order_by(desc(LogEntry.timestamp)).first()
|
||||
|
||||
return {
|
||||
'device': device,
|
||||
'total_logs': total_logs,
|
||||
'severity_counts': dict(severity_counts),
|
||||
'recent_logs_24h': recent_logs,
|
||||
'total_files': total_files,
|
||||
'last_log': last_log,
|
||||
'uptime_days': (datetime.utcnow() - device.last_seen).days if device.last_seen else 0
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error getting device statistics: {e}")
|
||||
return {}
|
||||
|
||||
def get_inactive_devices(self, hours: int = 24) -> List[Device]:
|
||||
"""Get devices that haven't been seen recently"""
|
||||
try:
|
||||
with self.db.get_session() as session:
|
||||
cutoff_time = datetime.utcnow() - timedelta(hours=hours)
|
||||
|
||||
return session.query(Device).filter(
|
||||
and_(
|
||||
Device.last_seen < cutoff_time,
|
||||
Device.status.in_(['active', 'maintenance'])
|
||||
)
|
||||
).order_by(desc(Device.last_seen)).all()
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error getting inactive devices: {e}")
|
||||
return []
|
||||
|
||||
def get_device_logs(self, device_id: int, limit: int = 100, severity: str = None) -> List[LogEntry]:
|
||||
"""Get logs for a specific device"""
|
||||
try:
|
||||
with self.db.get_session() as session:
|
||||
query = session.query(LogEntry).filter(
|
||||
LogEntry.device_id == device_id
|
||||
).order_by(desc(LogEntry.timestamp))
|
||||
|
||||
if severity:
|
||||
query = query.filter(LogEntry.severity == severity)
|
||||
|
||||
return query.limit(limit).all()
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error getting device logs: {e}")
|
||||
return []
|
||||
|
||||
def search_devices(self, search_term: str) -> List[Device]:
|
||||
"""Search devices by hostname, IP, or description"""
|
||||
try:
|
||||
with self.db.get_session() as session:
|
||||
search_pattern = f"%{search_term}%"
|
||||
|
||||
return session.query(Device).filter(
|
||||
(Device.hostname.like(search_pattern)) |
|
||||
(Device.device_ip.like(search_pattern)) |
|
||||
(Device.nume_masa.like(search_pattern)) |
|
||||
(Device.location.like(search_pattern)) |
|
||||
(Device.description.like(search_pattern))
|
||||
).order_by(desc(Device.last_seen)).all()
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error searching devices: {e}")
|
||||
return []
|
||||
|
||||
# Bulk Operations
|
||||
|
||||
def bulk_update_status(self, device_ids: List[int], status: str) -> int:
|
||||
"""Update status for multiple devices"""
|
||||
try:
|
||||
with self.db.get_session() as session:
|
||||
updated = session.query(Device).filter(
|
||||
Device.id.in_(device_ids)
|
||||
).update({Device.status: status}, synchronize_session=False)
|
||||
|
||||
session.commit()
|
||||
self.logger.info(f"Updated status for {updated} devices")
|
||||
return updated
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error bulk updating status: {e}")
|
||||
return 0
|
||||
|
||||
def get_device_summary(self) -> Dict[str, Any]:
|
||||
"""Get summary statistics for all devices"""
|
||||
try:
|
||||
with self.db.get_session() as session:
|
||||
# Device status counts
|
||||
status_counts = session.query(
|
||||
Device.status,
|
||||
func.count(Device.id)
|
||||
).group_by(Device.status).all()
|
||||
|
||||
# Device type counts
|
||||
type_counts = session.query(
|
||||
Device.device_type,
|
||||
func.count(Device.id)
|
||||
).group_by(Device.device_type).all()
|
||||
|
||||
# Recent activity
|
||||
last_24h = datetime.utcnow() - timedelta(hours=24)
|
||||
devices_seen_24h = session.query(Device).filter(
|
||||
Device.last_seen >= last_24h
|
||||
).count()
|
||||
|
||||
return {
|
||||
'total_devices': session.query(Device).count(),
|
||||
'status_counts': dict(status_counts),
|
||||
'type_counts': dict(type_counts),
|
||||
'devices_seen_24h': devices_seen_24h
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error getting device summary: {e}")
|
||||
return {}
|
||||
Reference in New Issue
Block a user