Coverage for archdocs/features/kubernetes/renderer.py: 100%
42 statements
« prev ^ index » next coverage.py v7.15.3, created at 2026-08-03 00:00 +0000
« prev ^ index » next coverage.py v7.15.3, created at 2026-08-03 00:00 +0000
1import typing
3from archdocs import diagram_model
4from archdocs.features.kubernetes import const
7_INGRESS_ENTRYPOINT_LABEL: typing.Final = "Ingress"
8_SECURE_SCHEME: typing.Final = "HTTPS"
9_PLAIN_SCHEME: typing.Final = "HTTP"
10_PERSISTENT_VOLUME_NODE: typing.Final = diagram_model.build_diagram_node(
11 "PersistentVolume",
12 "Persistent volume",
13 diagram_model.NodeGroup.data_stores,
14)
17def _render_amounts(resource_name: str, amounts_to_draw: const.ResourceAmounts, /) -> str:
18 if not amounts_to_draw.requested_amount:
19 return f"{resource_name} up to {amounts_to_draw.limited_amount}" if amounts_to_draw.limited_amount else ""
20 if amounts_to_draw.limited_amount in {"", amounts_to_draw.requested_amount}:
21 return f"{resource_name} {amounts_to_draw.requested_amount}"
22 return f"{resource_name} {amounts_to_draw.requested_amount}-{amounts_to_draw.limited_amount}"
25def render_kubernetes_node_annotations(features_to_draw: const.KubernetesFeatures) -> tuple[str, ...]:
26 scaling_to_draw: typing.Final = features_to_draw.scaling_features
27 resources_to_draw: typing.Final = features_to_draw.resource_features
28 return tuple(
29 filter(
30 None,
31 (
32 "" if scaling_to_draw.workload_kind == const.DEFAULT_WORKLOAD_KIND else scaling_to_draw.workload_kind,
33 f"replicas {scaling_to_draw.replica_count}" if scaling_to_draw.replica_count else "",
34 f"HPA {scaling_to_draw.min_replicas}-{scaling_to_draw.max_replicas}"
35 if scaling_to_draw.max_replicas
36 else "",
37 f"target CPU {scaling_to_draw.target_cpu_utilization}%"
38 if scaling_to_draw.target_cpu_utilization
39 else "",
40 _render_amounts("cpu", resources_to_draw.cpu_amounts),
41 _render_amounts("RAM", resources_to_draw.memory_amounts),
42 _render_amounts("GPU", resources_to_draw.gpu_amounts),
43 ),
44 ),
45 )
48def _render_entrypoint_label(traffic_to_draw: const.TrafficFeatures, /) -> str:
49 if traffic_to_draw.ingress_enabled:
50 return _INGRESS_ENTRYPOINT_LABEL
51 if traffic_to_draw.service_type not in const.EXPOSED_SERVICE_TYPES:
52 return ""
53 if not traffic_to_draw.service_port:
54 return traffic_to_draw.service_type
55 return f"{traffic_to_draw.service_type}, port {traffic_to_draw.service_port}"
58def _render_traffic_edges(
59 service_node: diagram_model.DiagramNode,
60 traffic_to_draw: const.TrafficFeatures,
61 /,
62) -> tuple[diagram_model.DiagramEdge, ...]:
63 if traffic_to_draw.ingress_enabled and traffic_to_draw.ingress_hosts:
64 ingress_scheme: typing.Final = _SECURE_SCHEME if traffic_to_draw.ingress_tls_enabled else _PLAIN_SCHEME
65 return tuple(
66 diagram_model.DiagramEdge(
67 source_node=diagram_model.EXTERNAL_CLIENT_NODE,
68 target_node=service_node,
69 edge_label=f"{ingress_scheme} {one_ingress_host}",
70 )
71 for one_ingress_host in traffic_to_draw.ingress_hosts
72 )
73 entrypoint_label: typing.Final = _render_entrypoint_label(traffic_to_draw)
74 if not entrypoint_label:
75 return ()
76 return (
77 diagram_model.DiagramEdge(
78 source_node=diagram_model.EXTERNAL_CLIENT_NODE,
79 target_node=service_node,
80 edge_label=entrypoint_label,
81 ),
82 )
85def _render_configuration_edges(
86 service_node: diagram_model.DiagramNode,
87 all_configuration_sources: tuple[const.ConfigurationSource, ...],
88 /,
89) -> tuple[diagram_model.DiagramEdge, ...]:
90 return tuple(
91 diagram_model.DiagramEdge(
92 source_node=diagram_model.build_diagram_node(
93 f"{one_source.source_kind} {one_source.source_name}",
94 f"{one_source.source_name} ({one_source.source_kind})",
95 diagram_model.NodeGroup.configuration,
96 ),
97 target_node=service_node,
98 edge_label=one_source.attachment_kind,
99 )
100 for one_source in all_configuration_sources
101 )
104def _render_storage_edges(
105 service_node: diagram_model.DiagramNode,
106 resources_to_draw: const.ResourceFeatures,
107 /,
108) -> tuple[diagram_model.DiagramEdge, ...]:
109 if not resources_to_draw.persistence_enabled:
110 return ()
111 storage_label: typing.Final = " ".join(
112 filter(None, (const.VOLUME_ATTACHMENT, resources_to_draw.persistence_size)),
113 )
114 return (
115 diagram_model.DiagramEdge(
116 source_node=service_node,
117 target_node=_PERSISTENT_VOLUME_NODE,
118 edge_label=storage_label,
119 ),
120 )
123def render_kubernetes_features(
124 service_node: diagram_model.DiagramNode,
125 features_to_draw: const.KubernetesFeatures,
126 /,
127) -> tuple[diagram_model.DiagramEdge, ...]:
128 return (
129 *_render_traffic_edges(service_node, features_to_draw.traffic_features),
130 *_render_configuration_edges(service_node, features_to_draw.configuration_sources),
131 *_render_storage_edges(service_node, features_to_draw.resource_features),
132 )