summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cloudinit/distros/photon.py217
-rw-r--r--cloudinit/net/networkd.py51
-rw-r--r--config/cloud.cfg.tmpl12
-rw-r--r--tests/unittests/test_distros/test_netconfig.py41
-rw-r--r--tests/unittests/test_net.py4
5 files changed, 79 insertions, 246 deletions
diff --git a/cloudinit/distros/photon.py b/cloudinit/distros/photon.py
index 8b78f98f..45125be7 100644
--- a/cloudinit/distros/photon.py
+++ b/cloudinit/distros/photon.py
@@ -10,10 +10,8 @@ from cloudinit import subp
from cloudinit import distros
from cloudinit import helpers
from cloudinit import log as logging
-from cloudinit.distros import net_util
from cloudinit.settings import PER_INSTANCE
from cloudinit.distros import rhel_util as rhutil
-from cloudinit.net.network_state import mask_to_net_prefix
from cloudinit.distros.parsers.hostname import HostnameConf
LOG = logging.getLogger(__name__)
@@ -79,9 +77,6 @@ class Distro(distros.Distro):
self.package_command('install', pkgs=pkglist)
def _write_network_config(self, netconfig):
- if isinstance(netconfig, str):
- self._write_network_(netconfig)
- return
return self._supported_write_network_config(netconfig)
def _bring_up_interfaces(self, device_names):
@@ -141,215 +136,3 @@ class Distro(distros.Distro):
def update_package_sources(self):
self._runner.run('update-sources', self.package_command,
['makecache'], freq=PER_INSTANCE)
-
- def _generate_resolv_conf(self):
- resolv_conf_fn = self.resolve_conf_fn
- resolv_templ_fn = 'systemd.resolved.conf'
-
- return resolv_conf_fn, resolv_templ_fn
-
- def _write_network_(self, settings):
- entries = net_util.translate_network(settings)
- LOG.debug('Translated ubuntu style network settings %s into %s',
- settings, entries)
- route_entries = []
- route_entries = translate_routes(settings)
- dev_names = entries.keys()
- nameservers = []
- searchdomains = []
- # Format for systemd
- for (dev, info) in entries.items():
- if 'dns-nameservers' in info:
- nameservers.extend(info['dns-nameservers'])
- if 'dns-search' in info:
- searchdomains.extend(info['dns-search'])
- if dev == 'lo':
- continue
-
- net_fn = self.network_conf_dir + '10-cloud-init-' + dev
- net_fn += '.network'
- dhcp_enabled = 'no'
- if info.get('bootproto') == 'dhcp':
- if (settings.find('inet dhcp') >= 0 and
- settings.find('inet6 dhcp') >= 0):
- dhcp_enabled = 'yes'
- else:
- if info.get('inet6') is True:
- dhcp_enabled = 'ipv6'
- else:
- dhcp_enabled = 'ipv4'
-
- net_cfg = {
- 'Name': dev,
- 'DHCP': dhcp_enabled,
- }
-
- if info.get('hwaddress'):
- net_cfg['MACAddress'] = info.get('hwaddress')
- if info.get('address'):
- net_cfg['Address'] = '%s' % (info.get('address'))
- if info.get('netmask'):
- net_cfg['Address'] += '/%s' % (
- mask_to_net_prefix(info.get('netmask')))
- if info.get('gateway'):
- net_cfg['Gateway'] = info.get('gateway')
- if info.get('dns-nameservers'):
- net_cfg['DNS'] = str(
- tuple(info.get('dns-nameservers'))).replace(',', '')
- if info.get('dns-search'):
- net_cfg['Domains'] = str(
- tuple(info.get('dns-search'))).replace(',', '')
- route_entry = []
- if dev in route_entries:
- route_entry = route_entries[dev]
- route_index = 0
- found = True
- while found:
- route_name = 'routes.' + str(route_index)
- if route_name in route_entries[dev]:
- val = str(tuple(route_entries[dev][route_name]))
- val = val.replace(',', '')
- if val:
- net_cfg[route_name] = val
- else:
- found = False
- route_index += 1
-
- if info.get('auto'):
- self._write_interface_file(net_fn, net_cfg, route_entry)
-
- resolve_data = []
- new_resolve_data = []
- with open(self.resolve_conf_fn, 'r') as rf:
- resolve_data = rf.readlines()
- LOG.debug('Old Resolve Data\n')
- LOG.debug('%s', resolve_data)
- for item in resolve_data:
- if ((nameservers and ('DNS=' in item)) or
- (searchdomains and ('Domains=' in item))):
- continue
- else:
- new_resolve_data.append(item)
-
- new_resolve_data = new_resolve_data + \
- convert_resolv_conf(nameservers, searchdomains)
- LOG.debug('New resolve data\n')
- LOG.debug('%s', new_resolve_data)
- if nameservers or searchdomains:
- util.write_file(self.resolve_conf_fn, ''.join(new_resolve_data))
-
- return dev_names
-
- def _write_interface_file(self, net_fn, net_cfg, route_entry):
- if not net_cfg['Name']:
- return
- content = '[Match]\n'
- content += 'Name=%s\n' % (net_cfg['Name'])
- if 'MACAddress' in net_cfg:
- content += 'MACAddress=%s\n' % (net_cfg['MACAddress'])
- content += '[Network]\n'
-
- if 'DHCP' in net_cfg and net_cfg['DHCP'] in {'yes', 'ipv4', 'ipv6'}:
- content += 'DHCP=%s\n' % (net_cfg['DHCP'])
- else:
- if 'Address' in net_cfg:
- content += 'Address=%s\n' % (net_cfg['Address'])
- if 'Gateway' in net_cfg:
- content += 'Gateway=%s\n' % (net_cfg['Gateway'])
- if 'DHCP' in net_cfg and net_cfg['DHCP'] == 'no':
- content += 'DHCP=%s\n' % (net_cfg['DHCP'])
-
- route_index = 0
- found = True
- if route_entry:
- while found:
- route_name = 'routes.' + str(route_index)
- if route_name in route_entry:
- content += '[Route]\n'
- if len(route_entry[route_name]) != 2:
- continue
- content += 'Gateway=%s\n' % (
- route_entry[route_name][0])
- content += 'Destination=%s\n' % (
- route_entry[route_name][1])
- else:
- found = False
- route_index += 1
-
- util.write_file(net_fn, content)
-
-
-def convert_resolv_conf(nameservers, searchdomains):
- ''' Returns a string formatted for resolv.conf '''
- result = []
- if nameservers:
- nslist = 'DNS='
- for ns in nameservers:
- nslist = nslist + '%s ' % ns
- nslist = nslist + '\n'
- result.append(str(nslist))
- if searchdomains:
- sdlist = 'Domains='
- for sd in searchdomains:
- sdlist = sdlist + '%s ' % sd
- sdlist = sdlist + '\n'
- result.append(str(sdlist))
- return result
-
-
-def translate_routes(settings):
- entries = []
- for line in settings.splitlines():
- line = line.strip()
- if not line or line.startswith('#'):
- continue
- split_up = line.split(None, 1)
- if len(split_up) <= 1:
- continue
- entries.append(split_up)
- consume = {}
- ifaces = []
- for (cmd, args) in entries:
- if cmd == 'iface':
- if consume:
- ifaces.append(consume)
- consume = {}
- consume[cmd] = args
- else:
- consume[cmd] = args
-
- absorb = False
- for (cmd, args) in consume.items():
- if cmd == 'iface':
- absorb = True
- if absorb:
- ifaces.append(consume)
- out_ifaces = {}
- for info in ifaces:
- if 'iface' not in info:
- continue
- iface_details = info['iface'].split(None)
- dev_name = None
- if len(iface_details) >= 1:
- dev = iface_details[0].strip().lower()
- if dev:
- dev_name = dev
- if not dev_name:
- continue
- route_info = {}
- route_index = 0
- found = True
- while found:
- route_name = 'routes.' + str(route_index)
- if route_name in info:
- val = info[route_name].split()
- if val:
- route_info[route_name] = val
- else:
- found = False
- route_index += 1
- if dev_name in out_ifaces:
- out_ifaces[dev_name].update(route_info)
- else:
- out_ifaces[dev_name] = route_info
- return out_ifaces
diff --git a/cloudinit/net/networkd.py b/cloudinit/net/networkd.py
index 71f87995..2dffce59 100644
--- a/cloudinit/net/networkd.py
+++ b/cloudinit/net/networkd.py
@@ -35,6 +35,8 @@ class CfgParser:
for k in self.conf_dict.keys():
if k == sec:
self.conf_dict[k].append(key+'='+str(val))
+ # remove duplicates from list
+ self.conf_dict[k] = list(dict.fromkeys(self.conf_dict[k]))
self.conf_dict[k].sort()
def get_final_conf(self):
@@ -103,19 +105,27 @@ class Renderer(renderer.Renderer):
def parse_routes(self, conf, cfg):
sec = 'Route'
+ route_cfg_map = {
+ 'gateway': 'Gateway',
+ 'network': 'Destination',
+ 'metric': 'Metric',
+ }
+
+ # prefix is derived using netmask by network_state
+ prefix = ''
+ if 'prefix' in conf:
+ prefix = '/' + str(conf['prefix'])
+
for k, v in conf.items():
- if k == 'gateway':
- cfg.update_section(sec, 'Gateway', v)
- elif k == 'network':
- tmp = v
- if 'prefix' in conf:
- tmp += '/' + str(conf['prefix'])
- cfg.update_section(sec, 'Destination', tmp)
- elif k == 'metric':
- cfg.update_section(sec, 'Metric', v)
+ if k not in route_cfg_map:
+ continue
+ if k == 'network':
+ v += prefix
+ cfg.update_section(sec, route_cfg_map[k], v)
def parse_subnets(self, iface, cfg):
dhcp = 'no'
+ sec = 'Network'
for e in iface.get('subnets', []):
t = e['type']
if t == 'dhcp4' or t == 'dhcp':
@@ -131,21 +141,24 @@ class Renderer(renderer.Renderer):
if 'routes' in e and e['routes']:
for i in e['routes']:
self.parse_routes(i, cfg)
- elif 'address' in e:
+ if 'address' in e:
+ subnet_cfg_map = {
+ 'address': 'Address',
+ 'gateway': 'Gateway',
+ 'dns_nameservers': 'DNS',
+ 'dns_search': 'Domains',
+ }
for k, v in e.items():
if k == 'address':
- tmp = v
if 'prefix' in e:
- tmp += '/' + str(e['prefix'])
- cfg.update_section('Address', 'Address', tmp)
+ v += '/' + str(e['prefix'])
+ cfg.update_section('Address', subnet_cfg_map[k], v)
elif k == 'gateway':
- cfg.update_section('Route', 'Gateway', v)
- elif k == 'dns_nameservers':
- cfg.update_section('Network', 'DNS', ' '.join(v))
- elif k == 'dns_search':
- cfg.update_section('Network', 'Domains', ' '.join(v))
+ cfg.update_section('Route', subnet_cfg_map[k], v)
+ elif k == 'dns_nameservers' or k == 'dns_search':
+ cfg.update_section(sec, subnet_cfg_map[k], ' '.join(v))
- cfg.update_section('Network', 'DHCP', dhcp)
+ cfg.update_section(sec, 'DHCP', dhcp)
# This is to accommodate extra keys present in VMware config
def dhcp_domain(self, d, cfg):
diff --git a/config/cloud.cfg.tmpl b/config/cloud.cfg.tmpl
index d6dbb833..cb2a625b 100644
--- a/config/cloud.cfg.tmpl
+++ b/config/cloud.cfg.tmpl
@@ -44,20 +44,12 @@ ssh_pwauth: 0
# This will cause the set+update hostname module to not operate (if true)
preserve_hostname: false
+# If you use datasource_list array, keep array items in a single line.
+# If you use multi line array, ds-identify script won't read array items.
{% if variant.endswith("bsd") %}
# This should not be required, but leave it in place until the real cause of
# not finding -any- datasources is resolved.
datasource_list: ['NoCloud', 'ConfigDrive', 'Azure', 'OpenStack', 'Ec2']
-{% elif variant in ["photon"] %}
-# Datasources to check for cloud-config
-datasource_list: [
- NoCloud,
- ConfigDrive,
- OVF,
- OpenStack,
- VMwareGuestInfo,
- None
- ]
{% endif %}
# Example datasource config
# datasource:
diff --git a/tests/unittests/test_distros/test_netconfig.py b/tests/unittests/test_distros/test_netconfig.py
index 562ee04a..d09e46af 100644
--- a/tests/unittests/test_distros/test_netconfig.py
+++ b/tests/unittests/test_distros/test_netconfig.py
@@ -15,6 +15,7 @@ from cloudinit.tests.helpers import (
FilesystemMockingTestCase, dir2dict)
from cloudinit import subp
from cloudinit import util
+from cloudinit import safeyaml
BASE_NET_CFG = '''
auto lo
@@ -88,6 +89,24 @@ V1_NET_CFG = {'config': [{'name': 'eth0',
'type': 'physical'}],
'version': 1}
+V1_NET_CFG_WITH_DUPS = """\
+# same value in interface specific dns and global dns
+# should produce single entry in network file
+version: 1
+config:
+ - type: physical
+ name: eth0
+ subnets:
+ - type: static
+ address: 192.168.0.102/24
+ dns_nameservers: [1.2.3.4]
+ dns_search: [test.com]
+ interface: eth0
+ - type: nameserver
+ address: [1.2.3.4]
+ search: [test.com]
+"""
+
V1_NET_CFG_OUTPUT = """\
# This file is generated from information provided by the datasource. Changes
# to it will not persist across an instance reboot. To disable cloud-init's
@@ -867,6 +886,28 @@ class TestNetCfgDistroPhoton(TestNetCfgDistroBase):
V2_NET_CFG,
expected_cfgs.copy())
+ def test_photon_network_config_v1_with_duplicates(self):
+ expected = """\
+ [Match]
+ Name=eth0
+ [Network]
+ DHCP=no
+ DNS=1.2.3.4
+ Domains=test.com
+ [Address]
+ Address=192.168.0.102/24"""
+
+ net_cfg = safeyaml.load(V1_NET_CFG_WITH_DUPS)
+
+ expected = self.create_conf_dict(expected.splitlines())
+ expected_cfgs = {
+ self.nwk_file_path('eth0'): expected,
+ }
+
+ self._apply_and_verify(self.distro.apply_network_config,
+ net_cfg,
+ expected_cfgs.copy())
+
def get_mode(path, target=None):
return os.stat(subp.target_path(target, path)).st_mode & 0o777
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index b2ddbf99..1aab51ee 100644
--- a/tests/unittests/test_net.py
+++ b/tests/unittests/test_net.py
@@ -825,10 +825,14 @@ NETWORK_CONFIGS = {
[Match]
Name=eth99
MACAddress=c0:d6:9f:2c:e8:80
+ [Address]
+ Address=192.168.21.3/24
[Network]
DHCP=ipv4
+ Domains=barley.maas sach.maas
Domains=wark.maas
DNS=1.2.3.4 5.6.7.8
+ DNS=8.8.8.8 8.8.4.4
[Route]
Gateway=65.61.151.37
Destination=0.0.0.0/0