VMware-Photon-OS/installer/networkmanager.py

200 lines
6.9 KiB
Python

#
# (c) 2019 VMware Inc.,
#
# Date: Fri Aug 30 11:28:18 IST 2019
# Author: Siddharth Chandrasekaran <csiddharth@vmware.com>
import os
import subprocess
import shutil
class NetworkManager():
TEMPLATE_NET_DHCP = (
'[Match]\n'
'Name=e*\n'
'\n'
'[Network]\n'
'DHCP=yes\n'
'IPv6AcceptRA=no\n'
)
TEMPLATE_NET_STATIC = (
"[Match]\n"
"Name=eth0\n"
"\n"
"[Network]\n"
"Address=@IP_ADDR@\n"
"Gateway=@GATEWAY@\n"
"DNS=@DNS@\n"
)
TEMPLATE_NET_DHCP_HOSTNAME = (
"\n"
"[DHCP]\n"
"SendHostname=True\n"
"Hostname=@HOSTNAME@\n"
)
TEMPLATE_NET_VLAN_NETDEV = (
'[NetDev]\n'
'Name=eth0.@VLAN_NO@\n'
'Kind=vlan\n'
'\n'
'[VLAN]\n'
'Id=@VLAN_NO@\n'
)
TEMPLATE_NET_VLAN_NETWORK = (
'[Match]\n'
'Name=eth0.@VLAN_NO@\n'
'\n'
'[Network]\n'
'DHCP=yes\n'
'IPv6AcceptRA=no\n'
)
def __init__(self, install_config, photon_root='/'):
self.photon_root = photon_root
self.install_config = install_config
self.conf_dir = os.path.join(self.photon_root, 'etc/systemd/network')
# Get contents of default dhcp config.
filename = '/etc/systemd/network/99-dhcp-en.network'
if os.path.exists(filename):
with open(filename, 'r') as f:
self.TEMPLATE_NET_DHCP = f.read()
self.TEMPLATE_NET_DHCP += '\n\n'
# Remove existing configs (if any)
for filename in os.listdir(self.conf_dir):
self.rm_f(os.path.join(self.conf_dir, filename))
def rm_f(self, filename):
if os.path.isfile(filename):
os.remove(filename)
def clean_conf_files(self):
if 'conf_files' not in self.install_config['network']:
return
for filename in self.install_config['network']['conf_files']:
self.rm_f(filename)
self.install_config['network']['conf_files'] = []
def netmask_to_cidr(self, netmask):
# param: netmask ip addr (eg: 255.255.255.0)
# return: equivalent cidr number to given netmask ip (eg: 24)
return sum([bin(int(x)).count('1') for x in netmask.split('.')])
def exec_cmd(self, cmd):
process = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, shell=True)
retval = process.wait()
if retval != 0:
return False
return True
def restart_networkd(self):
if not self.exec_cmd('systemctl restart systemd-networkd'):
raise Exception('Failed to restart networkd')
def setup_network(self):
if 'type' not in self.install_config['network']:
return False
if self.install_config['network']['type'] == 'dhcp':
return self.setup_network_dhcp()
elif self.install_config['network']['type'] == 'static':
return self.setup_network_static()
elif self.install_config['network']['type'] == 'vlan':
return self.setup_network_vlan()
return False
def setup_network_dhcp(self):
self.install_config['network']['type'] = 'dhcp'
self.install_config['network']['conf_files'] = []
hostname = self.install_config['network'].get('hostname', None)
filename = os.path.join(self.conf_dir, '99-dhcp-en.network')
with open(filename, 'w') as f:
f.write(self.TEMPLATE_NET_DHCP)
if hostname is not None:
f.write(self.TEMPLATE_NET_DHCP_HOSTNAME.replace('@HOSTNAME@', hostname))
self.install_config['network']['conf_files'].append(filename)
# Add a hosts entry
if hostname is not None:
hosts_file = os.path.join(self.photon_root, '/etc/hosts')
with open(hosts_file, 'a') as f:
f.write('\n127.0.0.1 {}\n'.format(hostname))
return True
def setup_network_static(self):
if ('ip_addr' not in self.install_config['network'] or
'netmask' not in self.install_config['network'] or
'gateway' not in self.install_config['network'] or
'nameserver' not in self.install_config['network']):
return False
self.install_config['network']['type'] = 'static'
self.install_config['network']['conf_files'] = []
if ('/' not in self.install_config['network']['ip_addr'] and
'netmask' in self.install_config['network']):
cidr = self.netmask_to_cidr(self.install_config['network']['netmask'])
self.install_config['network']['ip_addr'] += '/' + str(cidr)
self.install_config['network'].pop('netmask')
s = self.TEMPLATE_NET_STATIC
s = s.replace('@IP_ADDR@', self.install_config['network']['ip_addr'])
s = s.replace('@GATEWAY@', self.install_config['network']['gateway'])
s = s.replace('@DNS@', self.install_config['network']['nameserver'])
filename = os.path.join(self.conf_dir, '99-static-en.network')
with open(filename, 'w') as f:
f.write(s)
self.install_config['network']['conf_files'].append(filename)
return True
def setup_network_vlan(self):
if 'vlan_id' not in self.install_config['network']:
return False
self.install_config['network']['type'] = 'vlan'
self.install_config['network']['conf_files'] = []
vlan = self.install_config['network']['vlan_id']
filename = os.path.join(self.conf_dir, '99-dhcp-en.network')
with open(filename, 'w') as f:
f.write(self.TEMPLATE_NET_DHCP)
f.write('VLAN=eth0.{}\n'.format(str(vlan)))
self.install_config['network']['conf_files'].append(filename)
filename = '99-dhcp-en.vlan_' + vlan + '.netdev'
filename = os.path.join(self.conf_dir, filename)
with open(filename, 'w') as f:
f.write(self.TEMPLATE_NET_VLAN_NETDEV.replace('@VLAN_NO@', str(vlan)))
self.install_config['network']['conf_files'].append(filename)
filename = '99-dhcp-en.vlan_' + vlan + '.network'
filename = os.path.join(self.conf_dir, filename)
with open(filename, 'w') as f:
f.write(self.TEMPLATE_NET_VLAN_NETWORK.replace('@VLAN_NO@', str(vlan)))
self.install_config['network']['conf_files'].append(filename)
return True
def teardown_network_config(self):
self.clean_conf_files()
self.install_config['network'].pop('type', None)
# clean the hosts file entry
if 'hostname' in self.install_config['network']:
hosts_file = os.path.join(self.photon_root, '/etc/hosts')
with open(hosts_file, 'r') as f:
lines = f.readlines()
with open(hosts_file, 'w') as f:
for line in lines:
if self.install_config['network']['hostname'] not in line:
f.write(line)
self.install_config['network'].pop('hostname', None)