Merge pull request #35 from compose-viz/dev
chore: add graph of new components
12
.github/workflows/ci.yml
vendored
|
@ -20,18 +20,6 @@ jobs:
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y graphviz
|
sudo apt-get install -y graphviz
|
||||||
|
|
||||||
- name: Validate Test Files
|
|
||||||
run: |
|
|
||||||
docker compose -f tests/ymls/builds/docker-compose.yml config -q
|
|
||||||
docker compose -f tests/ymls/depends_on/docker-compose.yml config -q
|
|
||||||
docker compose -f tests/ymls/extends/docker-compose.yml config -q
|
|
||||||
docker compose -f tests/ymls/links/docker-compose.yml config -q
|
|
||||||
docker compose -f tests/ymls/networks/docker-compose.yml config -q
|
|
||||||
docker compose -f tests/ymls/ports/docker-compose.yml config -q
|
|
||||||
docker compose -f tests/ymls/volumes/docker-compose.yml config -q
|
|
||||||
docker compose -f examples/full-stack-node-app/docker-compose.yml config -q
|
|
||||||
docker compose -f examples/non-normative/docker-compose.yml config -q
|
|
||||||
|
|
||||||
- name: Setup Python 3.10.4
|
- name: Setup Python 3.10.4
|
||||||
uses: actions/setup-python@v3
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -5,13 +5,13 @@ import graphviz
|
||||||
from compose_viz.models.compose import Compose
|
from compose_viz.models.compose import Compose
|
||||||
|
|
||||||
|
|
||||||
def apply_vertex_style(type) -> dict:
|
def apply_vertex_style(type: str) -> dict:
|
||||||
style = {
|
style = {
|
||||||
"service": {
|
"service": {
|
||||||
"shape": "component",
|
"shape": "component",
|
||||||
},
|
},
|
||||||
"volume": {
|
"volume": {
|
||||||
"shape": "folder",
|
"shape": "cylinder",
|
||||||
},
|
},
|
||||||
"network": {
|
"network": {
|
||||||
"shape": "pentagon",
|
"shape": "pentagon",
|
||||||
|
@ -19,24 +19,39 @@ def apply_vertex_style(type) -> dict:
|
||||||
"port": {
|
"port": {
|
||||||
"shape": "circle",
|
"shape": "circle",
|
||||||
},
|
},
|
||||||
|
"env_file": {
|
||||||
|
"shape": "tab",
|
||||||
|
},
|
||||||
|
"porfile": {
|
||||||
|
"shape": "invhouse",
|
||||||
|
},
|
||||||
|
"cgroup": {
|
||||||
|
"shape": "diamond",
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"shape": "box3d",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return style[type]
|
return style[type]
|
||||||
|
|
||||||
|
|
||||||
def apply_edge_style(type) -> dict:
|
def apply_edge_style(type: str) -> dict:
|
||||||
style = {
|
style = {
|
||||||
"ports": {
|
"exposes": {
|
||||||
"style": "solid",
|
"style": "solid",
|
||||||
"dir": "both",
|
"dir": "both",
|
||||||
},
|
},
|
||||||
"links": {
|
"links": {
|
||||||
"style": "solid",
|
"style": "solid",
|
||||||
},
|
},
|
||||||
"volumes": {
|
"volumes_rw": {
|
||||||
"style": "dashed",
|
"style": "dashed",
|
||||||
"dir": "both",
|
"dir": "both",
|
||||||
},
|
},
|
||||||
|
"volumes_ro": {
|
||||||
|
"style": "dashed",
|
||||||
|
},
|
||||||
"depends_on": {
|
"depends_on": {
|
||||||
"style": "dotted",
|
"style": "dotted",
|
||||||
},
|
},
|
||||||
|
@ -45,6 +60,9 @@ def apply_edge_style(type) -> dict:
|
||||||
"arrowhead": "inv",
|
"arrowhead": "inv",
|
||||||
"arrowtail": "dot",
|
"arrowtail": "dot",
|
||||||
},
|
},
|
||||||
|
"env_file": {
|
||||||
|
"style": "solid",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return style[type]
|
return style[type]
|
||||||
|
@ -71,19 +89,38 @@ class Graph:
|
||||||
def render(self, format: str, cleanup: bool = True) -> None:
|
def render(self, format: str, cleanup: bool = True) -> None:
|
||||||
for service in self.compose.services:
|
for service in self.compose.services:
|
||||||
if service.image is not None:
|
if service.image is not None:
|
||||||
self.add_vertex(service.name, "service", lable=f"{service.name}\n({service.image})")
|
self.add_vertex(
|
||||||
|
service.name,
|
||||||
|
"service",
|
||||||
|
lable=f"{service.container_name if service.container_name else service.name}\n({service.image})",
|
||||||
|
)
|
||||||
if service.extends is not None:
|
if service.extends is not None:
|
||||||
self.add_vertex(service.name, "service", lable=f"{service.name}\n")
|
self.add_vertex(service.name, "service", lable=f"{service.name}\n")
|
||||||
self.add_edge(service.extends.service_name, service.name, "extends")
|
self.add_edge(service.extends.service_name, service.name, "extends")
|
||||||
|
if service.cgroup_parent is not None:
|
||||||
|
self.add_vertex(service.cgroup_parent, "cgroup")
|
||||||
|
self.add_edge(service.name, service.cgroup_parent, "links")
|
||||||
|
|
||||||
for network in service.networks:
|
for network in service.networks:
|
||||||
self.add_vertex(network, "network", lable=f"net:{network}")
|
self.add_vertex(network, "network", lable=f"net:{network}")
|
||||||
self.add_edge(service.name, network, "links")
|
self.add_edge(service.name, network, "links")
|
||||||
for volume in service.volumes:
|
for volume in service.volumes:
|
||||||
self.add_vertex(volume.source, "volume")
|
self.add_vertex(volume.source, "volume")
|
||||||
self.add_edge(service.name, volume.source, "volumes", lable=volume.target)
|
self.add_edge(
|
||||||
|
service.name,
|
||||||
|
volume.source,
|
||||||
|
"volumes_rw" if "rw" in volume.access_mode else "volumes_ro",
|
||||||
|
lable=volume.target,
|
||||||
|
)
|
||||||
|
for expose in service.expose:
|
||||||
|
self.add_vertex(expose, "port")
|
||||||
|
self.add_edge(expose, service.name, "exposes")
|
||||||
for port in service.ports:
|
for port in service.ports:
|
||||||
self.add_vertex(port.host_port, "port", lable=port.host_port)
|
self.add_vertex(port.host_port, "port", lable=port.host_port)
|
||||||
self.add_edge(port.host_port, service.name, "ports", lable=port.container_port)
|
self.add_edge(port.host_port, service.name, "links", lable=port.container_port)
|
||||||
|
for env_file in service.env_file:
|
||||||
|
self.add_vertex(env_file, "env_file")
|
||||||
|
self.add_edge(env_file, service.name, "env_file")
|
||||||
for link in service.links:
|
for link in service.links:
|
||||||
if ":" in link:
|
if ":" in link:
|
||||||
service_name, alias = link.split(":", 1)
|
service_name, alias = link.split(":", 1)
|
||||||
|
@ -92,5 +129,13 @@ class Graph:
|
||||||
self.add_edge(link, service.name, "links")
|
self.add_edge(link, service.name, "links")
|
||||||
for depends_on in service.depends_on:
|
for depends_on in service.depends_on:
|
||||||
self.add_edge(service.name, depends_on, "depends_on")
|
self.add_edge(service.name, depends_on, "depends_on")
|
||||||
|
for porfile in service.profiles:
|
||||||
|
self.add_vertex(porfile, "porfile")
|
||||||
|
self.add_edge(service.name, porfile, "links")
|
||||||
|
for device in service.devices:
|
||||||
|
self.add_vertex(device.host_path, "device")
|
||||||
|
self.add_edge(
|
||||||
|
device.host_path, service.name, "exposes", f"{device.container_path}\n({device.cgroup_permissions})"
|
||||||
|
)
|
||||||
|
|
||||||
self.dot.render(outfile=f"{self.filename}.{format}", format=format, cleanup=cleanup)
|
self.dot.render(outfile=f"{self.filename}.{format}", format=format, cleanup=cleanup)
|
||||||
|
|
20
compose_viz/models/device.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
class Device:
|
||||||
|
def __init__(self, host_path: str, container_path: str, cgroup_permissions: Optional[str] = None):
|
||||||
|
self._host_path = host_path
|
||||||
|
self._container_path = container_path
|
||||||
|
self._cgroup_permissions = cgroup_permissions
|
||||||
|
|
||||||
|
@property
|
||||||
|
def host_path(self):
|
||||||
|
return self._host_path
|
||||||
|
|
||||||
|
@property
|
||||||
|
def container_path(self):
|
||||||
|
return self._container_path
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cgroup_permissions(self):
|
||||||
|
return self._cgroup_permissions
|
|
@ -1,5 +1,6 @@
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
|
from compose_viz.models.device import Device
|
||||||
from compose_viz.models.extends import Extends
|
from compose_viz.models.extends import Extends
|
||||||
from compose_viz.models.port import Port
|
from compose_viz.models.port import Port
|
||||||
from compose_viz.models.volume import Volume
|
from compose_viz.models.volume import Volume
|
||||||
|
@ -16,6 +17,12 @@ class Service:
|
||||||
depends_on: List[str] = [],
|
depends_on: List[str] = [],
|
||||||
links: List[str] = [],
|
links: List[str] = [],
|
||||||
extends: Optional[Extends] = None,
|
extends: Optional[Extends] = None,
|
||||||
|
cgroup_parent: Optional[str] = None,
|
||||||
|
container_name: Optional[str] = None,
|
||||||
|
devices: List[Device] = [],
|
||||||
|
env_file: List[str] = [],
|
||||||
|
expose: List[str] = [],
|
||||||
|
profiles: List[str] = [],
|
||||||
) -> None:
|
) -> None:
|
||||||
self._name = name
|
self._name = name
|
||||||
self._image = image
|
self._image = image
|
||||||
|
@ -25,6 +32,12 @@ class Service:
|
||||||
self._depends_on = depends_on
|
self._depends_on = depends_on
|
||||||
self._links = links
|
self._links = links
|
||||||
self._extends = extends
|
self._extends = extends
|
||||||
|
self._cgroup_parent = cgroup_parent
|
||||||
|
self._container_name = container_name
|
||||||
|
self._devices = devices
|
||||||
|
self._env_file = env_file
|
||||||
|
self._expose = expose
|
||||||
|
self._profiles = profiles
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
@ -57,3 +70,27 @@ class Service:
|
||||||
@property
|
@property
|
||||||
def extends(self):
|
def extends(self):
|
||||||
return self._extends
|
return self._extends
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cgroup_parent(self):
|
||||||
|
return self._cgroup_parent
|
||||||
|
|
||||||
|
@property
|
||||||
|
def container_name(self):
|
||||||
|
return self._container_name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def devices(self):
|
||||||
|
return self._devices
|
||||||
|
|
||||||
|
@property
|
||||||
|
def env_file(self):
|
||||||
|
return self._env_file
|
||||||
|
|
||||||
|
@property
|
||||||
|
def expose(self):
|
||||||
|
return self._expose
|
||||||
|
|
||||||
|
@property
|
||||||
|
def profiles(self):
|
||||||
|
return self._profiles
|
||||||
|
|
|
@ -5,6 +5,7 @@ from pydantic import ValidationError
|
||||||
|
|
||||||
import compose_viz.spec.compose_spec as spec
|
import compose_viz.spec.compose_spec as spec
|
||||||
from compose_viz.models.compose import Compose, Service
|
from compose_viz.models.compose import Compose, Service
|
||||||
|
from compose_viz.models.device import Device
|
||||||
from compose_viz.models.extends import Extends
|
from compose_viz.models.extends import Extends
|
||||||
from compose_viz.models.port import Port, Protocol
|
from compose_viz.models.port import Port, Protocol
|
||||||
from compose_viz.models.volume import Volume, VolumeType
|
from compose_viz.models.volume import Volume, VolumeType
|
||||||
|
@ -176,6 +177,50 @@ class Parser:
|
||||||
if service_data.links is not None:
|
if service_data.links is not None:
|
||||||
service_links = service_data.links
|
service_links = service_data.links
|
||||||
|
|
||||||
|
cgroup_parent: Optional[str] = None
|
||||||
|
if service_data.cgroup_parent is not None:
|
||||||
|
cgroup_parent = service_data.cgroup_parent
|
||||||
|
|
||||||
|
container_name: Optional[str] = None
|
||||||
|
if service_data.container_name is not None:
|
||||||
|
container_name = service_data.container_name
|
||||||
|
|
||||||
|
env_file: List[str] = []
|
||||||
|
if service_data.env_file is not None:
|
||||||
|
if type(service_data.env_file) is spec.StringOrList:
|
||||||
|
if type(service_data.env_file.__root__) is spec.ListOfStrings:
|
||||||
|
env_file = service_data.env_file.__root__.__root__
|
||||||
|
elif type(service_data.env_file.__root__) is str:
|
||||||
|
env_file.append(service_data.env_file.__root__)
|
||||||
|
|
||||||
|
expose: List[str] = []
|
||||||
|
if service_data.expose is not None:
|
||||||
|
for port in service_data.expose:
|
||||||
|
expose.append(str(port))
|
||||||
|
|
||||||
|
profiles: List[str] = []
|
||||||
|
if service_data.profiles is not None:
|
||||||
|
if type(service_data.profiles) is spec.ListOfStrings:
|
||||||
|
profiles = service_data.profiles.__root__
|
||||||
|
|
||||||
|
devices: List[Device] = []
|
||||||
|
if service_data.devices is not None:
|
||||||
|
for device_data in service_data.devices:
|
||||||
|
if type(device_data) is str:
|
||||||
|
assert ":" in device_data, "Invalid volume input, aborting."
|
||||||
|
|
||||||
|
spilt_data = device_data.split(":")
|
||||||
|
if len(spilt_data) == 2:
|
||||||
|
devices.append(Device(host_path=spilt_data[0], container_path=spilt_data[1]))
|
||||||
|
elif len(spilt_data) == 3:
|
||||||
|
devices.append(
|
||||||
|
Device(
|
||||||
|
host_path=spilt_data[0],
|
||||||
|
container_path=spilt_data[1],
|
||||||
|
cgroup_permissions=spilt_data[2],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
services.append(
|
services.append(
|
||||||
Service(
|
Service(
|
||||||
name=service_name,
|
name=service_name,
|
||||||
|
@ -186,6 +231,12 @@ class Parser:
|
||||||
depends_on=service_depends_on,
|
depends_on=service_depends_on,
|
||||||
volumes=service_volumes,
|
volumes=service_volumes,
|
||||||
links=service_links,
|
links=service_links,
|
||||||
|
cgroup_parent=cgroup_parent,
|
||||||
|
container_name=container_name,
|
||||||
|
env_file=env_file,
|
||||||
|
expose=expose,
|
||||||
|
profiles=profiles,
|
||||||
|
devices=devices,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 134 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 93 KiB |
|
@ -6,10 +6,19 @@ services:
|
||||||
- back-tier
|
- back-tier
|
||||||
|
|
||||||
monitoring:
|
monitoring:
|
||||||
|
env_file:
|
||||||
|
- a.env
|
||||||
|
- b.env
|
||||||
|
container_name: monitoring-server
|
||||||
image: awesome/monitoring
|
image: awesome/monitoring
|
||||||
networks:
|
networks:
|
||||||
- admin
|
- admin
|
||||||
|
expose:
|
||||||
|
- 1234
|
||||||
|
profiles:
|
||||||
|
- tools
|
||||||
|
- foo
|
||||||
|
cgroup_parent: awesome-parent
|
||||||
|
|
||||||
backend:
|
backend:
|
||||||
networks:
|
networks:
|
||||||
|
@ -36,8 +45,12 @@ services:
|
||||||
- "8000:5010"
|
- "8000:5010"
|
||||||
links:
|
links:
|
||||||
- "db:database"
|
- "db:database"
|
||||||
|
cgroup_parent: awesome-parent
|
||||||
db:
|
db:
|
||||||
image: postgres
|
image: postgres
|
||||||
|
devices:
|
||||||
|
- "/dev/ttyUSB2:/dev/ttyUSB3"
|
||||||
|
- "/dev/sda:/dev/xvda:rwm"
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
front-tier:
|
front-tier:
|
||||||
|
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 70 KiB |
|
@ -38,8 +38,7 @@
|
||||||
<!-- 0.0.0.06379->redis -->
|
<!-- 0.0.0.06379->redis -->
|
||||||
<g id="edge2" class="edge">
|
<g id="edge2" class="edge">
|
||||||
<title>0.0.0.06379->redis</title>
|
<title>0.0.0.06379->redis</title>
|
||||||
<path fill="none" stroke="black" d="M104.53,-188.06C126.48,-169.27 151.57,-147.8 170.41,-131.68"/>
|
<path fill="none" stroke="black" d="M96.9,-194.6C120.47,-174.43 149.35,-149.71 170.41,-131.68"/>
|
||||||
<polygon fill="black" stroke="black" points="102.22,-185.44 96.9,-194.6 106.77,-190.75 102.22,-185.44"/>
|
|
||||||
<polygon fill="black" stroke="black" points="172.75,-134.28 178.07,-125.12 168.2,-128.96 172.75,-134.28"/>
|
<polygon fill="black" stroke="black" points="172.75,-134.28 178.07,-125.12 168.2,-128.96 172.75,-134.28"/>
|
||||||
<text text-anchor="middle" x="171.25" y="-146.8" font-family="Times New Roman,serif" font-size="14.00">6379</text>
|
<text text-anchor="middle" x="171.25" y="-146.8" font-family="Times New Roman,serif" font-size="14.00">6379</text>
|
||||||
</g>
|
</g>
|
||||||
|
@ -67,7 +66,8 @@
|
||||||
<!-- db-data -->
|
<!-- db-data -->
|
||||||
<g id="node6" class="node">
|
<g id="node6" class="node">
|
||||||
<title>db-data</title>
|
<title>db-data</title>
|
||||||
<polygon fill="none" stroke="black" points="700.75,-36 697.75,-40 676.75,-40 673.75,-36 641.75,-36 641.75,0 700.75,0 700.75,-36"/>
|
<path fill="none" stroke="black" d="M700.75,-32.73C700.75,-34.53 687.52,-36 671.25,-36 654.97,-36 641.75,-34.53 641.75,-32.73 641.75,-32.73 641.75,-3.27 641.75,-3.27 641.75,-1.47 654.97,0 671.25,0 687.52,0 700.75,-1.47 700.75,-3.27 700.75,-3.27 700.75,-32.73 700.75,-32.73"/>
|
||||||
|
<path fill="none" stroke="black" d="M700.75,-32.73C700.75,-30.92 687.52,-29.45 671.25,-29.45 654.97,-29.45 641.75,-30.92 641.75,-32.73"/>
|
||||||
<text text-anchor="middle" x="671.25" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">db-data</text>
|
<text text-anchor="middle" x="671.25" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">db-data</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- db->db-data -->
|
<!-- db->db-data -->
|
||||||
|
@ -108,8 +108,7 @@
|
||||||
<!-- 0.0.0.05000->vote -->
|
<!-- 0.0.0.05000->vote -->
|
||||||
<g id="edge6" class="edge">
|
<g id="edge6" class="edge">
|
||||||
<title>0.0.0.05000->vote</title>
|
<title>0.0.0.05000->vote</title>
|
||||||
<path fill="none" stroke="black" d="M271.25,-327.24C271.25,-304.1 271.25,-279.18 271.25,-260.67"/>
|
<path fill="none" stroke="black" d="M271.25,-337.29C271.25,-311.63 271.25,-282.06 271.25,-260.85"/>
|
||||||
<polygon fill="black" stroke="black" points="267.75,-327.29 271.25,-337.29 274.75,-327.29 267.75,-327.29"/>
|
|
||||||
<polygon fill="black" stroke="black" points="274.75,-260.58 271.25,-250.58 267.75,-260.58 274.75,-260.58"/>
|
<polygon fill="black" stroke="black" points="274.75,-260.58 271.25,-250.58 267.75,-260.58 274.75,-260.58"/>
|
||||||
<text text-anchor="middle" x="278.25" y="-308.29" font-family="Times New Roman,serif" font-size="14.00">80</text>
|
<text text-anchor="middle" x="278.25" y="-308.29" font-family="Times New Roman,serif" font-size="14.00">80</text>
|
||||||
</g>
|
</g>
|
||||||
|
@ -143,8 +142,7 @@
|
||||||
<!-- 0.0.0.05001->result -->
|
<!-- 0.0.0.05001->result -->
|
||||||
<g id="edge9" class="edge">
|
<g id="edge9" class="edge">
|
||||||
<title>0.0.0.05001->result</title>
|
<title>0.0.0.05001->result</title>
|
||||||
<path fill="none" stroke="black" d="M614.25,-327.24C614.25,-304.1 614.25,-279.18 614.25,-260.67"/>
|
<path fill="none" stroke="black" d="M614.25,-337.29C614.25,-311.63 614.25,-282.06 614.25,-260.85"/>
|
||||||
<polygon fill="black" stroke="black" points="610.75,-327.29 614.25,-337.29 617.75,-327.29 610.75,-327.29"/>
|
|
||||||
<polygon fill="black" stroke="black" points="617.75,-260.58 614.25,-250.58 610.75,-260.58 617.75,-260.58"/>
|
<polygon fill="black" stroke="black" points="617.75,-260.58 614.25,-250.58 610.75,-260.58 617.75,-260.58"/>
|
||||||
<text text-anchor="middle" x="621.25" y="-308.29" font-family="Times New Roman,serif" font-size="14.00">80</text>
|
<text text-anchor="middle" x="621.25" y="-308.29" font-family="Times New Roman,serif" font-size="14.00">80</text>
|
||||||
</g>
|
</g>
|
||||||
|
@ -181,7 +179,8 @@
|
||||||
<!-- /var/run/docker.sock -->
|
<!-- /var/run/docker.sock -->
|
||||||
<g id="node13" class="node">
|
<g id="node13" class="node">
|
||||||
<title>/var/run/docker.sock</title>
|
<title>/var/run/docker.sock</title>
|
||||||
<polygon fill="none" stroke="black" points="926.75,-124 923.75,-128 902.75,-128 899.75,-124 793.75,-124 793.75,-88 926.75,-88 926.75,-124"/>
|
<path fill="none" stroke="black" d="M926.75,-120.73C926.75,-122.53 896.94,-124 860.25,-124 823.55,-124 793.75,-122.53 793.75,-120.73 793.75,-120.73 793.75,-91.27 793.75,-91.27 793.75,-89.47 823.55,-88 860.25,-88 896.94,-88 926.75,-89.47 926.75,-91.27 926.75,-91.27 926.75,-120.73 926.75,-120.73"/>
|
||||||
|
<path fill="none" stroke="black" d="M926.75,-120.73C926.75,-118.92 896.94,-117.45 860.25,-117.45 823.55,-117.45 793.75,-118.92 793.75,-120.73"/>
|
||||||
<text text-anchor="middle" x="860.25" y="-102.3" font-family="Times New Roman,serif" font-size="14.00">/var/run/docker.sock</text>
|
<text text-anchor="middle" x="860.25" y="-102.3" font-family="Times New Roman,serif" font-size="14.00">/var/run/docker.sock</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- visualizer->/var/run/docker.sock -->
|
<!-- visualizer->/var/run/docker.sock -->
|
||||||
|
@ -201,8 +200,7 @@
|
||||||
<!-- 0.0.0.08080->visualizer -->
|
<!-- 0.0.0.08080->visualizer -->
|
||||||
<g id="edge14" class="edge">
|
<g id="edge14" class="edge">
|
||||||
<title>0.0.0.08080->visualizer</title>
|
<title>0.0.0.08080->visualizer</title>
|
||||||
<path fill="none" stroke="black" d="M860.25,-327.24C860.25,-304.1 860.25,-279.18 860.25,-260.67"/>
|
<path fill="none" stroke="black" d="M860.25,-337.29C860.25,-311.63 860.25,-282.06 860.25,-260.85"/>
|
||||||
<polygon fill="black" stroke="black" points="856.75,-327.29 860.25,-337.29 863.75,-327.29 856.75,-327.29"/>
|
|
||||||
<polygon fill="black" stroke="black" points="863.75,-260.58 860.25,-250.58 856.75,-260.58 863.75,-260.58"/>
|
<polygon fill="black" stroke="black" points="863.75,-260.58 860.25,-250.58 856.75,-260.58 863.75,-260.58"/>
|
||||||
<text text-anchor="middle" x="874.25" y="-308.29" font-family="Times New Roman,serif" font-size="14.00">8080</text>
|
<text text-anchor="middle" x="874.25" y="-308.29" font-family="Times New Roman,serif" font-size="14.00">8080</text>
|
||||||
</g>
|
</g>
|
||||||
|
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
@ -12,11 +12,17 @@ runner = CliRunner()
|
||||||
"test_file_path",
|
"test_file_path",
|
||||||
[
|
[
|
||||||
"tests/ymls/builds/docker-compose.yml",
|
"tests/ymls/builds/docker-compose.yml",
|
||||||
|
"tests/ymls/cgroup_parent/docker-compose.yml",
|
||||||
|
"tests/ymls/container_name/docker-compose.yml",
|
||||||
"tests/ymls/depends_on/docker-compose.yml",
|
"tests/ymls/depends_on/docker-compose.yml",
|
||||||
|
"tests/ymls/devices/docker-compose.yml",
|
||||||
|
"tests/ymls/env_file/docker-compose.yml",
|
||||||
|
"tests/ymls/expose/docker-compose.yml",
|
||||||
"tests/ymls/extends/docker-compose.yml",
|
"tests/ymls/extends/docker-compose.yml",
|
||||||
"tests/ymls/links/docker-compose.yml",
|
"tests/ymls/links/docker-compose.yml",
|
||||||
"tests/ymls/networks/docker-compose.yml",
|
"tests/ymls/networks/docker-compose.yml",
|
||||||
"tests/ymls/ports/docker-compose.yml",
|
"tests/ymls/ports/docker-compose.yml",
|
||||||
|
"tests/ymls/profiles/docker-compose.yml",
|
||||||
"tests/ymls/volumes/docker-compose.yml",
|
"tests/ymls/volumes/docker-compose.yml",
|
||||||
"examples/full-stack-node-app/docker-compose.yml",
|
"examples/full-stack-node-app/docker-compose.yml",
|
||||||
"examples/non-normative/docker-compose.yml",
|
"examples/non-normative/docker-compose.yml",
|
||||||
|
|
22
tests/test_devices.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
from compose_viz.models.device import Device
|
||||||
|
|
||||||
|
|
||||||
|
def test_device_init_normal() -> None:
|
||||||
|
try:
|
||||||
|
d = Device(host_path="/dev/ttyUSB0", container_path="/dev/ttyUSB1")
|
||||||
|
|
||||||
|
assert d.host_path == "/dev/ttyUSB0"
|
||||||
|
assert d.container_path == "/dev/ttyUSB1"
|
||||||
|
except Exception as e:
|
||||||
|
assert False, e
|
||||||
|
|
||||||
|
|
||||||
|
def test_device_with_cgroup_permissions() -> None:
|
||||||
|
try:
|
||||||
|
d = Device(host_path="/dev/sda1", container_path="/dev/xvda", cgroup_permissions="rwm")
|
||||||
|
|
||||||
|
assert d.host_path == "/dev/sda1"
|
||||||
|
assert d.container_path == "/dev/xvda"
|
||||||
|
assert d.cgroup_permissions == "rwm"
|
||||||
|
except Exception as e:
|
||||||
|
assert False, e
|
|
@ -1,6 +1,7 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from compose_viz.models.compose import Compose
|
from compose_viz.models.compose import Compose
|
||||||
|
from compose_viz.models.device import Device
|
||||||
from compose_viz.models.extends import Extends
|
from compose_viz.models.extends import Extends
|
||||||
from compose_viz.models.port import Port, Protocol
|
from compose_viz.models.port import Port, Protocol
|
||||||
from compose_viz.models.service import Service
|
from compose_viz.models.service import Service
|
||||||
|
@ -241,6 +242,123 @@ from compose_viz.parser import Parser
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"cgroup_parent/docker-compose",
|
||||||
|
Compose(
|
||||||
|
services=[
|
||||||
|
Service(
|
||||||
|
name="frontend",
|
||||||
|
image="awesome/frontend",
|
||||||
|
cgroup_parent="system",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"container_name/docker-compose",
|
||||||
|
Compose(
|
||||||
|
services=[
|
||||||
|
Service(
|
||||||
|
name="frontend",
|
||||||
|
image="awesome/frontend",
|
||||||
|
container_name="myfrontend",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"env_file/docker-compose",
|
||||||
|
Compose(
|
||||||
|
services=[
|
||||||
|
Service(
|
||||||
|
name="frontend",
|
||||||
|
image="awesome/frontend",
|
||||||
|
env_file=["a.env"],
|
||||||
|
),
|
||||||
|
Service(
|
||||||
|
name="backend",
|
||||||
|
image="awesome/backend",
|
||||||
|
env_file=["b.env"],
|
||||||
|
),
|
||||||
|
Service(
|
||||||
|
name="db",
|
||||||
|
image="awesome/db",
|
||||||
|
env_file=["c.env", "d.env"],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"expose/docker-compose",
|
||||||
|
Compose(
|
||||||
|
services=[
|
||||||
|
Service(
|
||||||
|
name="frontend",
|
||||||
|
image="awesome/frontend",
|
||||||
|
expose=["27118"],
|
||||||
|
),
|
||||||
|
Service(
|
||||||
|
name="backend",
|
||||||
|
image="awesome/backend",
|
||||||
|
expose=["27017", "27018"],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"profiles/docker-compose",
|
||||||
|
Compose(
|
||||||
|
services=[
|
||||||
|
Service(
|
||||||
|
name="frontend",
|
||||||
|
image="awesome/frontend",
|
||||||
|
profiles=["frontend"],
|
||||||
|
),
|
||||||
|
Service(
|
||||||
|
name="phpmyadmin",
|
||||||
|
image="phpmyadmin",
|
||||||
|
profiles=["debug"],
|
||||||
|
),
|
||||||
|
Service(
|
||||||
|
name="db",
|
||||||
|
image="awesome/db",
|
||||||
|
profiles=["db", "sql"],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"devices/docker-compose",
|
||||||
|
Compose(
|
||||||
|
services=[
|
||||||
|
Service(
|
||||||
|
name="frontend",
|
||||||
|
image="awesome/frontend",
|
||||||
|
devices=[
|
||||||
|
Device(
|
||||||
|
host_path="/dev/ttyUSB0",
|
||||||
|
container_path="/dev/ttyUSB1",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Service(
|
||||||
|
name="backend",
|
||||||
|
image="awesome/backend",
|
||||||
|
devices=[
|
||||||
|
Device(
|
||||||
|
host_path="/dev/ttyUSB2",
|
||||||
|
container_path="/dev/ttyUSB3",
|
||||||
|
),
|
||||||
|
Device(
|
||||||
|
host_path="/dev/sda",
|
||||||
|
container_path="/dev/xvda",
|
||||||
|
cgroup_permissions="rwm",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_parse_file(test_file_path: str, expected: Compose) -> None:
|
def test_parse_file(test_file_path: str, expected: Compose) -> None:
|
||||||
|
@ -275,3 +393,16 @@ def test_parse_file(test_file_path: str, expected: Compose) -> None:
|
||||||
if (actual_service.extends is not None) and (expected_service.extends is not None):
|
if (actual_service.extends is not None) and (expected_service.extends is not None):
|
||||||
assert actual_service.extends.service_name == expected_service.extends.service_name
|
assert actual_service.extends.service_name == expected_service.extends.service_name
|
||||||
assert actual_service.extends.from_file == expected_service.extends.from_file
|
assert actual_service.extends.from_file == expected_service.extends.from_file
|
||||||
|
|
||||||
|
assert actual_service.cgroup_parent == expected_service.cgroup_parent
|
||||||
|
assert actual_service.container_name == expected_service.container_name
|
||||||
|
|
||||||
|
assert actual_service.expose == expected_service.expose
|
||||||
|
assert actual_service.env_file == expected_service.env_file
|
||||||
|
assert actual_service.profiles == expected_service.profiles
|
||||||
|
|
||||||
|
assert len(actual_service.devices) == len(expected_service.devices)
|
||||||
|
for actual_device, expected_device in zip(actual_service.devices, expected_service.devices):
|
||||||
|
assert actual_device.host_path == expected_device.host_path
|
||||||
|
assert actual_device.container_path == expected_device.container_path
|
||||||
|
assert actual_device.cgroup_permissions == expected_device.cgroup_permissions
|
||||||
|
|
6
tests/ymls/cgroup_parent/docker-compose.yml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
frontend:
|
||||||
|
image: awesome/frontend
|
||||||
|
cgroup_parent: "system"
|
6
tests/ymls/container_name/docker-compose.yml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
frontend:
|
||||||
|
image: awesome/frontend
|
||||||
|
container_name: "myfrontend"
|
12
tests/ymls/devices/docker-compose.yml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
frontend:
|
||||||
|
image: awesome/frontend
|
||||||
|
devices:
|
||||||
|
- "/dev/ttyUSB0:/dev/ttyUSB1"
|
||||||
|
backend:
|
||||||
|
image: awesome/backend
|
||||||
|
devices:
|
||||||
|
- "/dev/ttyUSB2:/dev/ttyUSB3"
|
||||||
|
- "/dev/sda:/dev/xvda:rwm"
|
15
tests/ymls/env_file/docker-compose.yml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
frontend:
|
||||||
|
image: awesome/frontend
|
||||||
|
env_file: a.env
|
||||||
|
backend:
|
||||||
|
image: awesome/backend
|
||||||
|
env_file:
|
||||||
|
- b.env
|
||||||
|
db:
|
||||||
|
image: awesome/db
|
||||||
|
env_file:
|
||||||
|
- c.env
|
||||||
|
- d.env
|
12
tests/ymls/expose/docker-compose.yml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
frontend:
|
||||||
|
image: awesome/frontend
|
||||||
|
expose:
|
||||||
|
- "27118"
|
||||||
|
backend:
|
||||||
|
image: awesome/backend
|
||||||
|
expose:
|
||||||
|
- "27017"
|
||||||
|
- "27018"
|
14
tests/ymls/profiles/docker-compose.yml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
version: "3.9"
|
||||||
|
services:
|
||||||
|
frontend:
|
||||||
|
image: awesome/frontend
|
||||||
|
profiles: ["frontend"]
|
||||||
|
phpmyadmin:
|
||||||
|
image: phpmyadmin
|
||||||
|
profiles:
|
||||||
|
- debug
|
||||||
|
db:
|
||||||
|
image: awesome/db
|
||||||
|
profiles:
|
||||||
|
- db
|
||||||
|
- sql
|