-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add GitHub Actions workflows for CI/CD and also did clinting cleanups…
… for the whole codebase
- Loading branch information
1 parent
a4eb10c
commit f4a354f
Showing
18 changed files
with
911 additions
and
756 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
# .github/workflows/publish.yml | ||
name: Publish to PyPI | ||
|
||
on: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,16 @@ | ||
[build-system] | ||
requires = ["hatchling"] | ||
build-backend = "hatchling.build" | ||
requires = ["setuptools>=61.0"] | ||
build-backend = "setuptools.build_meta" | ||
|
||
[project] | ||
name = "knetvis" | ||
version = "0.1.0" | ||
description = "A CLI tool for network visualization" | ||
readme = "README.md" | ||
requires-python = ">=3.7" | ||
authors = [ | ||
{ name = "Samuel Arogbonlo", email = "[email protected]" }, | ||
] | ||
description = "A CLI tool for Kubernetes Network Policy visualization" | ||
readme = "README.md" | ||
requires-python = ">=3.8" | ||
dependencies = [ | ||
"kubernetes>=28.1.0", | ||
"networkx>=3.1", | ||
|
@@ -21,19 +21,7 @@ dependencies = [ | |
] | ||
|
||
[project.scripts] | ||
knetvis = "knetvis.cli:main" | ||
|
||
[tool.hatch.build.targets.wheel] | ||
packages = ["src"] | ||
knetvis = "knetvis.cli:cli" | ||
|
||
[project.optional-dependencies] | ||
dev = [ | ||
"pytest>=7.3.1", | ||
"pytest-cov>=4.1.0", | ||
"black>=22.3.0", | ||
"isort>=5.10.1", | ||
"flake8>=4.0.1", | ||
"pre-commit>=2.20.0", | ||
"tox>=3.24.0", | ||
"mypy>=0.982", | ||
] | ||
[tool.setuptools.packages.find] | ||
where = ["src"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
[flake8] | ||
max-line-length = 88 | ||
extend-ignore = E203 | ||
per-file-ignores = | ||
__init__.py:F401 | ||
exclude = .git,__pycache__,build,dist | ||
|
||
[mypy] | ||
python_version = 3.8 | ||
warn_return_any = True | ||
warn_unused_configs = True | ||
disallow_untyped_defs = True | ||
|
||
[mypy-kubernetes.*] | ||
ignore_missing_imports = True | ||
|
||
[mypy-networkx.*] | ||
ignore_missing_imports = True | ||
|
||
[mypy-yaml.*] | ||
ignore_missing_imports = True | ||
|
||
[tool:pytest] | ||
testpaths = tests | ||
python_files = test_*.py | ||
python_functions = test_* | ||
addopts = --cov=src --cov-report=term-missing | ||
|
||
[coverage:run] | ||
source = src | ||
|
||
[coverage:report] | ||
exclude_lines = | ||
pragma: no cover | ||
def __repr__ | ||
if self.debug: | ||
raise NotImplementedError | ||
if __name__ == .__main__.: | ||
pass | ||
raise ImportError | ||
|
||
[isort] | ||
profile = black | ||
multi_line_output = 3 | ||
include_trailing_comma = True | ||
force_grid_wrap = 0 | ||
use_parentheses = True | ||
line_length = 88 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# src/knetvis/__init__.py | ||
|
||
from .policy import PolicyParser | ||
from .simulator import TrafficSimulator | ||
from .visualizer import NetworkVisualizer | ||
|
||
__version__ = "0.1.0" | ||
|
||
# Export these classes as main package interfaces | ||
__all__ = [ | ||
"PolicyParser", | ||
"TrafficSimulator", | ||
"NetworkVisualizer", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import os | ||
|
||
import click | ||
from rich.console import Console | ||
|
||
from .models import Target | ||
from .policy import PolicyParser | ||
from .simulator import TrafficSimulator | ||
|
||
console = Console() | ||
|
||
|
||
@click.group() | ||
def cli() -> None: | ||
"""knetvis - Kubernetes Network Policy Visualization Tool""" | ||
pass | ||
|
||
|
||
@cli.command() | ||
@click.argument("source") | ||
@click.argument("destination") | ||
def test(source: str, destination: str) -> None: | ||
"""Test connectivity between resources.""" | ||
try: | ||
source_target = Target.from_str(source) | ||
dest_target = Target.from_str(destination) | ||
parser = PolicyParser() | ||
simulator = TrafficSimulator(parser) | ||
|
||
if not simulator.check_resource_exists(source_target): | ||
console.print(f"[red]Error: Source resource {source} not found[/red]") | ||
return | ||
if not simulator.check_resource_exists(dest_target): | ||
console.print( | ||
f"[red]Error: Destination resource {destination} not found[/red]" | ||
) | ||
return | ||
|
||
allowed = simulator.test_connectivity(source_target, dest_target) | ||
|
||
if allowed: | ||
console.print("[green]✓ Traffic is allowed[/green]") | ||
else: | ||
console.print("[red]✗ Traffic is blocked[/red]") | ||
|
||
except Exception as e: | ||
console.print(f"[red]Error: {str(e)}[/red]") | ||
|
||
|
||
@cli.command() | ||
@click.argument("policy-file") | ||
def validate(policy_file: str) -> None: | ||
"""Validate a network policy file""" | ||
try: | ||
if not os.path.exists(policy_file): | ||
console.print(f"[red]Error: File '{policy_file}' does not exist[/red]") | ||
return | ||
|
||
parser = PolicyParser() | ||
is_valid, message = parser.validate_policy(policy_file) | ||
|
||
if is_valid: | ||
console.print("[green]✓ Policy is valid[/green]") | ||
else: | ||
console.print("[yellow]Policy has potential issues:[/yellow]") | ||
console.print(f"[yellow]{message}[/yellow]") | ||
|
||
except Exception as e: | ||
console.print(f"[red]Error: {str(e)}[/red]") | ||
|
||
|
||
if __name__ == "__main__": | ||
cli() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import re | ||
from dataclasses import dataclass | ||
from typing import ClassVar, Pattern | ||
|
||
|
||
@dataclass | ||
class Target: | ||
namespace: str | ||
kind: str | ||
name: str | ||
TARGET_PATTERN: ClassVar[Pattern] = re.compile(r"^(?:([^/]+)/)?([^/]+)/([^/]+)$") | ||
|
||
@classmethod | ||
def from_str(cls, target_str: str) -> "Target": | ||
match = cls.TARGET_PATTERN.match(target_str) | ||
if not match: | ||
raise ValueError( | ||
f"Invalid target format: {target_str}. " | ||
"Expected format: [namespace/]kind/name" | ||
) | ||
namespace, kind, name = match.groups() | ||
return cls(namespace=namespace or "default", kind=kind, name=name) | ||
|
||
def __str__(self) -> str: | ||
"""Return string representation in format namespace/kind/name""" | ||
return f"{self.namespace}/{self.kind}/{self.name}" |
Oops, something went wrong.