Skip to content

Commit

Permalink
Tests and updates for compose generator (#86)
Browse files Browse the repository at this point in the history
  • Loading branch information
svrnm authored Jan 7, 2025
1 parent 9764bfc commit 1ce6645
Show file tree
Hide file tree
Showing 7 changed files with 280 additions and 69 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@
*.vsix
# Ignore local venv environment
.venv
__pycache__
.pytest_cache

# Ignore mac os x .DS_Store files
.DS_Store
2 changes: 1 addition & 1 deletion scripts/generators/docker-compose/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ RUN chown -R appuser:appgroup /app && chmod +x createComposeFile.py
USER appuser

# Define the default entrypoint to run the script
ENTRYPOINT ["python", "createComposeFile.py", "--template", "/app/docker-compose.j2"]
ENTRYPOINT ["python", "createComposeFile.py", "--template", "docker-compose.j2"]
63 changes: 54 additions & 9 deletions scripts/generators/docker-compose/createComposeFile.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,59 @@
import argparse
from deepmerge import always_merger
import inflect
from jinja2 import Environment, FileSystemLoader
import os
import yaml
# Initialize inflect engine
p = inflect.engine()


debug_mode = False

defaultValues = {
"imageNamePrefix": "ghcr.io/cisco-open/",
"imageNameSuffix": "latest",
"defaultPorts": {
"services": 80, # this is different from the "default default" on purpose.
"databases": 5432,
"loaders": 6000 # not used
},
# Keep the default ports for each service type here
# We need them to verify in the docker compose generation if they have been
# changed by the user.
"_defaultDefaultPorts": {
"services": 8080,
"databases": 5432,
"loaders": 6000
}
}

def plural_to_singular(word):
return p.singular_noun(word) or word

def read_yaml(file_path):
with open(os.path.expanduser(file_path), 'r') as file:
# Parse the YAML file
data = yaml.safe_load(file)
return data

def render_compose_file(template, data, defaultValues):
globalVars = data.get('global', {})

config = {
"global": always_merger.merge(defaultValues, globalVars),
"scopes": {
"services": data.get('services', {}),
"databases": data.get('databases', {}),
"loaders": data.get('loaders', {}),
}
}

return template.render(config)

def main():
global debug_mode
global defaultValues
parser = argparse.ArgumentParser(description='Process some configuration file.')
parser.add_argument(
'--config',
Expand Down Expand Up @@ -47,21 +88,25 @@ def main():
if isinstance(yaml_data, dict):
env = Environment(loader=FileSystemLoader('.'))

env.filters['singularize'] = plural_to_singular

template = env.get_template(template_path)

rendered_content = template.render(yaml_data)
rendered_content = render_compose_file(template, data, defaultValues)

with open(output_path, 'w') as output_file:
output_file.write(rendered_content)

else:
raise Exception(f"Failed to read the configuration file {config_file}: The top-level structure is not a dictionary.")

try:
main()
except Exception as e:
if not debug_mode:
print(e)
else:
raise e
exit(1)

if __name__ == "__main__":
try:
main()
except Exception as e:
if not debug_mode:
print(e)
else:
raise e
exit(1)
75 changes: 18 additions & 57 deletions scripts/generators/docker-compose/docker-compose.j2
Original file line number Diff line number Diff line change
@@ -1,72 +1,33 @@
---
{%- set global = global | default({}) -%}
{%- set imageNamePrefix = global.imageNamePrefix | default('ghcr.io/cisco-open/') -%}
{%- set imageNameSuffix = global.imageNameSuffix | default('latest') -%}
{%- set serviceDefaultPort = global.serviceDefaultPort | default(80) -%}
{# Ensure the variable always ends with a slash #}
{%- set imageNamePrefix = imageNamePrefix if imageNamePrefix.endswith('/') else imageNamePrefix + '/' %}
services:
{%- if services is defined and services is mapping %}
## services
{%- for name, details in services.items() %}
{%- for scope, scopeDetails in scopes.items() %}
## {{ scope }}
{%- for name, details in scopeDetails.items() %}
{{ name }}:
image: {{ imageNamePrefix }}app-simulator-services-{{ details.type }}:{{ imageNameSuffix }}
image: {{ global.imageNamePrefix }}app-simulator-{{ scope }}-{{ details.type }}:{{global.imageNameSuffix }}
{%- if details.port is defined %}
ports:
- "{{ details.port }}:8080"
- "{{ details.port }}:{{ global.defaultPorts[scope] }}"
{%- endif %}
{%- if serviceDefaultPort != 8080 %}
{%- if global.defaultPorts is defined -%}
{%- if global.defaultPorts[scope] is defined and global.defaultPorts[scope] != global._defaultDefaultPorts[scope] %}
environment:
SERVICE_DEFAULT_PORT: "{{ serviceDefaultPort }}"
{%- if serviceDefaultPort <= 1024 %}
- {{ scope | singularize | upper }}_DEFAULT_PORT={{ global.defaultPorts[scope] }}
{%- endif %}
{%- if global.defaultPorts[scope] <= 1024 %}
cap_add:
- NET_BIND_SERVICE
{%- endif %}
- NET_BIND_SERVICE
{%- endif %}
{%- endif %}
configs:
- source: service_{{ name | replace("-", "_") }}_config
target: /config.json
{%- endfor %}
{%- endif -%}
{%- if databases is defined and databases is mapping %}
## databases
{%- for name, details in databases.items() %}
{{ name }}:
image: {{ imageNamePrefix }}app-simulator-databases-{{ details.type }}:{{ imageNameSuffix }}
configs:
- source: database_{{ name | replace("-", "_") }}_config
target: /config.json
{%- endfor %}
{%- endif -%}
{%- if loaders is defined and loaders is mapping %}
## loaders
{%- for name, details in loaders.items() %}
{{ name }}:
image: {{ imageNamePrefix }}app-simulator-loaders-{{ details.type }}:{{ imageNameSuffix }}
configs:
- source: loader_{{ name | replace("-", "_") }}_config
- source: {{ scope }}_{{ name | replace("-", "_") | lower }}_config
target: /config.json
{%- endfor %}
{%- endif %}
{%- endfor %}
configs:
{%- if services is defined and services is mapping %}
{%- for name, details in services.items() %}
service_{{ name | replace("-", "_") }}_config:
content: |
{{ details | tojson }}
{%- endfor -%}
{%- endif %}
{%- if databases is defined and databases is mapping %}
{%- for name, details in databases.items() %}
database_{{ name | replace("-", "_") }}_config:
content: |
{{ details | tojson }}
{%- endfor -%}
{%- endif %}
{%- if loaders is defined and loaders is mapping %}
{%- for name, details in loaders.items() %}
loader_{{ name | replace("-", "_") }}_config:
{%- for scope, scopeDetails in scopes.items() %}
{%- for name, details in scopeDetails.items() %}
{{ scope }}_{{ name | replace("-", "_") | lower }}_config:
content: |
{{ details | tojson }}
{%- endfor -%}
{%- endif %}
{%- endfor %}
5 changes: 3 additions & 2 deletions scripts/generators/docker-compose/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
deepmerge==2.0
inflect==7.5.0
Jinja2==3.1.4
opentelemetry-api==1.29.0
opentelemetry-sdk==1.29.0
PyYAML==6.0.2
pytest==8.3.4
Empty file.
Loading

0 comments on commit 1ce6645

Please sign in to comment.