Skip to content

Instantly share code, notes, and snippets.

@usbpc
Last active May 1, 2020 20:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save usbpc/0d3c1254cd4e76d569d1ecafac34b2cb to your computer and use it in GitHub Desktop.
Save usbpc/0d3c1254cd4e76d569d1ecafac34b2cb to your computer and use it in GitHub Desktop.
network:
version: 2
renderer: networkd
ethernets:
enp3s0:
addresses:
- @@IP_SUBNET@@
gateway4: @@GATEWAY@@
nameservers:
addresses: [@@DNS@@]
# This is a very simpelistic example file
bind_addr=@@SERVER_ADDR@@
#!/usr/bin/python3
# This script is intended to allow easier rollout of software to multiple servers
# that each have a slightly diffrent configuration. There also need to be
# template configuration files provided, that have placeholders in the places
# where the values need to be inserted. The placeholder will need to have the form
# @@PLACEHOLDER_NAME@@.
# To work it first asks the user for input, then does some light processing on the
# user inputs. After that it copies files while replacing the placeholders. At the
# end it executes some shell commands.
# This is the place where the values the user will be asked for are defined.
# name => internal name for the placeholder
# prompt => the text displayed to the user when asked for this placeholder value
# regex => regex used for validation of user input
# repeated (optional) => indicates, that the user can input multiple values
# break (required if repeated) => regex for what needs to be input during 'repeated'
# values to get to the next prompt
# start (optional, only used if repeated) => string to prepend before any
# repeated values are put into string form
# seperator (optional, only used if repeated) => string to insert between
# repeated values for string form
# end (optional, only used if repeated) => string to append after all
# repeated values are put into string form
placeholders = [
{
'name':'IP_SUBNET',
'prompt':'IPv4 in CIDR notation: ',
'regex':r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}',
},
{
'name':'GATEWAY',
'prompt':'IPv4 of the Default Gateway: ',
'regex':r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
},
{
'name':'DNS',
'prompt':'IPv4 of the DNS Servers, use the empty string to terminate: ',
'regex':r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}',
'repeated': True,
'seperator':',',
'break':r''
}
]
# This is where some light processing for placeholders is defined. It takes a 'src'
# placeholder and writes whatevery is in the first capture group of the 'regex' to
# write into the 'dst' placeholder.
pholders_processing = [
{
'src':'IP_SUBNET',
'dst':'IP',
'regex':r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/\d{1,2}'
}
]
# Here the source and destination for files to be copied is defined.
# You also need to define what placeholders to use in a simple list of strings.
# Additionally to strings tuple pairs can be put in, an example is:
# ('IP', 'SERVER_ADDR') that can be read as 'use the IP placeholder, but for this
# file name it SERVER_ADDR'.
files = [
{
'src':'50-static-ip.yaml_template',
#Normally the destination for this would be set to /etc/netplan/50-static-ip.yaml
'dst':'50-static-ip.yaml',
'placeholders': ['IP_SUBNET', 'GATEWAY', 'DNS']
},
{
'src':'example.conf_template',
'dst':'example.conf',
'placeholders': [('IP', 'SERVER_ADDR')]
}
]
# This defines a list of commands to be ran after everything else was processed.
# The commands will be executed in the order defined here.
post_commands = [
['echo', 'Executed the command!']
]
import re
import subprocess
replacments = dict()
for p in placeholders:
r = re.compile(p['regex'])
repeated = p.get('repeated') and p.get('break') is not None
if repeated:
b = re.compile(p['break'])
l = list()
while True:
prompt = p['prompt']
tmp = input(f'{p.get("prompt")} ')
if r.fullmatch(tmp):
if repeated:
l.append(tmp)
else:
replacments[p['name']] = tmp
break
if repeated and b.fullmatch(tmp):
if p.get('start') is None:
p['start'] = ''
if p.get('seperator') is None:
p['seperator'] = ''
if p.get('end') is None:
p['end'] = ''
tmp = p['start']
first = True
for x in l:
if not first:
tmp += p['seperator']
first = False
tmp += x
tmp += p['end']
replacments[p['name']] = tmp
break
for p in pholders_processing:
if replacments.get(p.get('src')) is not list:
r = re.compile(p['regex'])
m = r.fullmatch(replacments.get(p.get('src')))
if m:
replacments[p.get('dst')] = m.groups()[0]
for file in files:
cur_placeholders = dict()
for x in file.get('placeholders'):
if type(x) is str:
cur_placeholders[x] = replacments.get(x)
elif type(x) is tuple:
cur_placeholders[x[1]] = replacments.get(x[0])
with open(file.get('src'), 'rt') as fi:
with open(file.get('dst'), 'wt') as fo:
tmp = fi.read()
for p, r in cur_placeholders.items():
tmp = tmp.replace(f'@@{p}@@', r)
fo.write(tmp)
print(f"moved '{file.get('src')} to '{file.get('dst')}'")
for cmd in post_commands:
r = subprocess.run(cmd, stdout=subprocess.PIPE)
print(r.stdout.decode('utf-8'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment