-
-
Save paigeadelethompson/0ee36787f13624ca426c7e9853033e39 to your computer and use it in GitHub Desktop.
dockerfile configuration automation / interpolation with Jinja2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
DEBIAN_RELEASE=bookworm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
❯ pwd | |
/home/xps/netcrave-docker-driver/setup | |
❯ tree | |
. | |
├── docker | |
│ ├── haproxy | |
│ │ ├── Dockerfile | |
│ │ └── templates | |
│ │ └── etc | |
│ │ └── haproxy | |
│ │ └── haproxy.cfg.jinja2 | |
│ ├── squid | |
│ │ └── templates | |
│ │ └── etc | |
│ │ └── squid.conf.jinja2 | |
│ └── vyos | |
│ └── templates | |
│ └── etc | |
│ └── boot.config.jinja2 | |
└── docker-compose.yml | |
12 directories, 5 files | |
# docker-compose build haproxy from the CWD |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
haproxy: | |
image: debian | |
networks: | |
netcrave-docker-driver-haproxy: | |
ipv4_address: 192.0.0.26 | |
ipv6_address: 2001:db8:aaaa:aaba:192:0:0:26 | |
logging: | |
driver: "fluentd" | |
options: | |
fluentd-address: 192.0.0.38 | |
build: | |
context: . | |
args: | |
DEBIAN_RELEASE: ${DEBIAN_RELEASE} | |
TEMPLATE_ROOT: ./docker/haproxy/templates | |
dockerfile: ./docker/haproxy/Dockerfile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ARG DEBIAN_RELEASE | |
FROM debian:$DEBIAN_RELEASE | |
ENV DEBIAN_FRONTEND noninteractive | |
RUN apt update | |
RUN apt -y --no-install-recommends install python-is-python3 python3-pip python3-dotenv python3-jinja2 curl | |
ADD .env /opt/conf/.env | |
ARG TEMPLATE_ROOT | |
ADD $TEMPLATE_ROOT /opt/conf/templates | |
RUN <<EOT python | |
from dotenv import load_dotenv; | |
import os, sys; | |
from pathlib import Path | |
import jinja2 | |
from itertools import islice | |
from itertools import chain | |
for index in chain.from_iterable([["{}/{}".format( | |
x, a) for a in z if a.endswith(".jinja2")] for x, y, z in os.walk( | |
"/opt", topdown=True, onerror=None, followlinks=False) if len(z) > 0]): | |
cur_path = Path(next(islice(Path(index).parents, 1))) | |
out_path = Path("/") / Path("/".join(islice(cur_path.parts, 4, None))) | |
print("current path: {}".format(cur_path)) | |
print("output path: {}".format(out_path)) | |
out_path.mkdir(parents = True, exist_ok = True) | |
templateLoader = jinja2.FileSystemLoader(searchpath = cur_path) | |
templateEnv = jinja2.Environment(loader = templateLoader) | |
template_file = Path(list(Path(index).parts).pop()) | |
out_file = Path(template_file.name.replace(".jinja2", "")) | |
print("template file name: {}".format(template_file)) | |
template = templateEnv.get_template(str(template_file)) | |
load_dotenv("/opt/conf/.env") | |
outputText = template.render(os.environ) | |
print("output file name: {}".format(out_file)) | |
print("full output path: {}".format(out_path / out_file)) | |
open(out_path / out_file, 'w+').write(outputText) | |
print("saved") | |
EOT | |
RUN apt -y remove python-is-python3 python3-pip python3-dotenv python3-jinja2 curl | |
RUN apt -y autoremove | |
RUN rm -rf /opt/conf | |
############################################ OK, do whatever you want now | |
RUN apt --option Dpkg::Options::="--force-confold" --no-install-recommends -y install haproxy | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from dotenv import load_dotenv; | |
import os, sys; | |
from pathlib import Path | |
import jinja2 | |
from itertools import islice | |
from itertools import chain | |
for index in chain.from_iterable([["{}/{}".format( | |
x, a) for a in z if a.endswith(".jinja2")] for x, y, z in os.walk( | |
"/opt", topdown=True, onerror=None, followlinks=False) if len(z) > 0]): | |
cur_path = Path(next(islice(Path(index).parents, 1))) | |
out_path = Path("/") / Path("/".join(islice(cur_path.parts, 4, None))) | |
print("current path: {}".format(cur_path)) | |
print("output path: {}".format(out_path)) | |
out_path.mkdir(parents = True, exist_ok = True) | |
templateLoader = jinja2.FileSystemLoader(searchpath = cur_path) | |
templateEnv = jinja2.Environment(loader = templateLoader) | |
template_file = Path(list(Path(index).parts).pop()) | |
out_file = Path(template_file.name.replace(".jinja2", "")) | |
print("template file name: {}".format(template_file)) | |
template = templateEnv.get_template(str(template_file)) | |
load_dotenv("/opt/conf/.env") | |
outputText = template.render(os.environ) | |
print("output file name: {}".format(out_file)) | |
print("full output path: {}".format(out_path / out_file)) | |
open(out_path / out_file, 'w+').write(outputText) | |
print("saved") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
global # bookworm | |
stats socket ipv6@[2001:db8:aaaa:aaba:192:0:0:26]:23 level admin | |
stats socket /run/haproxy/sock mode 666 level admin | |
stats timeout 86400s |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
global # {{ DEBIAN_RELEASE }} | |
stats socket ipv6@[2001:db8:aaaa:aaba:192:0:0:26]:23 level admin | |
stats socket /run/haproxy/sock mode 666 level admin | |
stats timeout 86400s |
I reckon this is close enough to a tail call, with two caveats:
- the lambda function logic has to be more complex to handle a multi-dimensional parameter and return one that is structurally identical, but it can be done.
- This relies on a fixed number of turns
list(itertools.accumulate([lambda x: x + 1] * 32, func = lambda tail, head: head(tail), initial = 1))
-> [1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
...
well, maybe try a mutable map instead of deque
In [29]: calls = collections.deque([lambda x: (x[0] + 1, x[1], x[0] > 2 and calls.append(lambda x: (x[0], None, None)) or None)] * 32)
In [30]: list(itertools.accumulate(calls, func = lambda v, f: f(v), initial = (1, None)))
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
Cell In [30], line 1
----> 1 list(itertools.accumulate(calls, func = lambda v, f: f(v), initial = (1, None)))
RuntimeError: deque mutated during iteration
In [31]:
I guess stacking parameters is an option but it only stacks after every call
calls = collections.deque([lambda x: (x[0] + 1, x[1]((x[0] * 2, lambda x: True)), True)] * 32)
list(itertools.accumulate(calls, func = lambda tail, head: head((tail[0], head)), initial = (1, lambda x: (x[0], x[1]), None)))
[(1, <function __main__.<lambda>(x)>, None),
(2, (3, True, True), True),
(3, (5, True, True), True),
(4, (7, True, True), True),
(5, (9, True, True), True),
(6, (11, True, True), True),
(7, (13, True, True), True),
(8, (15, True, True), True),
(9, (17, True, True), True),
(10, (19, True, True), True),
(11, (21, True, True), True),
(12, (23, True, True), True),
(13, (25, True, True), True),
(14, (27, True, True), True),
(15, (29, True, True), True),
(16, (31, True, True), True),
(17, (33, True, True), True),
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This might come in handy later .. courtesy stack overflow https://stackoverflow.com/questions/6027558/flatten-nested-dictionaries-compressing-keys
This is a pretty boss example, was kinda hoping for something non-recursive but what do you expect coming from stack overflow, https://stackoverflow.com/questions/4151320/efficient-circular-buffer this is probably a better tool for the job.
https://stackoverflow.com/questions/33923/what-is-tail-recursion this talks a little about the advantages of tail recursive optimization and reusing stack frames for subsequent calls, I used to wonder a lot about this actually, and whether it would ever become more common place
https://stackoverflow.com/questions/13591970/does-python-optimize-tail-recursion