From 97b5b40e14fd6563b9cac716f202891d4c38ecf6 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Mon, 12 Sep 2016 09:17:13 -0400 Subject: remove obsolete .bzrignore --- .bzrignore | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 .bzrignore diff --git a/.bzrignore b/.bzrignore deleted file mode 100644 index 926e4581..00000000 --- a/.bzrignore +++ /dev/null @@ -1,4 +0,0 @@ -.tox -dist -cloud_init.egg-info -__pycache__ -- cgit v1.2.3 From 2aa9b1ddf80ffe7d35e8437c59670856d612e64e Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Mon, 12 Sep 2016 12:32:08 -0400 Subject: DataSourceOVF: fix user-data as base64 with python3 When user-data was provided in the ovf environment python3 would call base64.decodestring() with a string rather than bytes and an exception would occur. This fixes the broken path and adds unit test. Also changes to return None rather than empty string when there is no user-data and when there is user-data return that as bytes instead of string. LP: #1619394 --- cloudinit/sources/DataSourceOVF.py | 8 +-- tests/unittests/test_datasource/test_ovf.py | 83 +++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 tests/unittests/test_datasource/test_ovf.py diff --git a/cloudinit/sources/DataSourceOVF.py b/cloudinit/sources/DataSourceOVF.py index 43347cfb..5b3bdb4e 100644 --- a/cloudinit/sources/DataSourceOVF.py +++ b/cloudinit/sources/DataSourceOVF.py @@ -237,7 +237,7 @@ def wait_for_imc_cfg_file(dirpath, filename, maxwait=180, naplen=5): def read_vmware_imc(config): md = {} cfg = {} - ud = "" + ud = None if config.host_name: if config.domain_name: md['local-hostname'] = config.host_name + "." + config.domain_name @@ -256,7 +256,7 @@ def read_ovf_environment(contents): props = get_properties(contents) md = {} cfg = {} - ud = "" + ud = None cfg_props = ['password'] md_props = ['seedfrom', 'local-hostname', 'public-keys', 'instance-id'] for (prop, val) in props.items(): @@ -268,9 +268,9 @@ def read_ovf_environment(contents): cfg[prop] = val elif prop == "user-data": try: - ud = base64.decodestring(val) + ud = base64.b64decode(val.encode()) except Exception: - ud = val + ud = val.encode() return (md, ud, cfg) diff --git a/tests/unittests/test_datasource/test_ovf.py b/tests/unittests/test_datasource/test_ovf.py new file mode 100644 index 00000000..5f8e7e44 --- /dev/null +++ b/tests/unittests/test_datasource/test_ovf.py @@ -0,0 +1,83 @@ +# vi: ts=4 expandtab +# +# Copyright (C) 2016 Canonical Ltd. +# +# Author: Scott Moser +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 3, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import base64 + +from .. import helpers as test_helpers + +from cloudinit.sources import DataSourceOVF as dsovf + +OVF_ENV_CONTENT = """ + + + + ESX Server + 3.0.1 + VMware, Inc. + en_US + + + +{properties} + + +""" + + +def fill_properties(props, template=OVF_ENV_CONTENT): + lines = [] + prop_tmpl = '' + for key, val in props.items(): + lines.append(prop_tmpl.format(key=key, val=val)) + indent = " " + properties = ''.join([indent + l + "\n" for l in lines]) + return template.format(properties=properties) + + +class TestReadOvfEnv(test_helpers.TestCase): + def test_with_b64_userdata(self): + user_data = "#!/bin/sh\necho hello world\n" + user_data_b64 = base64.b64encode(user_data.encode()).decode() + props = {"user-data": user_data_b64, "password": "passw0rd", + "instance-id": "inst-001"} + env = fill_properties(props) + md, ud, cfg = dsovf.read_ovf_environment(env) + self.assertEqual({"instance-id": "inst-001"}, md) + self.assertEqual(user_data.encode(), ud) + self.assertEqual({'password': "passw0rd"}, cfg) + + def test_with_non_b64_userdata(self): + user_data = "my-user-data" + props = {"user-data": user_data, "instance-id": "inst-001"} + env = fill_properties(props) + md, ud, cfg = dsovf.read_ovf_environment(env) + self.assertEqual({"instance-id": "inst-001"}, md) + self.assertEqual(user_data.encode(), ud) + self.assertEqual({}, cfg) + + def test_with_no_userdata(self): + props = {"password": "passw0rd", "instance-id": "inst-001"} + env = fill_properties(props) + md, ud, cfg = dsovf.read_ovf_environment(env) + self.assertEqual({"instance-id": "inst-001"}, md) + self.assertEqual({'password': "passw0rd"}, cfg) + self.assertEqual(None, ud) -- cgit v1.2.3 From 65ace7b35494dba1747eece815754ab8573d83d8 Mon Sep 17 00:00:00 2001 From: Jon Grimm Date: Fri, 9 Sep 2016 16:32:36 -0500 Subject: Allow link type of null in network_data.json Treat null type as yet another physical type, seen in real-world openstack cloud. Also, support the case where network_data.json provides mac addresses in upper case. Rackspace public cloud currently does that. LP: #1621968 --- cloudinit/sources/helpers/openstack.py | 14 +++++++------- .../unittests/test_datasource/test_configdrive.py | 22 +++++++++++++++++++--- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/cloudinit/sources/helpers/openstack.py b/cloudinit/sources/helpers/openstack.py index a5a2a1d6..61b0b08c 100644 --- a/cloudinit/sources/helpers/openstack.py +++ b/cloudinit/sources/helpers/openstack.py @@ -555,11 +555,12 @@ def convert_net_json(network_json=None, known_macs=None): if 'name' in link: cfg['name'] = link['name'] + link_mac_addr = None if link.get('ethernet_mac_address'): - link_id_info[link['id']] = link.get('ethernet_mac_address') + link_mac_addr = link.get('ethernet_mac_address').lower() + link_id_info[link['id']] = link_mac_addr - curinfo = {'name': cfg.get('name'), - 'mac': link.get('ethernet_mac_address'), + curinfo = {'name': cfg.get('name'), 'mac': link_mac_addr, 'id': link['id'], 'type': link['type']} for network in [n for n in networks @@ -582,10 +583,9 @@ def convert_net_json(network_json=None, known_macs=None): subnet['ipv6'] = True subnets.append(subnet) cfg.update({'subnets': subnets}) - if link['type'] in ['ethernet', 'vif', 'ovs', 'phy', 'bridge', 'tap']: - cfg.update({ - 'type': 'physical', - 'mac_address': link['ethernet_mac_address']}) + if link['type'] in [None, 'ethernet', 'vif', 'ovs', 'phy', + 'bridge', 'tap']: + cfg.update({'type': 'physical', 'mac_address': link_mac_addr}) elif link['type'] in ['bond']: params = {} for k, v in link.items(): diff --git a/tests/unittests/test_datasource/test_configdrive.py b/tests/unittests/test_datasource/test_configdrive.py index 98ff97a7..6e00abf4 100644 --- a/tests/unittests/test_datasource/test_configdrive.py +++ b/tests/unittests/test_datasource/test_configdrive.py @@ -1,4 +1,4 @@ -from copy import copy +from copy import copy, deepcopy import json import os import shutil @@ -101,7 +101,7 @@ NETWORK_DATA_2 = { "type": "vif", "id": "eth1", "vif_id": "vif-foo2"}] } -# This network data ha 'tap' type for a link. +# This network data ha 'tap' or null type for a link. NETWORK_DATA_3 = { "services": [{"type": "dns", "address": "172.16.36.11"}, {"type": "dns", "address": "172.16.36.12"}], @@ -132,7 +132,7 @@ NETWORK_DATA_3 = { "type": "tap", "id": "tap77a0dc5b-72", "vif_id": "77a0dc5b-720e-41b7-bfa7-1b2ff62e0d48"}, {"ethernet_mac_address": "fa:16:3e:a8:14:69", "mtu": None, - "type": "tap", "id": "tap7d6b7bec-93", + "type": None, "id": "tap7d6b7bec-93", "vif_id": "7d6b7bec-93e6-4c03-869a-ddc5014892d5"} ] } @@ -704,6 +704,22 @@ class TestConvertNetworkData(TestCase): self.assertIn("address 10.0.1.5", eni_rendering) self.assertIn("auto enp0s1.602", eni_rendering) + def test_mac_addrs_can_be_upper_case(self): + # input mac addresses on rackspace may be upper case + my_netdata = deepcopy(NETWORK_DATA) + for link in my_netdata['links']: + link['ethernet_mac_address'] = link['ethernet_mac_address'].upper() + + ncfg = openstack.convert_net_json(my_netdata, known_macs=KNOWN_MACS) + config_name2mac = {} + for n in ncfg['config']: + if n['type'] == 'physical': + config_name2mac[n['name']] = n['mac_address'] + + expected = {'nic0': 'fa:16:3e:05:30:fe', 'enp0s1': 'fa:16:3e:69:b0:58', + 'enp0s2': 'fa:16:3e:d4:57:ad'} + self.assertEqual(expected, config_name2mac) + def cfg_ds_from_dir(seed_d): cfg_ds = ds.DataSourceConfigDrive(settings.CFG_BUILTIN, None, -- cgit v1.2.3