137 lines
4.1 KiB
Python
Executable file
137 lines
4.1 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
from json import load
|
|
from os import environ
|
|
from os.path import join
|
|
from sys import argv, exit
|
|
from tempfile import gettempdir
|
|
|
|
from mako.template import Template
|
|
|
|
from bundlewrap.repo import Repository
|
|
from bundlewrap.utils.text import bold
|
|
from bundlewrap.utils.ui import io
|
|
|
|
NTP_SERVERS = {
|
|
# pool.ntp.org
|
|
'148.251.54.81',
|
|
'162.159.200.123',
|
|
'213.209.109.44',
|
|
'54.36.110.36',
|
|
}
|
|
|
|
try:
|
|
node_name = argv[1]
|
|
except Exception:
|
|
print(f'Usage: {argv[0]} <node name>')
|
|
exit(1)
|
|
|
|
path = environ.get('BW_REPO_PATH', '.')
|
|
repo = Repository(path)
|
|
node = repo.get_node(node_name)
|
|
|
|
try:
|
|
io.activate()
|
|
|
|
interfaces = {}
|
|
users = {}
|
|
vlans = {
|
|
'default': {
|
|
'id': None,
|
|
'ip_address': '169.254.254.254/24',
|
|
},
|
|
}
|
|
|
|
tmpfile = join(gettempdir(), f'{node.name}.conf')
|
|
|
|
gw_split = node.hostname.split('.')
|
|
gw_split[3] = '1'
|
|
gateway = '.'.join(gw_split)
|
|
|
|
with io.job('reading netbox_dump.json'):
|
|
with open(join(repo.path, 'netbox_dump.json'), 'r') as f:
|
|
json = load(f)[node.metadata.get('location')]
|
|
|
|
for vlan, vid in json['vlans'].items():
|
|
vlans[vlan] = {
|
|
'id': vid,
|
|
'ip_address': None,
|
|
}
|
|
|
|
for iface, iconfig in json['devices'][node.name].items():
|
|
if iface in vlans:
|
|
# If the interface name is the same as a vlan name, this
|
|
# means the ip assigned to this interface should get
|
|
# assigned to that vlan.
|
|
vlans[iface]['ip_address'] = iconfig['ip_addresses'][0]
|
|
else:
|
|
interfaces[iface] = {
|
|
'enabled': bool(
|
|
iconfig['enabled']
|
|
and iconfig['mode']
|
|
and (
|
|
iconfig['vlans']['tagged']
|
|
or iconfig['vlans']['untagged']
|
|
)
|
|
),
|
|
'description': iconfig['description'],
|
|
'untagged_vlan': iconfig['vlans']['untagged'],
|
|
}
|
|
|
|
if iconfig['mode'] and iconfig['mode'].startswith('tagged'):
|
|
interfaces[iface]['mode'] = 'trunk'
|
|
else:
|
|
interfaces[iface]['mode'] = 'access'
|
|
|
|
tagged_vlans = set()
|
|
for vlan in iconfig['vlans']['tagged']:
|
|
tagged_vlans.add(str(vlans[vlan]['id']))
|
|
interfaces[iface]['tagged_vlans'] = tagged_vlans
|
|
|
|
with io.job('reading users.json'):
|
|
with open(join(repo.path, 'users.json'), 'r') as f:
|
|
json = load(f)
|
|
|
|
users = {}
|
|
for uname, config in json.items():
|
|
if config.get('is_admin', False):
|
|
users[uname] = {
|
|
'password': repo.vault.password_for(f'{node.name} {uname} login'),
|
|
'ssh_pubkey': set(config['ssh_pubkey']),
|
|
}
|
|
|
|
|
|
with io.job(f'{bold(node.name)} rendering config template to {tmpfile}'):
|
|
with open(join(repo.path, 'configs', 'junos-template.conf')) as f:
|
|
template = Template(
|
|
f.read().encode('utf-8'),
|
|
input_encoding='utf-8',
|
|
output_encoding='utf-8',
|
|
)
|
|
content = template.render(
|
|
gateway=gateway,
|
|
interfaces=interfaces,
|
|
node=node,
|
|
ntp_servers=NTP_SERVERS,
|
|
repo=repo,
|
|
users=users,
|
|
vlans=vlans,
|
|
)
|
|
with open(tmpfile, 'w+') as f:
|
|
f.write(content.decode('utf-8'))
|
|
|
|
with io.job(f'{bold(node.name)} updating configuration on device'):
|
|
node.upload(tmpfile, '/tmp/bundlewrap.conf')
|
|
|
|
result = node.run(
|
|
'configure exclusive ; load override /tmp/bundlewrap.conf ; commit',
|
|
log_output=True,
|
|
)
|
|
|
|
if 'commit complete' in result.stdout.decode():
|
|
node.run(
|
|
'request system configuration rescue save',
|
|
log_output=True,
|
|
)
|
|
finally:
|
|
io.deactivate()
|