102 lines
2.9 KiB
Python
102 lines
2.9 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Network configuration validator for ICS-SimLab.
|
|
|
|
Checks for common network configuration issues that cause docker-compose failures:
|
|
1. Duplicate IPs within the same docker_network ("Address already in use")
|
|
2. docker_network not declared in ip_networks[]
|
|
3. IP address outside the declared subnet
|
|
|
|
Usage:
|
|
python3 -m tools.check_networking --config <path> [--strict]
|
|
|
|
Exit codes:
|
|
0: No issues found
|
|
1: Issues found (or --strict and warnings exist)
|
|
2: Configuration file error
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import List
|
|
|
|
from models.ics_simlab_config_v2 import Config
|
|
from tools.semantic_validation import validate_network_config, SemanticError
|
|
|
|
|
|
def format_issues(errors: List[SemanticError]) -> str:
|
|
"""Format errors for human-readable output."""
|
|
lines = []
|
|
for err in errors:
|
|
lines.append(f" - {err.entity}: {err.message}")
|
|
return "\n".join(lines)
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(
|
|
description="Validate ICS-SimLab network configuration"
|
|
)
|
|
parser.add_argument(
|
|
"--config",
|
|
required=True,
|
|
help="Path to configuration.json"
|
|
)
|
|
parser.add_argument(
|
|
"--strict",
|
|
action="store_true",
|
|
help="Exit non-zero on any issue (not just errors)"
|
|
)
|
|
parser.add_argument(
|
|
"--json",
|
|
action="store_true",
|
|
help="Output in JSON format"
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
config_path = Path(args.config)
|
|
if not config_path.exists():
|
|
print(f"ERROR: Config file not found: {config_path}", file=sys.stderr)
|
|
return 2
|
|
|
|
# Load and validate config
|
|
try:
|
|
raw_data = json.loads(config_path.read_text(encoding="utf-8"))
|
|
config = Config.model_validate(raw_data)
|
|
except json.JSONDecodeError as e:
|
|
print(f"ERROR: Invalid JSON in {config_path}: {e}", file=sys.stderr)
|
|
return 2
|
|
except Exception as e:
|
|
print(f"ERROR: Config validation failed: {e}", file=sys.stderr)
|
|
return 2
|
|
|
|
# Run network validation
|
|
errors = validate_network_config(config)
|
|
|
|
if args.json:
|
|
output = {
|
|
"config": str(config_path),
|
|
"issues": [{"entity": e.entity, "message": e.message} for e in errors],
|
|
"status": "error" if errors else "ok"
|
|
}
|
|
print(json.dumps(output, indent=2))
|
|
else:
|
|
if errors:
|
|
print(f"NETWORK VALIDATION ISSUES ({len(errors)}):")
|
|
print(format_issues(errors))
|
|
print()
|
|
print("FIX: Each device must have a unique IP within its docker_network.")
|
|
print(" Check for copy-paste errors or IP assignment overlap.")
|
|
else:
|
|
print(f"OK: Network configuration valid ({config_path})")
|
|
|
|
# Return appropriate exit code
|
|
if errors:
|
|
return 1
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|