Skip to content

Commit 7cd6aa2

Browse files
authored
Add docker compose generator (#72)
1 parent db2b7b4 commit 7cd6aa2

File tree

5 files changed

+164
-0
lines changed

5 files changed

+164
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
docker-compose.yaml
2+
config.yaml
3+
example.yml
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
FROM python:3.14-alpine
2+
3+
WORKDIR /app
4+
5+
RUN apk addgroup -S appgroup && adduser -S appuser -G appgroup
6+
7+
COPY requirements.txt .
8+
RUN pip install --no-cache-dir -r requirements.txt
9+
10+
COPY createComposeFile.py .
11+
12+
COPY docker-compose.j2 .
13+
14+
RUN chown -R appuser:appgroup /app && chmod +x createComposeFile.py
15+
USER appuser
16+
17+
# Define the default entrypoint to run the script
18+
ENTRYPOINT ["python", "createComposeFile.py", "--template", "/app/docker-compose.j2"]
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import argparse
2+
from jinja2 import Environment, FileSystemLoader
3+
import os
4+
import yaml
5+
6+
debug_mode = False
7+
8+
def read_yaml(file_path):
9+
with open(os.path.expanduser(file_path), 'r') as file:
10+
# Parse the YAML file
11+
data = yaml.safe_load(file)
12+
return data
13+
14+
def main():
15+
global debug_mode
16+
parser = argparse.ArgumentParser(description='Process some configuration file.')
17+
parser.add_argument(
18+
'--config',
19+
type=str,
20+
default='config.yaml', # Set your default config file here
21+
help='Path to the configuration file (default: config.yaml)'
22+
)
23+
parser.add_argument(
24+
'--debug',
25+
action='store_true',
26+
help='Enable debug mode'
27+
)
28+
parser.add_argument(
29+
'--template',
30+
type=str,
31+
default='docker-compose.j2',
32+
help='Path to the Jinja2 template file (default: docker-compose.j2)'
33+
)
34+
parser.add_argument(
35+
'--output',
36+
type=str,
37+
default='docker-compose.yaml',
38+
help='Path to the output file (default: docker-compose.yaml)'
39+
)
40+
args = parser.parse_args()
41+
config_path = args.config
42+
debug_mode = args.debug
43+
template_path = args.template
44+
output_path = args.output
45+
46+
yaml_data = read_yaml(config_path)
47+
if isinstance(yaml_data, dict):
48+
env = Environment(loader=FileSystemLoader('.'))
49+
50+
template = env.get_template(template_path)
51+
52+
rendered_content = template.render(yaml_data)
53+
54+
with open(output_path, 'w') as output_file:
55+
output_file.write(rendered_content)
56+
57+
else:
58+
raise Exception(f"Failed to read the configuration file {config_file}: The top-level structure is not a dictionary.")
59+
60+
try:
61+
main()
62+
except Exception as e:
63+
if not debug_mode:
64+
print(e)
65+
else:
66+
raise e
67+
exit(1)
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
---
2+
{%- set global = global | default({}) -%}
3+
{%- set imageNamePrefix = global.imageNamePrefix | default('ghcr.io/cisco-open/') -%}
4+
{%- set imageNameSuffix = global.imageNameSuffix | default('latest') -%}
5+
{%- set serviceDefaultPort = global.serviceDefaultPort | default(80) -%}
6+
{# Ensure the variable always ends with a slash #}
7+
{%- set imageNamePrefix = imageNamePrefix if imageNamePrefix.endswith('/') else imageNamePrefix + '/' %}
8+
services:
9+
{%- if services is defined and services is mapping %}
10+
## services
11+
{%- for name, details in services.items() %}
12+
{{ name }}:
13+
image: {{ imageNamePrefix }}app-simulator-services-{{ details.type }}:{{ imageNameSuffix }}
14+
{%- if details.port is defined %}
15+
ports:
16+
- "{{ details.port }}:8080"
17+
{%- endif %}
18+
{%- if serviceDefaultPort != 8080 %}
19+
environment:
20+
SERVICE_DEFAULT_PORT: "{{ serviceDefaultPort }}"
21+
{%- if serviceDefaultPort <= 1024 %}
22+
cap_add:
23+
- NET_BIND_SERVICE
24+
{%- endif %}
25+
{%- endif %}
26+
configs:
27+
- source: service_{{ name | replace("-", "_") }}_config
28+
target: /config.json
29+
{%- endfor %}
30+
{%- endif -%}
31+
{%- if databases is defined and databases is mapping %}
32+
## databases
33+
{%- for name, details in databases.items() %}
34+
{{ name }}:
35+
image: {{ imageNamePrefix }}app-simulator-databases-{{ details.type }}:{{ imageNameSuffix }}
36+
configs:
37+
- source: database_{{ name | replace("-", "_") }}_config
38+
target: /config.json
39+
{%- endfor %}
40+
{%- endif -%}
41+
{%- if loaders is defined and loaders is mapping %}
42+
## loaders
43+
{%- for name, details in loaders.items() %}
44+
{{ name }}:
45+
image: {{ imageNamePrefix }}app-simulator-loaders-{{ details.type }}:{{ imageNameSuffix }}
46+
configs:
47+
- source: loader_{{ name | replace("-", "_") }}_config
48+
target: /config.json
49+
{%- endfor %}
50+
{%- endif %}
51+
configs:
52+
{%- if services is defined and services is mapping %}
53+
{%- for name, details in services.items() %}
54+
service_{{ name | replace("-", "_") }}_config:
55+
content: |
56+
{{ details | tojson }}
57+
{%- endfor -%}
58+
{%- endif %}
59+
{%- if databases is defined and databases is mapping %}
60+
{%- for name, details in databases.items() %}
61+
database_{{ name | replace("-", "_") }}_config:
62+
content: |
63+
{{ details | tojson }}
64+
{%- endfor -%}
65+
{%- endif %}
66+
{%- if loaders is defined and loaders is mapping %}
67+
{%- for name, details in loaders.items() %}
68+
loader_{{ name | replace("-", "_") }}_config:
69+
content: |
70+
{{ details | tojson }}
71+
{%- endfor -%}
72+
{%- endif %}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Jinja2==3.1.4
2+
opentelemetry-api==1.29.0
3+
opentelemetry-sdk==1.29.0
4+
PyYAML==6.0.2

0 commit comments

Comments
 (0)