Skip to content

Commit fdf7783

Browse files
committed
improve path resolution
1 parent 1351d9d commit fdf7783

13 files changed

Lines changed: 105 additions & 32 deletions

File tree

README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ A Python library for rendering Helm charts and Kubernetes resources with optiona
1111
- `KubernetesResource` class for raw Kubernetes resources (no Helm required)
1212
- `TemplateRegistry` for managing multiple templates (charts and resources)
1313
- Command-line interface (CLI) for rendering and applying manifests
14+
- Resource visualization with Graphviz DOT diagrams showing resource relationships
1415
- Automatic Docker image build and load steps (executed sequentially during template registration)
1516
- Git operations for manifest repository management
1617
- Docker image build and push utilities with custom Dockerfile support
@@ -363,6 +364,49 @@ for template_class in templates:
363364

364365
**For HelmChart:** Renders to `manifests/{chart-name}/{chart-name}-manifests.yaml`, writes extra manifests to `manifests/{chart-name}/`, and generates ArgoCD Application to `manifests/apps/{chart-name}-application.yaml` (if enabled).
365366

367+
### Visualizing Resource Relationships
368+
369+
Generate Graphviz DOT diagrams to visualize Kubernetes resources and their relationships:
370+
371+
```bash
372+
# Generate visualization and save to file
373+
kubeman visualize --file kubeman.py --output diagram.dot
374+
375+
# Output to stdout
376+
kubeman visualize --file kubeman.py
377+
378+
# Include CustomResourceDefinitions in visualization
379+
kubeman visualize --file kubeman.py --output diagram.dot --show-crds
380+
381+
# Use custom manifests directory
382+
kubeman visualize --file kubeman.py --output-dir ./custom-manifests --output diagram.dot
383+
```
384+
385+
The visualization command:
386+
1. Renders templates to generate manifests (build steps are automatically skipped)
387+
2. Analyzes rendered manifests to detect relationships (ConfigMap references, Service selectors, network connections, etc.)
388+
3. Generates a Graphviz DOT diagram showing resource hierarchy and relationships
389+
4. Outputs to a file or stdout
390+
391+
**Rendering the diagram:**
392+
393+
After generating the DOT file, render it to an image using Graphviz:
394+
395+
```bash
396+
# Generate PNG image
397+
dot -Tpng diagram.dot -o diagram.png
398+
399+
# Generate SVG image
400+
dot -Tsvg diagram.dot -o diagram.svg
401+
```
402+
403+
**Visualization features:**
404+
- Shows resources grouped by namespace
405+
- Displays relationships between resources (uses, selects, connects-to)
406+
- Includes connection addresses (e.g., database URLs from ConfigMaps)
407+
- Filters to only show resources from templates in your `kubeman.py` file
408+
- Optionally includes CustomResourceDefinitions (hidden by default)
409+
366410
**For KubernetesResource:** Writes each manifest to `manifests/{name}/{manifest-name}-{kind}.yaml` and generates ArgoCD Application to `manifests/apps/{name}-application.yaml` (if enabled).
367411

368412
### Advanced Chart Configuration

examples/fullstack/templates/backend.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
for the fullstack TODO application.
66
"""
77

8-
from pathlib import Path
98
from kubeman import KubernetesResource, TemplateRegistry
109

1110

@@ -98,11 +97,11 @@ def build(self) -> None:
9897
"""Build Docker image for backend API"""
9998
from kubeman import DockerManager
10099

101-
backend_dir = Path(__file__).parent.parent / "backend"
100+
context_path = self.resolve_path("../backend")
102101
docker = DockerManager()
103102
docker.build_image(
104103
component="backend-api",
105-
context_path=str(backend_dir),
104+
context_path=context_path,
106105
tag="latest",
107106
dockerfile="Dockerfile",
108107
)

examples/fullstack/templates/frontend.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
for the fullstack TODO application.
66
"""
77

8-
from pathlib import Path
98
from kubeman import KubernetesResource, TemplateRegistry
109

1110

@@ -117,11 +116,11 @@ def build(self) -> None:
117116
"""Build Docker image for frontend app"""
118117
from kubeman import DockerManager
119118

120-
frontend_dir = Path(__file__).parent.parent / "frontend"
119+
context_path = self.resolve_path("../frontend")
121120
docker = DockerManager()
122121
docker.build_image(
123122
component="frontend-app",
124-
context_path=str(frontend_dir),
123+
context_path=context_path,
125124
tag="latest",
126125
dockerfile="Dockerfile",
127126
)

examples/fullstack/templates/postgres_db.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,7 @@ def __init__(self):
133133

134134
def extra_manifests(self) -> list[dict]:
135135
"""Add ConfigMap with init.sql for database initialization"""
136-
from pathlib import Path
137-
138-
init_sql_path = Path(__file__).parent.parent / "init.sql"
136+
init_sql_path = self.resolve_path("../init.sql")
139137
init_sql_content = init_sql_path.read_text()
140138

141139
return [

examples/kafka/templates/stock_price_consumer.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,13 @@ def __init__(self):
7777

7878
def build(self) -> None:
7979
"""Build Docker image for stock price consumer"""
80-
from pathlib import Path
8180
from kubeman import DockerManager
8281

83-
kafka_dir = Path(__file__).parent.parent
82+
context_path = self.resolve_path("..")
8483
docker = DockerManager()
8584
docker.build_image(
8685
component="stock-price-consumer",
87-
context_path=str(kafka_dir),
86+
context_path=context_path,
8887
tag="latest",
8988
dockerfile="Dockerfile.consumer",
9089
)

examples/kafka/templates/stock_price_producer.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,13 @@ def __init__(self):
9191

9292
def build(self) -> None:
9393
"""Build Docker image for stock price producer"""
94-
from pathlib import Path
9594
from kubeman import DockerManager
9695

97-
kafka_dir = Path(__file__).parent.parent
96+
context_path = self.resolve_path("..")
9897
docker = DockerManager()
9998
docker.build_image(
10099
component="stock-price-producer",
101-
context_path=str(kafka_dir),
100+
context_path=context_path,
102101
tag="latest",
103102
dockerfile="Dockerfile.producer",
104103
)

examples/spark/README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,13 @@ To modify the build or load behavior, edit `custom_pyspark_job.py`:
106106
```python
107107
def build(self) -> None:
108108
"""Build Docker image for custom PySpark job"""
109-
from pathlib import Path
110109
from kubeman import DockerManager
111110

112-
spark_dir = Path(__file__).parent
111+
context_path = self.resolve_path("..")
113112
docker = DockerManager()
114113
docker.build_image(
115114
component="custom-pyspark-job",
116-
context_path=str(spark_dir),
115+
context_path=context_path,
117116
tag="latest",
118117
dockerfile="Dockerfile.pyspark",
119118
)

examples/spark/templates/custom_pyspark_job.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,13 @@ def extra_manifests(self) -> list[dict]:
8989

9090
def build(self) -> None:
9191
"""Build Docker image for custom PySpark job"""
92-
from pathlib import Path
9392
from kubeman import DockerManager
9493

95-
spark_dir = Path(__file__).parent.parent
94+
context_path = self.resolve_path("..")
9695
docker = DockerManager()
9796
docker.build_image(
9897
component="custom-pyspark-job",
99-
context_path=str(spark_dir),
98+
context_path=context_path,
10099
tag="latest",
101100
dockerfile="Dockerfile.pyspark",
102101
)

kubeman/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@
2929
"apply_manifests",
3030
]
3131

32-
__version__ = "0.5.3"
32+
__version__ = "0.5.4"

kubeman/docker.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from pathlib import Path
2-
from typing import Optional
2+
from typing import Optional, Union
33
from kubeman.config import Config
44
from kubeman.executor import CommandExecutor, get_executor
55

@@ -41,15 +41,15 @@ def __init__(
4141
def build_image(
4242
self,
4343
component: str,
44-
context_path: str,
44+
context_path: Union[str, Path],
4545
tag: Optional[str] = None,
4646
dockerfile: Optional[str] = None,
4747
) -> str:
4848
"""Build a Docker image for a component.
4949
5050
Args:
5151
component: The name of the component (e.g., 'frontend')
52-
context_path: Path to the Docker context
52+
context_path: Path to the Docker context (str or Path)
5353
tag: Optional specific tag, defaults to 'latest'
5454
dockerfile: Optional Dockerfile name (defaults to 'Dockerfile')
5555
@@ -59,7 +59,7 @@ def build_image(
5959
tag = tag or "latest"
6060
image_name = f"{self.registry}/{component}:{tag}"
6161

62-
context = Path(context_path)
62+
context = Path(context_path).resolve()
6363
dockerfile_path = context / (dockerfile or "Dockerfile")
6464

6565
cmd = [
@@ -95,15 +95,15 @@ def push_image(self, component: str, tag: Optional[str] = None) -> str:
9595
def build_and_push(
9696
self,
9797
component: str,
98-
context_path: str,
98+
context_path: Union[str, Path],
9999
tag: Optional[str] = None,
100100
dockerfile: Optional[str] = None,
101101
) -> str:
102102
"""Build and push a Docker image in one go.
103103
104104
Args:
105105
component: The name of the component
106-
context_path: Path to the Docker context
106+
context_path: Path to the Docker context (str or Path)
107107
tag: Optional specific tag
108108
dockerfile: Optional Dockerfile name (defaults to 'Dockerfile')
109109
"""

0 commit comments

Comments
 (0)