cloud-init-dev team mailing list archive
-
cloud-init-dev team
-
Mailing list archive
-
Message #01755
Re: [Merge] ~raharper/cloud-init:rebased-netconfig-v2-passthrough into cloud-init:master
i have some small comments.
don't worry about fixing the 'handle_' comment, but i do worry about the confusion.
Diff comments:
> diff --git a/cloudinit/distros/__init__.py b/cloudinit/distros/__init__.py
> index 803ac74..22ae998 100755
> --- a/cloudinit/distros/__init__.py
> +++ b/cloudinit/distros/__init__.py
> @@ -73,7 +73,7 @@ class Distro(object):
>
> def _supported_write_network_config(self, network_config):
> priority = util.get_cfg_by_path(
> - self._cfg, ('network', 'renderers'), None)
> + self._cfg, ('system_info', 'network', 'renderers'), None)
I'm pretty sure this is wrong.
distro gets as its config the system_info. it does not get access to the full thing. see usage of _cfg via 'get_option' and '_get_arch_package_mirror_info' for my reasoning. I did not test though.
>
> name, render_cls = renderers.select(priority=priority)
> LOG.debug("Selected renderer '%s' from priority list: %s",
> diff --git a/cloudinit/distros/debian.py b/cloudinit/distros/debian.py
> index 1101f02..26267c3 100644
> --- a/cloudinit/distros/debian.py
> +++ b/cloudinit/distros/debian.py
> @@ -75,7 +80,8 @@ class Distro(distros.Distro):
> self.package_command('install', pkgs=pkglist)
>
> def _write_network(self, settings):
> - util.write_file(NETWORK_CONF_FN, settings)
> + # this is always going to be legacy based
# _write_network is legacy, it will always write eni
that sound reasonable?
> + util.write_file(self.network_conf_fn["eni"], settings)
> return ['all']
>
> def _write_network_config(self, netconfig):
> diff --git a/cloudinit/net/network_state.py b/cloudinit/net/network_state.py
> index 90b2835..ba84059 100644
> --- a/cloudinit/net/network_state.py
> +++ b/cloudinit/net/network_state.py
> @@ -103,14 +114,21 @@ class CommandHandlerMeta(type):
>
> class NetworkState(object):
>
> - def __init__(self, network_state, version=NETWORK_STATE_VERSION):
> + def __init__(self, network_state, version=NETWORK_STATE_VERSION,
> + config=None):
I dont understand why NetworkState is now getting a 'config', as it doesnt look like it gets used for anything.
> self._network_state = copy.deepcopy(network_state)
> self._version = version
> + self._config = copy.deepcopy(config)
> + self.use_ipv6 = network_state.get('use_ipv6', False)
>
> @property
> def version(self):
> return self._version
>
> + @property
> + def config(self):
> + return self._config
> +
> def iter_routes(self, filter_func=None):
> for route in self._network_state.get('routes', []):
> if filter_func is not None:
> @@ -407,6 +471,239 @@ class NetworkStateInterpreter(object):
> }
> routes.append(route)
>
> + # V2 handlers
can we name these handle_v2_bonds, handle_v2_ethernets ?....
just looking at this diff, I thought "Why are we adding support now for 'bonds' and 'vlans'?" I'm sure I'll be confused by that again.
i realize that this is a bit involved due to the CommadnHandlerMeta path.. but this is going to get confusing.
> + def handle_bonds(self, command):
> + '''
> + v2_command = {
> + bond0: {
> + 'interfaces': ['interface0', 'interface1'],
> + 'miimon': 100,
> + 'mode': '802.3ad',
> + 'xmit_hash_policy': 'layer3+4'},
> + bond1: {
> + 'bond-slaves': ['interface2', 'interface7'],
> + 'mode': 1
> + }
> + }
> +
> + v1_command = {
> + 'type': 'bond'
> + 'name': 'bond0',
> + 'bond_interfaces': [interface0, interface1],
> + 'params': {
> + 'bond-mode': '802.3ad',
> + 'bond_miimon: 100,
> + 'bond_xmit_hash_policy': 'layer3+4',
> + }
> + }
> +
> + '''
> + self._handle_bond_bridge(command, cmd_type='bond')
> +
> + def handle_bridges(self, command):
> +
> + '''
> + v2_command = {
> + br0: {
> + 'interfaces': ['interface0', 'interface1'],
> + 'fd': 0,
> + 'stp': 'off',
> + 'maxwait': 0,
> + }
> + }
> +
> + v1_command = {
> + 'type': 'bridge'
> + 'name': 'br0',
> + 'bridge_interfaces': [interface0, interface1],
> + 'params': {
> + 'bridge_stp': 'off',
> + 'bridge_fd: 0,
> + 'bridge_maxwait': 0
> + }
> + }
> +
> + '''
> + self._handle_bond_bridge(command, cmd_type='bridge')
> +
> + def handle_ethernets(self, command):
> + '''
> + ethernets:
> + eno1:
> + match:
> + macaddress: 00:11:22:33:44:55
> + wakeonlan: true
> + dhcp4: true
> + dhcp6: false
> + addresses:
> + - 192.168.14.2/24
> + - 2001:1::1/64
> + gateway4: 192.168.14.1
> + gateway6: 2001:1::2
> + nameservers:
> + search: [foo.local, bar.local]
> + addresses: [8.8.8.8, 8.8.4.4]
> + lom:
> + match:
> + driver: ixgbe
> + set-name: lom1
> + dhcp6: true
> + switchports:
> + match:
> + name: enp2*
> + mtu: 1280
> +
> + command = {
> + 'type': 'physical',
> + 'mac_address': 'c0:d6:9f:2c:e8:80',
> + 'name': 'eth0',
> + 'subnets': [
> + {'type': 'dhcp4'}
> + ]
> + }
> + '''
> + for eth, cfg in command.items():
> + phy_cmd = {
> + 'type': 'physical',
> + 'name': cfg.get('set-name', eth),
> + }
> + mac_address = cfg.get('match', {}).get('macaddress', None)
> + if not mac_address:
> + LOG.warning('NetworkState Version2: missing macaddress')
> +
> + for key in ['mtu', 'match', 'wakeonlan']:
> + if key in cfg:
> + phy_cmd.update({key: cfg.get(key)})
> +
> + subnets = self._v2_to_v1_ipcfg(cfg)
> + if len(subnets) > 0:
> + phy_cmd.update({'subnets': subnets})
> +
> + LOG.debug('v2(ethernets) -> v1(physical):\n%s', phy_cmd)
> + self.handle_physical(phy_cmd)
> +
> + def handle_vlans(self, command):
> + '''
> + v2_vlans = {
> + 'eth0.123': {
> + 'id': 123,
> + 'link': 'eth0',
> + 'dhcp4': True,
> + }
> + }
> +
> + v1_command = {
> + 'type': 'vlan',
> + 'name': 'eth0.123',
> + 'vlan_link': 'eth0',
> + 'vlan_id': 123,
> + 'subnets': [{'type': 'dhcp4'}],
> + }
> + '''
> + for vlan, cfg in command.items():
> + vlan_cmd = {
> + 'type': 'vlan',
> + 'name': vlan,
> + 'vlan_id': cfg.get('id'),
> + 'vlan_link': cfg.get('link'),
> + }
> + subnets = self._v2_to_v1_ipcfg(cfg)
> + if len(subnets) > 0:
> + vlan_cmd.update({'subnets': subnets})
> + LOG.debug('v2(vlans) -> v1(vlan):\n%s', vlan_cmd)
> + self.handle_vlan(vlan_cmd)
> +
> + def handle_wifis(self, command):
> + raise NotImplemented('NetworkState V2: Skipping wifi configuration')
> +
> + def _v2_common(self, cfg):
> + LOG.debug('v2_common: handling config:\n%s', cfg)
> + if 'nameservers' in cfg:
> + search = cfg.get('nameservers').get('search', [])
> + dns = cfg.get('nameservers').get('addresses', [])
> + name_cmd = {'type': 'nameserver'}
> + if len(search) > 0:
> + name_cmd.update({'search': search})
> + if len(dns) > 0:
> + name_cmd.update({'addresses': dns})
> + LOG.debug('v2(nameserver) -> v1(nameserver):\n%s', name_cmd)
> + self.handle_nameserver(name_cmd)
> +
> + def _handle_bond_bridge(self, command, cmd_type=None):
> + """Common handler for bond and bridge types"""
> + for item_name, item_cfg in command.items():
> + item_params = dict((key, value) for (key, value) in
> + item_cfg.items() if key not in
> + NETWORK_V2_KEY_FILTER)
> + v1_cmd = {
> + 'type': cmd_type,
> + 'name': item_name,
> + cmd_type + '_interfaces': item_cfg.get('interfaces'),
> + 'params': item_params,
> + }
> + subnets = self._v2_to_v1_ipcfg(item_cfg)
> + if len(subnets) > 0:
> + v1_cmd.update({'subnets': subnets})
> +
> + LOG.debug('v2(%ss) -> v1(%s):\n%s', cmd_type, cmd_type, v1_cmd)
> + self.handle_bridge(v1_cmd)
> +
> + def _v2_to_v1_ipcfg(self, cfg):
> + """Common ipconfig extraction from v2 to v1 subnets array."""
> +
> + subnets = []
> + if 'dhcp4' in cfg:
> + subnets.append({'type': 'dhcp4'})
> + if 'dhcp6' in cfg:
> + self.use_ipv6 = True
> + subnets.append({'type': 'dhcp6'})
> +
> + gateway4 = None
> + gateway6 = None
> + for address in cfg.get('addresses', []):
> + subnet = {
> + 'type': 'static',
> + 'address': address,
> + }
> +
> + routes = []
> + for route in cfg.get('routes', []):
> + route_addr = route.get('to')
> + if "/" in route_addr:
> + route_addr, route_cidr = route_addr.split("/")
> + route_netmask = cidr2mask(route_cidr)
> + subnet_route = {
> + 'address': route_addr,
> + 'netmask': route_netmask,
> + 'gateway': route.get('via')
> + }
> + routes.append(subnet_route)
> + if len(routes) > 0:
> + subnet.update({'routes': routes})
> +
> + if ":" in address:
> + if 'gateway6' in cfg and gateway6 is None:
> + gateway6 = cfg.get('gateway6')
> + subnet.update({'gateway': gateway6})
> + else:
> + if 'gateway4' in cfg and gateway4 is None:
> + gateway4 = cfg.get('gateway4')
> + subnet.update({'gateway': gateway4})
> +
> + subnets.append(subnet)
> + return subnets
> +
> +
> +def subnet_is_ipv6(subnet):
> + """ Common helper for checking network_state subnets for ipv6"""
> + # 'static6' or 'dhcp6'
> + if subnet['type'].endswith('6'):
> + # This is a request for DHCPv6.
> + return True
> + elif subnet['type'] == 'static' and ":" in subnet['address']:
> + return True
> + return False
> +
>
> def cidr2mask(cidr):
> mask = [0, 0, 0, 0]
> diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py
> index 117b515..23ac2e3 100644
> --- a/cloudinit/net/sysconfig.py
> +++ b/cloudinit/net/sysconfig.py
> @@ -390,19 +391,32 @@ class Renderer(renderer.Renderer):
> return contents
>
> def render_network_state(self, network_state, target=None):
> + file_mode = 0o644
> base_sysconf_dir = util.target_path(target, self.sysconf_dir)
> for path, data in self._render_sysconfig(base_sysconf_dir,
> network_state).items():
> - util.write_file(path, data)
> + util.write_file(path, data, file_mode)
> if self.dns_path:
> dns_path = util.target_path(target, self.dns_path)
> resolv_content = self._render_dns(network_state,
> existing_dns_path=dns_path)
> - util.write_file(dns_path, resolv_content)
> + util.write_file(dns_path, resolv_content, file_mode)
> if self.netrules_path:
> netrules_content = self._render_persistent_net(network_state)
> netrules_path = util.target_path(target, self.netrules_path)
> - util.write_file(netrules_path, netrules_content)
> + util.write_file(netrules_path, netrules_content, file_mode)
> +
> + # always write /etc/sysconfig/network configuration
> + sysconfig_path = util.target_path(target, "etc/sysconfig/network")
> + netcfg = [
> + ('# Created by cloud-init on instance boot automatically, '
i think this should be
netcg = _make_header() + ["NETWORKING="yes"]
> + 'do not edit.'),
> + 'NETWORKING=yes',
> + ]
> + if network_state.use_ipv6:
> + netcfg.append('NETWORKING_IPV6=yes')
> + netcfg.append('IPV6_AUTOCONF=no')
> + util.write_file(sysconfig_path, "\n".join(netcfg) + "\n", file_mode)
>
>
> def available(target=None):
--
https://code.launchpad.net/~raharper/cloud-init/+git/cloud-init/+merge/320291
Your team cloud init development team is requested to review the proposed merge of ~raharper/cloud-init:rebased-netconfig-v2-passthrough into cloud-init:master.
References