diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..95d4369 --- /dev/null +++ b/.env.example @@ -0,0 +1,76 @@ +# SysAdmin Portfolio - Environment Variables Template +# Copy this file to .env and fill in your values +# NEVER commit the .env file to version control! + +# ============================================ +# Network Monitoring Settings +# ============================================ +# SNMP community string for device queries +SNMP_COMMUNITY=public + +# SNMP version (1, 2c, or 3) +SNMP_VERSION=2c + +# Default timeout for network operations (seconds) +DEFAULT_TIMEOUT=5.0 + +# Network devices for monitoring +MIKROTIK_HOST=192.168.1.1 +UBIQUITI_HOST=192.168.1.2 +OMADA_HOST=192.168.1.3 + +# ============================================ +# Monitoring Stack Settings +# ============================================ +# Grafana admin password (change this!) +GRAFANA_ADMIN_PASSWORD=changeme + +# Prometheus data retention period +PROMETHEUS_RETENTION=15d + +# Alertmanager webhook URL (optional) +ALERTMANAGER_WEBHOOK_URL= + +# SMTP settings for email alerts (optional) +SMTP_HOST=smtp.example.com +SMTP_PORT=587 +SMTP_USER= +SMTP_PASSWORD= +ALERT_EMAIL_TO=admin@example.com + +# ============================================ +# Microsoft 365 Settings (for PowerShell scripts) +# ============================================ +# Azure AD App Registration details +M365_TENANT_ID=your-tenant-id +M365_CLIENT_ID=your-client-id +M365_CLIENT_SECRET=your-client-secret + +# ============================================ +# Backup Settings +# ============================================ +# Backup destination path +BACKUP_DEST=/var/backups + +# Retention period in days +BACKUP_RETENTION_DAYS=30 + +# Database connection strings (for DB backups) +MYSQL_HOST=localhost +MYSQL_PORT=3306 +MYSQL_USER=backup_user +MYSQL_PASSWORD= + +POSTGRES_HOST=localhost +POSTGRES_PORT=5432 +POSTGRES_USER=backup_user +POSTGRES_PASSWORD= + +# ============================================ +# Logging Settings +# ============================================ +# Log level: DEBUG, INFO, WARNING, ERROR, CRITICAL +LOG_LEVEL=INFO + +# Log file path (optional, defaults to stdout) +LOG_FILE= diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a48aefc --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,115 @@ +name: CI Pipeline + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + lint: + name: Lint & Format Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install ruff black + + - name: Run Ruff linter + run: ruff check . + + - name: Check formatting with Black + run: black --check . + + type-check: + name: Type Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements-dev.txt + + - name: Run MyPy + run: mypy . --ignore-missing-imports + + test: + name: Test + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.9", "3.10", "3.11", "3.12"] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements-dev.txt + + - name: Run tests with coverage + run: | + pytest tests/ -v --cov --cov-report=xml --cov-report=term-missing + + - name: Upload coverage to Codecov + if: matrix.python-version == '3.11' + uses: codecov/codecov-action@v4 + with: + file: ./coverage.xml + fail_ci_if_error: false + + docker-validate: + name: Validate Docker Compose + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Validate docker-compose.yml + run: | + if [ -f "2-infra-monitoring/docker-compose.yml" ]; then + docker compose -f 2-infra-monitoring/docker-compose.yml config + else + echo "docker-compose.yml not found yet, skipping validation" + fi + + powershell-lint: + name: PowerShell Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install PSScriptAnalyzer + shell: pwsh + run: | + Install-Module -Name PSScriptAnalyzer -Force -Scope CurrentUser + + - name: Run PSScriptAnalyzer + shell: pwsh + run: | + $scripts = Get-ChildItem -Path "4-m365-admin-scripts" -Filter "*.ps1" -Recurse -ErrorAction SilentlyContinue + if ($scripts) { + Invoke-ScriptAnalyzer -Path "4-m365-admin-scripts" -Recurse -Settings PSGallery + } else { + Write-Host "No PowerShell scripts found yet, skipping lint" + } diff --git a/1-sysadmin-toolkit/__init__.py b/1-sysadmin-toolkit/__init__.py new file mode 100644 index 0000000..4ff5161 --- /dev/null +++ b/1-sysadmin-toolkit/__init__.py @@ -0,0 +1,18 @@ +""" +SysAdmin Toolkit - Rendszergazda eszközök. + +Ez a modul tartalmazza a rendszergazdai feladatokhoz szükséges eszközöket: +- System info riport generálás +- Disk usage monitoring és alertek +- User audit +- Service monitor +- Log analyzer + +Használat: + >>> from sysadmin_toolkit import get_system_info + >>> info = get_system_info() + >>> print(f"CPU: {info.cpu_percent}%, RAM: {info.memory_percent}%") +""" + +__version__ = "1.0.0" +__author__ = "SysAdmin Portfolio" diff --git a/3-network-health-checker/__init__.py b/3-network-health-checker/__init__.py new file mode 100644 index 0000000..222039e --- /dev/null +++ b/3-network-health-checker/__init__.py @@ -0,0 +1,19 @@ +""" +Network Health Checker - Hálózati diagnosztikai eszközök. + +Ez a modul tartalmazza a hálózati monitorozáshoz szükséges eszközöket: +- Ping monitor (ICMP) +- Port scanner (TCP) +- DNS lookup +- Subnet calculator +- SNMP query +- Network info + +Használat: + >>> from network_health_checker import ping_host + >>> result = ping_host("8.8.8.8") + >>> print(f"Status: {result.status}, Latency: {result.latency_ms}ms") +""" + +__version__ = "1.0.0" +__author__ = "SysAdmin Portfolio" diff --git a/3-network-health-checker/network_tools/__init__.py b/3-network-health-checker/network_tools/__init__.py new file mode 100644 index 0000000..274a147 --- /dev/null +++ b/3-network-health-checker/network_tools/__init__.py @@ -0,0 +1,8 @@ +""" +Network Tools - Hálózati eszközök gyűjteménye. + +Tartalmazza az összes hálózati diagnosztikai és monitorozási eszközt. +""" + +# A modulok importálása a package-ből történő könnyebb eléréshez +# Ezek később kerülnek hozzáadásra a megfelelő modulok implementálásakor diff --git a/5-backup-automation/__init__.py b/5-backup-automation/__init__.py new file mode 100644 index 0000000..03d3624 --- /dev/null +++ b/5-backup-automation/__init__.py @@ -0,0 +1,19 @@ +""" +Backup Automation - Automatizált mentési rendszer. + +Ez a modul tartalmazza a backup műveletekhez szükséges eszközöket: +- File/folder backup +- MySQL backup +- PostgreSQL backup +- Retention manager +- Restore test + +Használat: + >>> from backup_automation import FileBackup + >>> backup = FileBackup(source="/data", dest="/backups") + >>> result = backup.run() + >>> print(f"Backup: {result.success}, Size: {result.backup_size_bytes}") +""" + +__version__ = "1.0.0" +__author__ = "SysAdmin Portfolio" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..4197776 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,134 @@ +[build-system] +requires = ["setuptools>=61.0", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "sysadmin-portfolio" +version = "1.0.0" +description = "Comprehensive System Administrator Portfolio - Network monitoring, automation scripts, M365 management, and infrastructure tools" +readme = "README.md" +license = {text = "MIT"} +requires-python = ">=3.9" +authors = [ + {name = "SysAdmin Portfolio", email = "admin@example.com"} +] +classifiers = [ + "Development Status :: 4 - Beta", + "Environment :: Console", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: System :: Networking :: Monitoring", + "Topic :: System :: Systems Administration", +] +keywords = ["sysadmin", "network", "monitoring", "snmp", "automation"] + +dependencies = [ + "ping3>=4.0.4", + "pysnmp>=7.1.0", + "typer[all]>=0.9.0", + "rich>=13.0.0", + "dnspython>=2.4.0", + "pydantic>=2.0.0", + "pydantic-settings>=2.0.0", + "python-dotenv>=1.0.0", + "pyyaml>=6.0.0", + "psutil>=5.9.0", + "paramiko>=3.0.0", + "httpx>=0.25.0", +] + +[project.optional-dependencies] +dev = [ + "pytest>=7.0.0", + "pytest-asyncio>=0.21.0", + "pytest-cov>=4.0.0", + "pytest-mock>=3.10.0", + "mypy>=1.0.0", + "ruff>=0.1.0", + "black>=23.0.0", +] + +[project.scripts] +nettools = "network_health_checker.cli:app" + +[project.urls] +Homepage = "https://github.com/w7-mgfcode/sysadmin-portfolio" +Documentation = "https://github.com/w7-mgfcode/sysadmin-portfolio#readme" +Repository = "https://github.com/w7-mgfcode/sysadmin-portfolio.git" +Issues = "https://github.com/w7-mgfcode/sysadmin-portfolio/issues" + +[tool.setuptools.packages.find] +where = ["."] +include = [ + "network_health_checker*", + "sysadmin_toolkit*", + "backup_automation*", +] + +[tool.ruff] +target-version = "py39" +line-length = 100 +select = [ + "E", # pycodestyle errors + "W", # pycodestyle warnings + "F", # Pyflakes + "I", # isort + "B", # flake8-bugbear + "C4", # flake8-comprehensions + "UP", # pyupgrade + "ARG", # flake8-unused-arguments + "SIM", # flake8-simplify +] +ignore = [ + "E501", # line too long (handled by formatter) + "B008", # do not perform function calls in argument defaults + "B905", # zip without strict parameter + "C901", # too complex +] + +[tool.ruff.per-file-ignores] +"__init__.py" = ["F401"] +"tests/*" = ["ARG001"] + +[tool.ruff.isort] +known-first-party = ["network_health_checker", "sysadmin_toolkit", "backup_automation"] + +[tool.mypy] +python_version = "3.9" +warn_return_any = true +warn_unused_configs = true +disallow_untyped_defs = true +disallow_incomplete_defs = true +check_untyped_defs = true +ignore_missing_imports = true + +[tool.pytest.ini_options] +minversion = "7.0" +addopts = "-ra -q --strict-markers" +testpaths = ["tests"] +pythonpath = ["."] +asyncio_mode = "auto" +markers = [ + "slow: marks tests as slow (deselect with '-m \"not slow\"')", + "integration: marks tests as integration tests", +] + +[tool.coverage.run] +source = ["network_health_checker", "sysadmin_toolkit", "backup_automation"] +branch = true +omit = ["*/tests/*", "*/__init__.py"] + +[tool.coverage.report] +exclude_lines = [ + "pragma: no cover", + "def __repr__", + "raise NotImplementedError", + "if __name__ == .__main__.:", + "if TYPE_CHECKING:", +] diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..9377b58 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,20 @@ +# SysAdmin Portfolio - Development Dependencies +# Install with: pip install -r requirements-dev.txt + +# Include production dependencies +-r requirements.txt + +# Testing +pytest>=7.0.0 # Test framework +pytest-asyncio>=0.21.0 # Async test support +pytest-cov>=4.0.0 # Coverage reporting +pytest-mock>=3.10.0 # Mocking utilities + +# Code quality +mypy>=1.0.0 # Static type checking +ruff>=0.1.0 # Fast linter +black>=23.0.0 # Code formatter + +# Type stubs for better type checking +types-PyYAML>=6.0.0 # YAML type stubs +types-psutil>=5.9.0 # psutil type stubs diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c1b96d2 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,28 @@ +# SysAdmin Portfolio - Production Dependencies +# Python 3.9+ required + +# Network monitoring tools +ping3>=4.0.4 # ICMP ping implementation +pysnmp>=7.1.0 # SNMP queries for network devices +dnspython>=2.4.0 # DNS lookups and queries + +# CLI framework +typer[all]>=0.9.0 # CLI framework with type hints +rich>=13.0.0 # Beautiful terminal output + +# Data validation +pydantic>=2.0.0 # Data models and validation +pydantic-settings>=2.0.0 # Settings management + +# Configuration +python-dotenv>=1.0.0 # Environment variable management +pyyaml>=6.0.0 # YAML configuration files + +# System utilities +psutil>=5.9.0 # System and process information + +# Remote access +paramiko>=3.0.0 # SSH connections + +# HTTP client +httpx>=0.25.0 # Async HTTP client diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..d4839a6 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +# Tests package diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..425e3c4 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,176 @@ +""" +Pytest konfiguráció és közös fixture-ök. + +Ez a fájl tartalmazza a tesztekhez használt közös beállításokat, +fixture-öket és mock konfigurációkat. +""" + +import os +import sys +from pathlib import Path +from typing import Generator +from unittest.mock import MagicMock, patch + +import pytest + +# Projekt gyökérkönyvtár hozzáadása a Python path-hoz +PROJECT_ROOT = Path(__file__).parent.parent +sys.path.insert(0, str(PROJECT_ROOT)) + + +# ============================================ +# Környezeti változók fixture-ök +# ============================================ + + +@pytest.fixture(autouse=True) +def setup_test_environment() -> Generator[None, None, None]: + """ + Teszt környezet beállítása minden teszthez. + + Beállítja a szükséges környezeti változókat és + a teszt végén visszaállítja az eredeti állapotot. + """ + # Eredeti környezet mentése + original_env = os.environ.copy() + + # Teszt környezeti változók beállítása + os.environ.update( + { + "SNMP_COMMUNITY": "public", + "SNMP_VERSION": "2c", + "DEFAULT_TIMEOUT": "5.0", + "LOG_LEVEL": "DEBUG", + } + ) + + yield + + # Eredeti környezet visszaállítása + os.environ.clear() + os.environ.update(original_env) + + +# ============================================ +# Hálózati mock fixture-ök +# ============================================ + + +@pytest.fixture +def mock_ping() -> Generator[MagicMock, None, None]: + """ + Mock a ping3.ping függvényhez. + + Szimulálja a sikeres ping választ hálózati hívás nélkül. + """ + with patch("ping3.ping") as mock: + # Alapértelmezett: sikeres ping 10ms latency-vel + mock.return_value = 10.0 + yield mock + + +@pytest.fixture +def mock_socket() -> Generator[MagicMock, None, None]: + """ + Mock a socket műveletekhez. + + Szimulálja a socket kapcsolatokat hálózati hívás nélkül. + """ + with patch("socket.socket") as mock: + mock_instance = MagicMock() + mock.return_value.__enter__ = MagicMock(return_value=mock_instance) + mock.return_value.__exit__ = MagicMock(return_value=False) + yield mock_instance + + +@pytest.fixture +def mock_dns_resolver() -> Generator[MagicMock, None, None]: + """ + Mock a DNS resolver-hez. + + Szimulálja a DNS lekérdezéseket hálózati hívás nélkül. + """ + with patch("dns.resolver.resolve") as mock: + # Alapértelmezett A rekord válasz + mock_answer = MagicMock() + mock_answer.to_text.return_value = "93.184.216.34" + mock.return_value = [mock_answer] + yield mock + + +# ============================================ +# SNMP mock fixture-ök +# ============================================ + + +@pytest.fixture +def mock_snmp_engine() -> Generator[MagicMock, None, None]: + """ + Mock az SNMP engine-hez. + + Szimulálja az SNMP lekérdezéseket hálózati hívás nélkül. + """ + with patch("pysnmp.hlapi.v3arch.asyncio.SnmpEngine") as mock: + mock_instance = MagicMock() + mock.return_value = mock_instance + yield mock_instance + + +# ============================================ +# Fájlrendszer fixture-ök +# ============================================ + + +@pytest.fixture +def temp_directory(tmp_path: Path) -> Path: + """ + Ideiglenes könyvtár létrehozása tesztekhez. + + Args: + tmp_path: Pytest által biztosított ideiglenes útvonal + + Returns: + Path objektum az ideiglenes könyvtárhoz + """ + test_dir = tmp_path / "test_data" + test_dir.mkdir(parents=True, exist_ok=True) + return test_dir + + +@pytest.fixture +def sample_log_file(temp_directory: Path) -> Path: + """ + Minta log fájl létrehozása tesztekhez. + + Args: + temp_directory: Ideiglenes könyvtár + + Returns: + Path a létrehozott log fájlhoz + """ + log_file = temp_directory / "sample.log" + log_content = """2024-01-15 10:00:00 INFO Application started +2024-01-15 10:00:01 DEBUG Loading configuration +2024-01-15 10:00:02 WARNING Disk usage above 80% +2024-01-15 10:00:03 ERROR Connection failed to database +2024-01-15 10:00:04 INFO Retrying connection +2024-01-15 10:00:05 INFO Connection established +""" + log_file.write_text(log_content) + return log_file + + +# ============================================ +# Marker konfigurációk +# ============================================ + + +def pytest_configure(config: pytest.Config) -> None: + """ + Pytest konfiguráció egyedi markerekkel. + + Regisztrálja a projektben használt egyedi markereket. + """ + config.addinivalue_line("markers", "slow: marks tests as slow running") + config.addinivalue_line("markers", "integration: marks tests as integration tests") + config.addinivalue_line("markers", "network: marks tests that require network access")