Skip to content

Commit

Permalink
Add GitHub Actions workflows for CI/CD and also did clinting cleanups…
Browse files Browse the repository at this point in the history
… for the whole codebase
  • Loading branch information
samuelarogbonlo committed Jan 10, 2025
1 parent a4eb10c commit f4a354f
Show file tree
Hide file tree
Showing 18 changed files with 911 additions and 756 deletions.
4 changes: 1 addition & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# .github/workflows/ci.yml
name: CI

on:
Expand Down Expand Up @@ -66,5 +65,4 @@ jobs:
uses: actions/upload-artifact@v2
with:
name: dist
path: dist/

path: dist/
1 change: 0 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# .github/workflows/publish.yml
name: Publish to PyPI

on:
Expand Down
28 changes: 8 additions & 20 deletions pyproject.toml
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",
Expand All @@ -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"]
48 changes: 48 additions & 0 deletions setup.cfg
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
9 changes: 5 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
setup(
name="knetvis",
version="0.1.0",
author="Your Name",
author_email="your.email@example.com",
author="Samuel Arogbonlo",
author_email="sbayo971@gmail.com",
description="Kubernetes Network Policy Visualization Tool",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/yourusername/knetvis",
packages=find_packages(),
package_dir={"": "src"}, # Add this line - tells setuptools packages are in src directory
packages=find_packages(where="src"), # Update this line - look for packages in src directory
classifiers=[
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
Expand All @@ -35,7 +36,7 @@
],
entry_points={
"console_scripts": [
"knetvis=src.main:cli",
"knetvis=knetvis.cli:cli",
],
},
)
Empty file removed src/__init__.py
Empty file.
14 changes: 14 additions & 0 deletions src/knetvis/__init__.py
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",
]
73 changes: 73 additions & 0 deletions src/knetvis/cli.py
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()
26 changes: 26 additions & 0 deletions src/knetvis/models.py
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}"
Loading

0 comments on commit f4a354f

Please sign in to comment.