146 lines
5.8 KiB
Python
146 lines
5.8 KiB
Python
import csv
|
|
import os
|
|
import sys
|
|
import platform
|
|
import socket
|
|
import subprocess
|
|
from concurrent.futures import ThreadPoolExecutor
|
|
from datetime import datetime
|
|
from rich.console import Console
|
|
from rich.table import Table
|
|
from rich.live import Live
|
|
|
|
# Configure the console
|
|
console = Console()
|
|
|
|
def check_ping(hostname):
|
|
"""Ping the hostname detecting the current OS."""
|
|
# -n for Windows, -c for Linux/macOS. 1sec / 1000ms Timeout.
|
|
param = '-n' if platform.system().lower() == 'windows' else '-c'
|
|
timeout_param = '-w' if platform.system().lower() == 'windows' else '-W'
|
|
timeout_value = '1000' if platform.system().lower() == 'windows' else '1'
|
|
|
|
command = ['ping', param, '1', timeout_param, timeout_value, hostname]
|
|
|
|
try:
|
|
# Return True if the exit code is 0
|
|
return subprocess.call(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) == 0
|
|
except Exception:
|
|
return False
|
|
|
|
def check_port(hostname, port):
|
|
"""Try to open the TCP connection using the specified port."""
|
|
try:
|
|
port = int(port)
|
|
except (ValueError, TypeError):
|
|
return False # invalid port
|
|
|
|
try:
|
|
with socket.create_connection((hostname, port), timeout=1.5) as sock:
|
|
return True
|
|
except (socket.timeout, ConnectionRefusedError, OSError):
|
|
return False
|
|
|
|
def check_device(device):
|
|
"""Execute both test for one device."""
|
|
name = device['name']
|
|
hostname = device['hostname']
|
|
port = device['port']
|
|
|
|
ping_ok = check_ping(hostname)
|
|
port_ok = check_port(hostname, port) if port else False
|
|
|
|
return {
|
|
'name': name,
|
|
'hostname': hostname,
|
|
'port': port if port else 'N/A',
|
|
'ping': '[green]ONLINE[/green]' if ping_ok else '[red]OFFLINE[/red]',
|
|
'port_status': '[green]OPEN[/green]' if port_ok else '[red]CLOSED[/red]' if port else 'N/A',
|
|
# Store clean strings for the final CSV export
|
|
'raw_ping': 'ONLINE' if ping_ok else 'OFFLINE',
|
|
'raw_port': 'OPEN' if port_ok else 'CLOSED' if port else 'N/A'
|
|
}
|
|
|
|
def save_to_csv(results):
|
|
"""Export the results to a new CSV file."""
|
|
fieldnames = ['name', 'hostname', 'port', 'ping_status', 'port_status', 'timestamp']
|
|
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
|
name_ts = datetime.now().strftime('%y%m%d%H%M')
|
|
output_filename = "%s_Results.csv" % name_ts
|
|
try:
|
|
with open(output_filename, mode='w', newline='', encoding='utf-8') as f:
|
|
writer = csv.DictWriter(f, fieldnames=fieldnames)
|
|
writer.writeheader()
|
|
for r in results:
|
|
writer.writerow({
|
|
'name': r['name'],
|
|
'hostname': r['hostname'],
|
|
'port': r['port'],
|
|
'ping_status': r['raw_ping'],
|
|
'port_status': r['raw_port'],
|
|
'timestamp': timestamp
|
|
})
|
|
console.print(f"\n[bold green]✓[/bold green] Results exported to file: [cyan]{output_filename}[/cyan]")
|
|
except Exception as e:
|
|
console.print(f"\n[bold red]Error saving CSV file:[/bold red] {e}")
|
|
|
|
def main():
|
|
# Subtle header decoration for the brand identity
|
|
if len(sys.argv) > 1:
|
|
input_file = sys.argv[1]
|
|
else:
|
|
input_file = 'devices.csv'
|
|
|
|
if not os.path.exists(input_file):
|
|
console.print(f"[bold red]Error:[/bold red] Input file could not be found: '{input_file}'")
|
|
return
|
|
|
|
# Read target devices from CSV
|
|
devices = []
|
|
with open(input_file, encoding='utf-8', errors='ignore') as f:
|
|
reader = csv.DictReader(f)
|
|
for row in reader:
|
|
devices.append(row)
|
|
|
|
results = []
|
|
|
|
try:
|
|
while True:
|
|
os.system('cls' if platform.system().lower() == 'windows' else 'clear') # Clear the console for each iteration
|
|
console.clear()
|
|
# Real-time console interface header
|
|
console.print("\nNetwork Connection Tester - [bold blue]Prime Controls[/bold blue] [dim]v1.0.0[/dim]")
|
|
console.print("[dim]Developed by Emmanuel Hernandez Cruz | Automation Specialist II[/dim]\n")
|
|
console.print(f"\n[bold cyan]●[/bold cyan] Testing {len(devices)} network connections...")
|
|
console.print("Press [bold yellow]Ctrl + C[/bold yellow] to [bold red]stop[/bold red] monitoring and export results.\n")
|
|
# Create dynamic table to show the results in real time
|
|
table = Table(title="Realtime Network Status:")
|
|
table.add_column("Name", justify="left", style="cyan")
|
|
table.add_column("Hostname/IP", justify="left")
|
|
table.add_column("Port", justify="center", style="magenta")
|
|
table.add_column("Ping Status", justify="center")
|
|
table.add_column("Port Status", justify="center")
|
|
|
|
results = [] # Reset results for each iteration
|
|
|
|
# Update the table UI dynamically using Rich Live display
|
|
with Live(table, refresh_per_second=4):
|
|
with ThreadPoolExecutor(max_workers=30) as executor:
|
|
futures = [executor.submit(check_device, dev) for dev in devices]
|
|
|
|
for future in futures:
|
|
res = future.result()
|
|
results.append(res)
|
|
# Add row to the table
|
|
table.add_row(res['name'], res['hostname'], str(res['port']), res['ping'], res['port_status'])
|
|
import time
|
|
time.sleep(5) # Wait for 5 seconds before the next iteration
|
|
except KeyboardInterrupt:
|
|
console.print("\n[bold yellow]<!>[/bold yellow] Monitoring stopped by user.")
|
|
# Generate final report
|
|
save_to_csv(results)
|
|
console.print("\n[dim]Press Enter to close this window...[/dim]", end="")
|
|
input()
|
|
|
|
if __name__ == '__main__':
|
|
main() |