Repository navigation
Expand file tree
/
Copy pathdockercompose.py
More file actions
134 lines (120 loc) · 4.84 KB
/
Copy pathdockercompose.py
File metadata and controls
134 lines (120 loc) · 4.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
"""deployment-configuration/compose/ is a parallel Helm chart (its own
Chart.yaml/values.yaml/templates/), rendered through the real `helm` binary
used purely as a Go-template engine - `helm template` never talks to a
cluster here. Everything about which apps/images/values go into it is
identical to the real Helm chart (CHProject.build_final_helm_values()).
"""
import logging
import shutil
import subprocess
from pathlib import Path
from .helm import CHHelmChart
from .model import CHAppInstance, CHValues, register_file
from .utils import ( # type: ignore
_merge_base_chain,
collect_and_merge_env_specific_files,
get_yaml_parser,
)
logger = logging.getLogger(__name__)
def _merge_helper_templates(
app, destination: Path, templates_dir_of=lambda a: a.path / "deploy" / "templates"
) -> None:
if app.base is not None:
_merge_helper_templates(app.base, destination, templates_dir_of)
templates_dir = templates_dir_of(app)
if not templates_dir.exists():
return
destination.mkdir(parents=True, exist_ok=True)
for helper in templates_dir.glob("_*.tpl"):
dest_file = destination / helper.name
if not dest_file.exists():
shutil.copy(helper, dest_file)
@register_file(
"docker_compose",
lambda root: root / "deployment-configuration" / "compose" / "Chart.yaml",
)
class CHDockerCompose(CHHelmChart):
def generate(self) -> None:
project = self.project
dest = Path(project.config.output_path) / "compose"
shutil.rmtree(dest, ignore_errors=True)
_merge_base_chain(
project, lambda p: p.root / "deployment-configuration" / "compose", dest
)
self.write(dest)
for app in project.involved_apps:
if isinstance(app, str):
continue
if isinstance(app, CHAppInstance):
self._collect_instance_deploy_directories(app, dest)
continue
_merge_base_chain(
app,
lambda a: a.path / "deploy" / "templates-compose",
dest / "templates" / app.name,
)
_merge_helper_templates(app, dest / "templates" / app.name)
_merge_base_chain(
app,
lambda a: a.path / "deploy" / "resources",
dest / "resources" / app.name,
)
collect_and_merge_env_specific_files(dest, project.config.envs)
values = project.build_final_helm_values(write_on_disk=False).to_dict()
CHValues.write_on_disk(dest / "values.yaml", values)
CHValues.write_on_disk(dest / "allvalues.yaml", self._secrets_stripped(values))
self._render(dest)
def _collect_instance_deploy_directories(self, instance: CHAppInstance, dest: Path) -> None:
parent, own = instance.parent_app, instance.instance_name
destination = dest / "templates" / instance.name
_merge_base_chain(
parent, lambda a: a.path / "deploy" / "templates-compose", destination
)
_merge_helper_templates(parent, destination)
_merge_base_chain(
parent,
lambda a, own=own: a.path / "deploy" / "instances" / own / "templates-compose",
destination,
)
_merge_helper_templates(
parent,
destination,
lambda a, own=own: a.path / "deploy" / "instances" / own / "templates",
)
_merge_base_chain(
parent, lambda a: a.path / "deploy" / "resources", dest / "resources" / instance.name
)
_merge_base_chain(
parent,
lambda a, own=own: a.path / "deploy" / "instances" / own / "resources",
dest / "resources" / instance.name,
)
def _secrets_stripped(self, values: dict) -> dict:
apps = {
name: {**app, "harness": {**app["harness"], "secrets": {}}}
for name, app in values["apps"].items()
}
return {**values, "apps": apps}
def _render(self, dest: Path) -> None:
rendered = subprocess.run(
["helm", "template", str(dest)],
check=True,
capture_output=True,
text=True,
).stdout
yaml = get_yaml_parser()
main_document = None
for document in yaml.load_all(rendered):
if not document:
continue
metadata = document.get("cloudharness-metadata")
if metadata:
embedded_path = dest / metadata["path"]
embedded_path.parent.mkdir(parents=True, exist_ok=True)
embedded_path.write_text(document["data"])
else:
main_document = document
compose_path = dest.parent.parent / "docker-compose.yaml"
with compose_path.open("w", encoding="utf-8") as f:
yaml.dump(main_document, f)
logger.info("Wrote %s", compose_path)