Merge ~sw37th/cloud-init:opennebula_fix_null_gateway6 into cloud-init:master

Proposed by Akihiko Ota
Status: Merged
Approved by: Scott Moser
Approved revision: 3f8f3249643056c751efe11ce27edfe56d9cec3d
Merge reported by: Server Team CI bot
Merged at revision: not available
Proposed branch: ~sw37th/cloud-init:opennebula_fix_null_gateway6
Merge into: cloud-init:master
Diff against target: 446 lines (+407/-3)
2 files modified
cloudinit/sources/DataSourceOpenNebula.py (+1/-1)
tests/unittests/test_datasource/test_opennebula.py (+406/-2)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
Scott Moser Approve
Review via email: mp+350428@code.launchpad.net

Commit message

OpenNebula: Fix null gateway6

The OpenNebula data source generates an invalid netplan yaml file
if the IPv6 gateway is not defined in context.sh.

LP: #1768547

To post a comment you must log in.
Revision history for this message
Akihiko Ota (sw37th) wrote :

OpenNebula: Fix null gateway6

The OpenNebula data source generates an invalid netplan yaml file
if the IPv6 gateway is not defined in context.sh.

LP: #1768547

Revision history for this message
Scott Moser (smoser) wrote :

Hi,
Thanks for the merge proposal. I'll have the c-i bot run tests on it and it will post result here shortly.

That said, I'd like to see a unit tests added that covers this path.
It looks l ike you should be able to add a test to
  tests/unittests/test_datasource/test_opennebula.py:TestOpenNebulaNetwork

without too much effort.

Please feel free to ping me if you have any questions.

Thanks!

57941a4... by Akihiko Ota on 2018-07-24

OpenNebula: add tests for OpenNebulaNetwork.gen_conf()

148dda5... by Akihiko Ota on 2018-07-25

OpenNebula: add tests for several get methods of OpenNebulaNetwork

Revision history for this message
Akihiko Ota (sw37th) wrote :

Hi Scott,

Ok, I added some tests for TestOpenNebulaNetwork.gen_conf().
And also added several tests for get_* methods.

Revision history for this message
Scott Moser (smoser) wrote :

Akihiko,

This looks great, thank you for the extended test coverage.

I have a few little things inline.

https://jenkins.ubuntu.com/server/job/cloud-init-ci/179/
is running against your build here and will post its results.

3f8f324... by Akihiko Ota on 2018-08-01

OpenNebula: Fix up unittests

Added docstring, changed argument order of assertEqual, and splited some
tests.
Changed from assertIsNone() to assertEqual() to avoid RPM build error.

Revision history for this message
Akihiko Ota (sw37th) wrote :

Hi Scott,

I have changed TestOpenNebulaNetwork:
- added docstrings to each new tests.
- changed argument order of assertEqual().
- splited some tests.

And changed from assertIsNone() to assertEqual() to avoid RPM build error.
Please confirm.

Revision history for this message
Scott Moser (smoser) wrote :

Akihiko,
Thanks.
https://jenkins.ubuntu.com/server/job/cloud-init-ci/189/console
is running it will post here.

if it passes. i approve.
thanks.

review: Approve
Revision history for this message
Server Team CI bot (server-team-bot) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/cloudinit/sources/DataSourceOpenNebula.py b/cloudinit/sources/DataSourceOpenNebula.py
2index 16c1078..77ccd12 100644
3--- a/cloudinit/sources/DataSourceOpenNebula.py
4+++ b/cloudinit/sources/DataSourceOpenNebula.py
5@@ -232,7 +232,7 @@ class OpenNebulaNetwork(object):
6
7 # Set IPv6 default gateway
8 gateway6 = self.get_gateway6(c_dev)
9- if gateway:
10+ if gateway6:
11 devconf['gateway6'] = gateway6
12
13 # Set DNS servers and search domains
14diff --git a/tests/unittests/test_datasource/test_opennebula.py b/tests/unittests/test_datasource/test_opennebula.py
15index ab42f34..36b4d77 100644
16--- a/tests/unittests/test_datasource/test_opennebula.py
17+++ b/tests/unittests/test_datasource/test_opennebula.py
18@@ -354,6 +354,412 @@ class TestOpenNebulaNetwork(unittest.TestCase):
19
20 system_nics = ('eth0', 'ens3')
21
22+ def test_context_devname(self):
23+ """Verify context_devname correctly returns mac and name."""
24+ context = {
25+ 'ETH0_MAC': '02:00:0a:12:01:01',
26+ 'ETH1_MAC': '02:00:0a:12:0f:0f', }
27+ expected = {
28+ '02:00:0a:12:01:01': 'ETH0',
29+ '02:00:0a:12:0f:0f': 'ETH1', }
30+ net = ds.OpenNebulaNetwork(context)
31+ self.assertEqual(expected, net.context_devname)
32+
33+ def test_get_nameservers(self):
34+ """
35+ Verify get_nameservers('device') correctly returns DNS server addresses
36+ and search domains.
37+ """
38+ context = {
39+ 'DNS': '1.2.3.8',
40+ 'ETH0_DNS': '1.2.3.6 1.2.3.7',
41+ 'ETH0_SEARCH_DOMAIN': 'example.com example.org', }
42+ expected = {
43+ 'addresses': ['1.2.3.6', '1.2.3.7', '1.2.3.8'],
44+ 'search': ['example.com', 'example.org']}
45+ net = ds.OpenNebulaNetwork(context)
46+ val = net.get_nameservers('eth0')
47+ self.assertEqual(expected, val)
48+
49+ def test_get_mtu(self):
50+ """Verify get_mtu('device') correctly returns MTU size."""
51+ context = {'ETH0_MTU': '1280'}
52+ net = ds.OpenNebulaNetwork(context)
53+ val = net.get_mtu('eth0')
54+ self.assertEqual('1280', val)
55+
56+ def test_get_ip(self):
57+ """Verify get_ip('device') correctly returns IPv4 address."""
58+ context = {'ETH0_IP': PUBLIC_IP}
59+ net = ds.OpenNebulaNetwork(context)
60+ val = net.get_ip('eth0', MACADDR)
61+ self.assertEqual(PUBLIC_IP, val)
62+
63+ def test_get_ip_emptystring(self):
64+ """
65+ Verify get_ip('device') correctly returns IPv4 address.
66+ It returns IP address created by MAC address if ETH0_IP has empty
67+ string.
68+ """
69+ context = {'ETH0_IP': ''}
70+ net = ds.OpenNebulaNetwork(context)
71+ val = net.get_ip('eth0', MACADDR)
72+ self.assertEqual(IP_BY_MACADDR, val)
73+
74+ def test_get_ip6(self):
75+ """
76+ Verify get_ip6('device') correctly returns IPv6 address.
77+ In this case, IPv6 address is Given by ETH0_IP6.
78+ """
79+ context = {
80+ 'ETH0_IP6': IP6_GLOBAL,
81+ 'ETH0_IP6_ULA': '', }
82+ expected = [IP6_GLOBAL]
83+ net = ds.OpenNebulaNetwork(context)
84+ val = net.get_ip6('eth0')
85+ self.assertEqual(expected, val)
86+
87+ def test_get_ip6_ula(self):
88+ """
89+ Verify get_ip6('device') correctly returns IPv6 address.
90+ In this case, IPv6 address is Given by ETH0_IP6_ULA.
91+ """
92+ context = {
93+ 'ETH0_IP6': '',
94+ 'ETH0_IP6_ULA': IP6_ULA, }
95+ expected = [IP6_ULA]
96+ net = ds.OpenNebulaNetwork(context)
97+ val = net.get_ip6('eth0')
98+ self.assertEqual(expected, val)
99+
100+ def test_get_ip6_dual(self):
101+ """
102+ Verify get_ip6('device') correctly returns IPv6 address.
103+ In this case, IPv6 addresses are Given by ETH0_IP6 and ETH0_IP6_ULA.
104+ """
105+ context = {
106+ 'ETH0_IP6': IP6_GLOBAL,
107+ 'ETH0_IP6_ULA': IP6_ULA, }
108+ expected = [IP6_GLOBAL, IP6_ULA]
109+ net = ds.OpenNebulaNetwork(context)
110+ val = net.get_ip6('eth0')
111+ self.assertEqual(expected, val)
112+
113+ def test_get_ip6_prefix(self):
114+ """
115+ Verify get_ip6_prefix('device') correctly returns IPv6 prefix.
116+ """
117+ context = {'ETH0_IP6_PREFIX_LENGTH': IP6_PREFIX}
118+ net = ds.OpenNebulaNetwork(context)
119+ val = net.get_ip6_prefix('eth0')
120+ self.assertEqual(IP6_PREFIX, val)
121+
122+ def test_get_ip6_prefix_emptystring(self):
123+ """
124+ Verify get_ip6_prefix('device') correctly returns IPv6 prefix.
125+ It returns default value '64' if ETH0_IP6_PREFIX_LENGTH has empty
126+ string.
127+ """
128+ context = {'ETH0_IP6_PREFIX_LENGTH': ''}
129+ net = ds.OpenNebulaNetwork(context)
130+ val = net.get_ip6_prefix('eth0')
131+ self.assertEqual('64', val)
132+
133+ def test_get_gateway(self):
134+ """
135+ Verify get_gateway('device') correctly returns IPv4 default gateway
136+ address.
137+ """
138+ context = {'ETH0_GATEWAY': '1.2.3.5'}
139+ net = ds.OpenNebulaNetwork(context)
140+ val = net.get_gateway('eth0')
141+ self.assertEqual('1.2.3.5', val)
142+
143+ def test_get_gateway6(self):
144+ """
145+ Verify get_gateway6('device') correctly returns IPv6 default gateway
146+ address.
147+ """
148+ context = {'ETH0_GATEWAY6': IP6_GW}
149+ net = ds.OpenNebulaNetwork(context)
150+ val = net.get_gateway6('eth0')
151+ self.assertEqual(IP6_GW, val)
152+
153+ def test_get_mask(self):
154+ """
155+ Verify get_mask('device') correctly returns IPv4 subnet mask.
156+ """
157+ context = {'ETH0_MASK': '255.255.0.0'}
158+ net = ds.OpenNebulaNetwork(context)
159+ val = net.get_mask('eth0')
160+ self.assertEqual('255.255.0.0', val)
161+
162+ def test_get_mask_emptystring(self):
163+ """
164+ Verify get_mask('device') correctly returns IPv4 subnet mask.
165+ It returns default value '255.255.255.0' if ETH0_MASK has empty string.
166+ """
167+ context = {'ETH0_MASK': ''}
168+ net = ds.OpenNebulaNetwork(context)
169+ val = net.get_mask('eth0')
170+ self.assertEqual('255.255.255.0', val)
171+
172+ def test_get_network(self):
173+ """
174+ Verify get_network('device') correctly returns IPv4 network address.
175+ """
176+ context = {'ETH0_NETWORK': '1.2.3.0'}
177+ net = ds.OpenNebulaNetwork(context)
178+ val = net.get_network('eth0', MACADDR)
179+ self.assertEqual('1.2.3.0', val)
180+
181+ def test_get_network_emptystring(self):
182+ """
183+ Verify get_network('device') correctly returns IPv4 network address.
184+ It returns network address created by MAC address if ETH0_NETWORK has
185+ empty string.
186+ """
187+ context = {'ETH0_NETWORK': ''}
188+ net = ds.OpenNebulaNetwork(context)
189+ val = net.get_network('eth0', MACADDR)
190+ self.assertEqual('10.18.1.0', val)
191+
192+ def test_get_field(self):
193+ """
194+ Verify get_field('device', 'name') returns *context* value.
195+ """
196+ context = {'ETH9_DUMMY': 'DUMMY_VALUE'}
197+ net = ds.OpenNebulaNetwork(context)
198+ val = net.get_field('eth9', 'dummy')
199+ self.assertEqual('DUMMY_VALUE', val)
200+
201+ def test_get_field_withdefaultvalue(self):
202+ """
203+ Verify get_field('device', 'name', 'default value') returns *context*
204+ value.
205+ """
206+ context = {'ETH9_DUMMY': 'DUMMY_VALUE'}
207+ net = ds.OpenNebulaNetwork(context)
208+ val = net.get_field('eth9', 'dummy', 'DEFAULT_VALUE')
209+ self.assertEqual('DUMMY_VALUE', val)
210+
211+ def test_get_field_withdefaultvalue_emptycontext(self):
212+ """
213+ Verify get_field('device', 'name', 'default value') returns *default*
214+ value if context value is empty string.
215+ """
216+ context = {'ETH9_DUMMY': ''}
217+ net = ds.OpenNebulaNetwork(context)
218+ val = net.get_field('eth9', 'dummy', 'DEFAULT_VALUE')
219+ self.assertEqual('DEFAULT_VALUE', val)
220+
221+ def test_get_field_emptycontext(self):
222+ """
223+ Verify get_field('device', 'name') returns None if context value is
224+ empty string.
225+ """
226+ context = {'ETH9_DUMMY': ''}
227+ net = ds.OpenNebulaNetwork(context)
228+ val = net.get_field('eth9', 'dummy')
229+ self.assertEqual(None, val)
230+
231+ def test_get_field_nonecontext(self):
232+ """
233+ Verify get_field('device', 'name') returns None if context value is
234+ None.
235+ """
236+ context = {'ETH9_DUMMY': None}
237+ net = ds.OpenNebulaNetwork(context)
238+ val = net.get_field('eth9', 'dummy')
239+ self.assertEqual(None, val)
240+
241+ @mock.patch(DS_PATH + ".get_physical_nics_by_mac")
242+ def test_gen_conf_gateway(self, m_get_phys_by_mac):
243+ """Test rendering with/without IPv4 gateway"""
244+ self.maxDiff = None
245+ # empty ETH0_GATEWAY
246+ context = {
247+ 'ETH0_MAC': '02:00:0a:12:01:01',
248+ 'ETH0_GATEWAY': '', }
249+ for nic in self.system_nics:
250+ expected = {
251+ 'version': 2,
252+ 'ethernets': {
253+ nic: {
254+ 'match': {'macaddress': MACADDR},
255+ 'addresses': [IP_BY_MACADDR + '/' + IP4_PREFIX]}}}
256+ m_get_phys_by_mac.return_value = {MACADDR: nic}
257+ net = ds.OpenNebulaNetwork(context)
258+ self.assertEqual(net.gen_conf(), expected)
259+
260+ # set ETH0_GATEWAY
261+ context = {
262+ 'ETH0_MAC': '02:00:0a:12:01:01',
263+ 'ETH0_GATEWAY': '1.2.3.5', }
264+ for nic in self.system_nics:
265+ expected = {
266+ 'version': 2,
267+ 'ethernets': {
268+ nic: {
269+ 'gateway4': '1.2.3.5',
270+ 'match': {'macaddress': MACADDR},
271+ 'addresses': [IP_BY_MACADDR + '/' + IP4_PREFIX]}}}
272+ m_get_phys_by_mac.return_value = {MACADDR: nic}
273+ net = ds.OpenNebulaNetwork(context)
274+ self.assertEqual(net.gen_conf(), expected)
275+
276+ @mock.patch(DS_PATH + ".get_physical_nics_by_mac")
277+ def test_gen_conf_gateway6(self, m_get_phys_by_mac):
278+ """Test rendering with/without IPv6 gateway"""
279+ self.maxDiff = None
280+ # empty ETH0_GATEWAY6
281+ context = {
282+ 'ETH0_MAC': '02:00:0a:12:01:01',
283+ 'ETH0_GATEWAY6': '', }
284+ for nic in self.system_nics:
285+ expected = {
286+ 'version': 2,
287+ 'ethernets': {
288+ nic: {
289+ 'match': {'macaddress': MACADDR},
290+ 'addresses': [IP_BY_MACADDR + '/' + IP4_PREFIX]}}}
291+ m_get_phys_by_mac.return_value = {MACADDR: nic}
292+ net = ds.OpenNebulaNetwork(context)
293+ self.assertEqual(net.gen_conf(), expected)
294+
295+ # set ETH0_GATEWAY6
296+ context = {
297+ 'ETH0_MAC': '02:00:0a:12:01:01',
298+ 'ETH0_GATEWAY6': IP6_GW, }
299+ for nic in self.system_nics:
300+ expected = {
301+ 'version': 2,
302+ 'ethernets': {
303+ nic: {
304+ 'gateway6': IP6_GW,
305+ 'match': {'macaddress': MACADDR},
306+ 'addresses': [IP_BY_MACADDR + '/' + IP4_PREFIX]}}}
307+ m_get_phys_by_mac.return_value = {MACADDR: nic}
308+ net = ds.OpenNebulaNetwork(context)
309+ self.assertEqual(net.gen_conf(), expected)
310+
311+ @mock.patch(DS_PATH + ".get_physical_nics_by_mac")
312+ def test_gen_conf_ipv6address(self, m_get_phys_by_mac):
313+ """Test rendering with/without IPv6 address"""
314+ self.maxDiff = None
315+ # empty ETH0_IP6, ETH0_IP6_ULA, ETH0_IP6_PREFIX_LENGTH
316+ context = {
317+ 'ETH0_MAC': '02:00:0a:12:01:01',
318+ 'ETH0_IP6': '',
319+ 'ETH0_IP6_ULA': '',
320+ 'ETH0_IP6_PREFIX_LENGTH': '', }
321+ for nic in self.system_nics:
322+ expected = {
323+ 'version': 2,
324+ 'ethernets': {
325+ nic: {
326+ 'match': {'macaddress': MACADDR},
327+ 'addresses': [IP_BY_MACADDR + '/' + IP4_PREFIX]}}}
328+ m_get_phys_by_mac.return_value = {MACADDR: nic}
329+ net = ds.OpenNebulaNetwork(context)
330+ self.assertEqual(net.gen_conf(), expected)
331+
332+ # set ETH0_IP6, ETH0_IP6_ULA, ETH0_IP6_PREFIX_LENGTH
333+ context = {
334+ 'ETH0_MAC': '02:00:0a:12:01:01',
335+ 'ETH0_IP6': IP6_GLOBAL,
336+ 'ETH0_IP6_PREFIX_LENGTH': IP6_PREFIX,
337+ 'ETH0_IP6_ULA': IP6_ULA, }
338+ for nic in self.system_nics:
339+ expected = {
340+ 'version': 2,
341+ 'ethernets': {
342+ nic: {
343+ 'match': {'macaddress': MACADDR},
344+ 'addresses': [
345+ IP_BY_MACADDR + '/' + IP4_PREFIX,
346+ IP6_GLOBAL + '/' + IP6_PREFIX,
347+ IP6_ULA + '/' + IP6_PREFIX]}}}
348+ m_get_phys_by_mac.return_value = {MACADDR: nic}
349+ net = ds.OpenNebulaNetwork(context)
350+ self.assertEqual(net.gen_conf(), expected)
351+
352+ @mock.patch(DS_PATH + ".get_physical_nics_by_mac")
353+ def test_gen_conf_dns(self, m_get_phys_by_mac):
354+ """Test rendering with/without DNS server, search domain"""
355+ self.maxDiff = None
356+ # empty DNS, ETH0_DNS, ETH0_SEARCH_DOMAIN
357+ context = {
358+ 'ETH0_MAC': '02:00:0a:12:01:01',
359+ 'DNS': '',
360+ 'ETH0_DNS': '',
361+ 'ETH0_SEARCH_DOMAIN': '', }
362+ for nic in self.system_nics:
363+ expected = {
364+ 'version': 2,
365+ 'ethernets': {
366+ nic: {
367+ 'match': {'macaddress': MACADDR},
368+ 'addresses': [IP_BY_MACADDR + '/' + IP4_PREFIX]}}}
369+ m_get_phys_by_mac.return_value = {MACADDR: nic}
370+ net = ds.OpenNebulaNetwork(context)
371+ self.assertEqual(net.gen_conf(), expected)
372+
373+ # set DNS, ETH0_DNS, ETH0_SEARCH_DOMAIN
374+ context = {
375+ 'ETH0_MAC': '02:00:0a:12:01:01',
376+ 'DNS': '1.2.3.8',
377+ 'ETH0_DNS': '1.2.3.6 1.2.3.7',
378+ 'ETH0_SEARCH_DOMAIN': 'example.com example.org', }
379+ for nic in self.system_nics:
380+ expected = {
381+ 'version': 2,
382+ 'ethernets': {
383+ nic: {
384+ 'nameservers': {
385+ 'addresses': ['1.2.3.6', '1.2.3.7', '1.2.3.8'],
386+ 'search': ['example.com', 'example.org']},
387+ 'match': {'macaddress': MACADDR},
388+ 'addresses': [IP_BY_MACADDR + '/' + IP4_PREFIX]}}}
389+ m_get_phys_by_mac.return_value = {MACADDR: nic}
390+ net = ds.OpenNebulaNetwork(context)
391+ self.assertEqual(net.gen_conf(), expected)
392+
393+ @mock.patch(DS_PATH + ".get_physical_nics_by_mac")
394+ def test_gen_conf_mtu(self, m_get_phys_by_mac):
395+ """Test rendering with/without MTU"""
396+ self.maxDiff = None
397+ # empty ETH0_MTU
398+ context = {
399+ 'ETH0_MAC': '02:00:0a:12:01:01',
400+ 'ETH0_MTU': '', }
401+ for nic in self.system_nics:
402+ expected = {
403+ 'version': 2,
404+ 'ethernets': {
405+ nic: {
406+ 'match': {'macaddress': MACADDR},
407+ 'addresses': [IP_BY_MACADDR + '/' + IP4_PREFIX]}}}
408+ m_get_phys_by_mac.return_value = {MACADDR: nic}
409+ net = ds.OpenNebulaNetwork(context)
410+ self.assertEqual(net.gen_conf(), expected)
411+
412+ # set ETH0_MTU
413+ context = {
414+ 'ETH0_MAC': '02:00:0a:12:01:01',
415+ 'ETH0_MTU': '1280', }
416+ for nic in self.system_nics:
417+ expected = {
418+ 'version': 2,
419+ 'ethernets': {
420+ nic: {
421+ 'mtu': '1280',
422+ 'match': {'macaddress': MACADDR},
423+ 'addresses': [IP_BY_MACADDR + '/' + IP4_PREFIX]}}}
424+ m_get_phys_by_mac.return_value = {MACADDR: nic}
425+ net = ds.OpenNebulaNetwork(context)
426+ self.assertEqual(net.gen_conf(), expected)
427+
428 @mock.patch(DS_PATH + ".get_physical_nics_by_mac")
429 def test_eth0(self, m_get_phys_by_mac):
430 for nic in self.system_nics:
431@@ -395,7 +801,6 @@ class TestOpenNebulaNetwork(unittest.TestCase):
432 'match': {'macaddress': MACADDR},
433 'addresses': [IP_BY_MACADDR + '/16'],
434 'gateway4': '1.2.3.5',
435- 'gateway6': None,
436 'nameservers': {
437 'addresses': ['1.2.3.6', '1.2.3.7', '1.2.3.8']}}}}
438
439@@ -494,7 +899,6 @@ class TestOpenNebulaNetwork(unittest.TestCase):
440 'match': {'macaddress': MAC_1},
441 'addresses': ['10.3.1.3/16'],
442 'gateway4': '10.3.0.1',
443- 'gateway6': None,
444 'nameservers': {
445 'addresses': ['10.3.1.2', '1.2.3.8'],
446 'search': [

Subscribers

People subscribed via source and target branches