-
Notifications
You must be signed in to change notification settings - Fork 4
/
Caddyfile.generate
executable file
·115 lines (95 loc) · 3.84 KB
/
Caddyfile.generate
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
#! /usr/bin/env python3
# Copyright (C) 2018 Sebastian Pipping <[email protected]>
# Licensed under GNU Affero GPL v3 or later
import subprocess
import sys
from argparse import ArgumentParser
from configparser import ConfigParser, NoOptionError
from contextlib import suppress
from collections import namedtuple
from tempfile import NamedTemporaryFile
from textwrap import dedent
class CaddyfileGenerator:
Site = namedtuple('Site', [
'alias_domains',
'backend_authority',
'domain',
])
def __init__(self):
self._redir_target_of = {}
self._backend_of = {}
def add(self, site):
self._backend_of[site.domain] = site.backend_authority
for domain in site.alias_domains:
self._redir_target_of[domain] = site.domain
def write_to(self, fp):
print(dedent("""\
# NOTE: This file has been generated, do not edit
(common) {
encode zstd gzip
log {
output stdout
}
}"""), file=fp)
for domain, backend_authority in sorted(self._backend_of.items()):
print(dedent("""
%s {
import common
reverse_proxy %s {
header_down +Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
}
}""") % (domain, backend_authority), file=fp)
for source_domain, target_domain in sorted(
self._redir_target_of.items()):
print(dedent("""
%s {
import common
redir https://%s{uri}
}""") % (source_domain, target_domain), file=fp)
def run(options):
config = ConfigParser()
with open(options.config_filename) as fin:
config.read_file(fin, options.config_filename)
caddyfile = CaddyfileGenerator()
for domain in config.sections():
try:
alias_domains = config.get(domain, 'aliases').split()
except NoOptionError:
alias_domains = []
backend_authority = config.get(domain, 'backend')
site = CaddyfileGenerator.Site(alias_domains, backend_authority,
domain)
caddyfile.add(site)
with NamedTemporaryFile() as temp_file:
# The idea is to diff against previous content or against
# empty file when there is no previos content
with suppress(OSError):
with open(options.output_filename, 'r+b') as fin:
temp_file.file.write(fin.read())
temp_file.file.flush()
with open(options.output_filename, 'w') as fout:
caddyfile.write_to(fout)
exit_code = subprocess.call(['diff', '-u', temp_file.name,
options.output_filename])
# Write stateful output in the format expected by SaltStack
if exit_code and options.saltstack:
print()
print("changed=yes comment='Caddyfile changed'")
if __name__ == '__main__':
parser = ArgumentParser()
parser.add_argument('--config', dest='config_filename', metavar='FILENAME',
default='sites.cfg',
help='Path to config file to read'
' (default: %(default)s)')
parser.add_argument('--output', dest='output_filename', metavar='FILENAME',
default='Caddyfile',
help='Path to write Caddyfile to'
' (default: %(default)s)')
parser.add_argument('--saltstack', action='store_true',
help='Add lines signaling changes to SaltStack'
' (default: omitted)')
options = parser.parse_args()
try:
run(options)
except IOError as e:
sys.exit(e)