sysconfig renderer should render DNSx= and GATEWAY= lines

Bug #1705804 reported by rc556677 on 2017-07-22
8
This bug affects 1 person
Affects Status Importance Assigned to Milestone
cloud-init
Medium
Unassigned

Bug Description

cloud-init 0.7.9 on CentOS and Fedora are semi-broken because the sysconfig renderer does not render
DNS1=...
GATEWAY=...

into /etc/sysconfig/network-scripts/ifcfg-eth0. The VM has no default gateway or nameservers.

This is using NoCloud ENI source -> network_config -> network_state -> sysconfig renderer

From this ENI source:
auto eth0
iface eth0 inet static
address 192.168.125.154
netmask 255.255.255.0
gateway 192.168.125.1
dns-nameservers 192.168.125.1 8.8.8.8 8.8.4.4 1.2.3.4
dns-search example.com foo.biz bar.info foobar.toomany

Actual result:
# Created by cloud-init on instance boot automatically, do not edit.
#
BOOTPROTO=static
DEVICE=eth0
IPADDR=192.168.125.154
NETMASK=255.255.255.0
ONBOOT=yes
TYPE=Ethernet
USERCTL=no

Expected result:
# Created by cloud-init on instance boot automatically, do not edit.
#
BOOTPROTO=static
DEVICE=eth0
DNS1=192.168.125.1
DNS2=8.8.8.8
DNS3=8.8.4.4
GATEWAY=192.168.125.1
HELLO=world
IPADDR=192.168.125.154
NETMASK=255.255.255.0
ONBOOT=yes
SEARCH="example.com foo.biz info.bar"
TYPE=Ethernet
USERCTL=no

The network_config object:
{'version': 1, 'config': [{'type': 'physical', 'name': 'eth0', 'subnets': [{'_orig_eni_name': 'eth0', 'type': 'static', 'control': 'auto', 'address': '192.168.125.154', 'netmask': '255.255.255.0', 'gateway': '192.168.125.1', 'dns_nameservers': ['192.168.125.1', '8.8.8.8', '8.8.4.4', '1.2.3.4'], 'dns_search': ['example.com', 'foo.biz', 'bar.info', 'foobar.toomany']}]}]}

The network_state object:

!!python/object:cloudinit.net.network_state.NetworkState
_network_state:
    dns:
        nameservers: []
        search: []
    interfaces:
        eth0:
            address: null
            gateway: null
            inet: inet
            mac_address: null
            mode: manual
            mtu: null
            name: eth0
            subnets:
            - _orig_eni_name: eth0
                address: 192.168.125.154
                control: auto
                dns_nameservers:
                - 192.168.125.1
                - 8.8.8.8
                - 8.8.4.4
                - 1.2.3.4
                dns_search:
                - example.com
                - foo.biz
                - bar.info
                - foobar.toomany
                gateway: 192.168.125.1
                netmask: 255.255.255.0
                type: static
            type: physical
    routes: []
_version: 1

Related branches

rc556677 (rc556677) wrote :

Tested on ubuntu/zesty branch using net-convert.py. Reproduced on Fedora 26 cloud-init 0.7.9 (a few commits behind without netplan)

rc556677 (rc556677) wrote :

Quick-n-dirty hack to get more complete rendered output:
cloudinit/net/sysconfig.py:
    205 @classmethod
    206 def _render_iface_shared(cls, iface, iface_cfg):
    207 print("XXA:", iface, iface_cfg)
    208 for k, v in cls.iface_defaults:
    209 iface_cfg[k] = v
    210
    211 for (old_key, new_key) in [('mac_address', 'HWADDR'), ('mtu', 'MTU')]:
    212 old_value = iface.get(old_key)
    213 if old_value is not None:
    214 iface_cfg[new_key] = old_value
    215
    216 if 'subnets' in iface:
    217 for subnet in iface['subnets']:
    218 if 'dns_search' in subnet:
    219 search_str = ""
    220 for i, k in enumerate(subnet['dns_search']):
    221 if i > 3:
    222 break
    223 if i > 0:
    224 search_str = search_str + " "
    225 search_str = search_str + k
    226 iface_cfg['SEARCH'] = search_str
    227
    228 if 'dns_nameservers' in subnet:
    229 ns_str = ""
    230 for i, k in enumerate(subnet['dns_nameservers']):
    231 if i == 3:
    232 break
    233 iface_cfg['DNS'+str(i+1)] = k
    234
    235 if 'gateway' in subnet:
    236 iface_cfg['GATEWAY'] = subnet['gateway']
    237

rc556677 (rc556677) wrote :

Ouch python indent screwed up, attaching patch instead

rc556677 (rc556677) wrote :

Render DNS1, DNS2, DNS3, SEARCH, GATEWAY lines in sysconfig.py

rc556677 (rc556677) wrote :

Typo: 'SEARCH' key should be replaced by 'DOMAIN'

Joshua Powers (powersj) wrote :

hi rc556677, thanks for taking the time to file a bug!

There have been numerous recent commits trying to get sysconfig and routes working:

IPv6 Networking and Gateway fixes (LP: #1694801, #1701097)
Other networking fixes (LP: #1695092, #1702513)
Numerous CentOS networking commits (LP: #1682014, #1701417, #1686856, #1687725)

Would you be willing to try out one of our nightly builds from a COPR repo to see if this has been fixed?

https://copr.fedorainfracloud.org/coprs/g/cloud-init/cloud-init-dev/

Changed in cloud-init:
status: New → Incomplete
rc556677 (rc556677) wrote :

hi powers,

On Fedora 26 I tested : cloud-init-0.7.9+225.g85c984c-1.fc26.noarch.rpm
TL;DR: GATEWAY is fixed in /network-config v1 and ENI; DNS still not fixed with ENI->sysconfig

Results:
network-config v1->sysconfig - GATEWAY is now rendered correctly from 'gateway' key directly under a 'subnets' entry; I do not have to nest it under a 'routes'

ENI->sysconfig - GATEWAY is now rendered correctly from 'gateway' under 'network-interfaces' in /meta-data

ENI->sysconfig - /etc/resolv.conf is still not rendered correctly because the dns attr in network-state is empty. The conversion from ENI to network_config does not create any 'type': 'nameserver' entries. _ifaces_to_net_config_data() is not creating a 'type': 'nameserver' entry when it sees 'dns'; instead it creates useless 'dns_nameservers' and 'dns_search' entries under subnets and nobody subsequently consumes these keys.

rc556677 (rc556677) wrote :

Correction: 'nobody in sysconfig.py', I see that 'dns_nameservers' / 'dns_search' keys in subnets are used by netplan.py.

rc556677 (rc556677) wrote :

Oh I see: sysconfig.py needs to do the same thing as netplan.py

sysconfig.py is missing this logic:

            if 'dns_nameservers' in subnet:
                nameservers += _listify(subnet.get('dns_nameservers', []))
            if 'dns_search' in subnet:
                searchdomains += _listify(subnet.get('dns_search', []))

etc etc

Scott Moser (smoser) wrote :

Hi, I think there is enough information to work on here. You did a good job filing the bug, thank you.

I'm curious though, what platform you're running on that is passing ENI format. Is it openstack?

Basically, where did you come to this bug? cloud-init reading ENI and rendering sysconfig is kind of a legacy mode that i'm only aware happens in older versions of openstack (without network_data.json).

thanks.

rc556677 (rc556677) wrote :

smoser, :-) we were spinning up atomic hosts (CentOS and Fedora) under oVirt with the NoCloud datasources created by scripts. It generated /meta-data+ENI as the lowest-common denominator. To our surprise none of the Fedora 25/26 instances came up correctly :-(.

Scott Moser (smoser) wrote :

@rc556677,

OK. that makes sense. I understand the least common denominator approach. Hopefully it wont be too long until you can pass either network config (v1 or v2) everywhere.

For older OSes, we do have daily builds that you update images with.
  fedora/redhat: https://copr.fedorainfracloud.org/coprs/g/cloud-init/cloud-init/
  ubuntu: https://code.launchpad.net/~cloud-init-dev/+archive/ubuntu/daily

I understand daily isn't exactly wonderful either.
thanks again for the good bug report.

Changed in cloud-init:
status: Incomplete → Confirmed
importance: Undecided → Medium
Scott Moser (smoser) on 2017-11-21
Changed in cloud-init:
status: Confirmed → Fix Committed

This bug is believed to be fixed in cloud-init in 17.1. If this is still a problem for you, please make a comment and set the state back to New

Thank you.

Changed in cloud-init:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers