From 7deec7b6a1fce87dc2d9cd886053804bbc70380e Mon Sep 17 00:00:00 2001 From: Akihiko Ota Date: Tue, 20 Mar 2018 11:41:26 -0600 Subject: OpenNebula: Update network to return v2 config rather than ENI. OpenNebulaNetwork.gen_conf() was previously returning ENI format. This is updated to return netplan/v2 config. The changes here also adds support for IPv6 configuration distributed from OpenNebula and fixes some issues about nameserver information. --- cloudinit/sources/DataSourceOpenNebula.py | 104 +++++++++++++++++++++--------- 1 file changed, 74 insertions(+), 30 deletions(-) (limited to 'cloudinit/sources') diff --git a/cloudinit/sources/DataSourceOpenNebula.py b/cloudinit/sources/DataSourceOpenNebula.py index 9450835e..02cb98f7 100644 --- a/cloudinit/sources/DataSourceOpenNebula.py +++ b/cloudinit/sources/DataSourceOpenNebula.py @@ -20,7 +20,6 @@ import string from cloudinit import log as logging from cloudinit import net -from cloudinit.net import eni from cloudinit import sources from cloudinit import util @@ -91,15 +90,15 @@ class DataSourceOpenNebula(sources.DataSource): return False self.seed = seed - self.network_eni = results.get('network-interfaces') + self.network = results.get('network-interfaces') self.metadata = md self.userdata_raw = results.get('userdata') return True @property def network_config(self): - if self.network_eni is not None: - return eni.convert_eni_data(self.network_eni) + if self.network is not None: + return self.network else: return None @@ -143,18 +142,42 @@ class OpenNebulaNetwork(object): def mac2network(self, mac): return self.mac2ip(mac).rpartition(".")[0] + ".0" - def get_dns(self, dev): - return self.get_field(dev, "dns", "").split() + def get_nameservers(self, dev): + nameservers = {} + dns = self.get_field(dev, "dns", "").split() + dns.extend(self.context.get('DNS', "").split()) + if dns: + nameservers['addresses'] = dns + search_domain = self.get_field(dev, "search_domain", "").split() + if search_domain: + nameservers['search'] = search_domain + return nameservers - def get_domain(self, dev): - return self.get_field(dev, "domain") + def get_mtu(self, dev): + return self.get_field(dev, "mtu") def get_ip(self, dev, mac): return self.get_field(dev, "ip", self.mac2ip(mac)) + def get_ip6(self, dev): + addresses6 = [] + ip6 = self.get_field(dev, "ip6") + if ip6: + addresses6.append(ip6) + ip6_ula = self.get_field(dev, "ip6_ula") + if ip6_ula: + addresses6.append(ip6_ula) + return addresses6 + + def get_ip6_prefix(self, dev): + return self.get_field(dev, "ip6_prefix_length", "64") + def get_gateway(self, dev): return self.get_field(dev, "gateway") + def get_gateway6(self, dev): + return self.get_field(dev, "gateway6") + def get_mask(self, dev): return self.get_field(dev, "mask", "255.255.255.0") @@ -171,10 +194,11 @@ class OpenNebulaNetwork(object): return default if val in (None, "") else val def gen_conf(self): - global_dns = self.context.get('DNS', "").split() - - conf = ['auto lo', 'iface lo inet loopback', ''] + netconf = {} + netconf['version'] = 2 + netconf['ethernets'] = {} + ethernets = {} for mac, dev in self.ifaces.items(): mac = mac.lower() @@ -182,29 +206,49 @@ class OpenNebulaNetwork(object): # dev stores the current system name. c_dev = self.context_devname.get(mac, dev) - conf.append('auto ' + dev) - conf.append('iface ' + dev + ' inet static') - conf.append(' #hwaddress %s' % mac) - conf.append(' address ' + self.get_ip(c_dev, mac)) - conf.append(' network ' + self.get_network(c_dev, mac)) - conf.append(' netmask ' + self.get_mask(c_dev)) + devconf = {} + + # Set MAC address + devconf['match'] = {'macaddress': mac} + # Set IPv4 address + devconf['addresses'] = [] + mask = self.get_mask(c_dev) + prefix = str(net.mask_to_net_prefix(mask)) + devconf['addresses'].append( + self.get_ip(c_dev, mac) + '/' + prefix) + + # Set IPv6 Global and ULA address + addresses6 = self.get_ip6(c_dev) + if addresses6: + prefix6 = self.get_ip6_prefix(c_dev) + devconf['addresses'].extend( + [i + '/' + prefix6 for i in addresses6]) + + # Set IPv4 default gateway gateway = self.get_gateway(c_dev) if gateway: - conf.append(' gateway ' + gateway) + devconf['gateway4'] = gateway + + # Set IPv6 default gateway + gateway6 = self.get_gateway6(c_dev) + if gateway: + devconf['gateway6'] = gateway6 - domain = self.get_domain(c_dev) - if domain: - conf.append(' dns-search ' + domain) + # Set DNS servers and search domains + nameservers = self.get_nameservers(c_dev) + if nameservers: + devconf['nameservers'] = nameservers - # add global DNS servers to all interfaces - dns = self.get_dns(c_dev) - if global_dns or dns: - conf.append(' dns-nameservers ' + ' '.join(global_dns + dns)) + # Set MTU size + mtu = self.get_mtu(c_dev) + if mtu: + devconf['mtu'] = mtu - conf.append('') + ethernets[dev] = devconf - return "\n".join(conf) + netconf['ethernets'] = ethernets + return(netconf) def find_candidate_devs(): @@ -390,10 +434,10 @@ def read_context_disk_dir(source_dir, asuser=None): except TypeError: LOG.warning("Failed base64 decoding of userdata") - # generate static /etc/network/interfaces + # generate Network Configuration v2 # only if there are any required context variables - # http://opennebula.org/documentation:rel3.8:cong#network_configuration - ipaddr_keys = [k for k in context if re.match(r'^ETH\d+_IP$', k)] + # http://docs.opennebula.org/5.4/operation/references/template.html#context-section + ipaddr_keys = [k for k in context if re.match(r'^ETH\d+_IP.*$', k)] if ipaddr_keys: onet = OpenNebulaNetwork(context) results['network-interfaces'] = onet.gen_conf() -- cgit v1.2.3