import glob
import os
import re
import shutil
import sys
ASSIGNED_PORTS_GLOB = "/opt/vade/apps/*/active-deployment/assigned-ports"
FIRST_PORT = 8000
NAMED_PORT_RE = re.compile(r'{{ port\("([^"]+)"\) }}')
def read_ports(path):
try:
with open(path) as f:
return [int(line) for line in f if line.strip()]
except FileNotFoundError:
return []
def gather_taken_ports():
taken = set()
for path in glob.glob(ASSIGNED_PORTS_GLOB):
taken.update(read_ports(path))
return taken
def gather_named_ports(templated_files):
names = set()
for path in templated_files:
with open(path) as f:
content = f.read()
names.update(NAMED_PORT_RE.findall(content))
return sorted(names)
def choose_ports(reserve_count, active_ports, taken):
if len(active_ports) == reserve_count:
return active_ports
chosen = []
port = FIRST_PORT
while len(chosen) < reserve_count:
if port not in taken:
chosen.append(port)
port += 1
return chosen
def substitute_placeholders(text, ports):
for name, port in ports:
text = text.replace('{{ port("' + name + '") }}', str(port))
return text
def main():
active_ports_file = sys.argv[1]
candidate_dir = sys.argv[2]
app_user = sys.argv[3]
templated_files = sys.argv[4:]
port_names = gather_named_ports(templated_files)
ports = choose_ports(
len(port_names),
read_ports(active_ports_file),
gather_taken_ports(),
)
candidate_ports_file = os.path.join(candidate_dir, "assigned-ports")
with open(candidate_ports_file, "w") as f:
for port in ports:
f.write(str(port) + "\n")
shutil.chown(candidate_ports_file, app_user, app_user)
os.chmod(candidate_ports_file, 0o644)
for path in templated_files:
with open(path) as f:
content = f.read()
with open(path, "w") as f:
f.write(substitute_placeholders(content, zip(port_names, ports)))
if __name__ == "__main__":
main()