Merge ~minagalic/cloud-init:feax/ephemeral_connectivity into cloud-init:master
- Git
- lp:~minagalic/cloud-init
- feax/ephemeral_connectivity
- Merge into master
Status: | Merged |
---|---|
Approved by: | Chad Smith |
Approved revision: | f8466558de72accfcb9aca923a147fb3bedb2a4e |
Merged at revision: | ef0611a51a98a273cfa37b0daeb3e9d151888b88 |
Proposed branch: | ~minagalic/cloud-init:feax/ephemeral_connectivity |
Merge into: | cloud-init:master |
Diff against target: |
270 lines (+134/-7) 4 files modified
cloudinit/net/__init__.py (+34/-2) cloudinit/net/dhcp.py (+14/-3) cloudinit/net/tests/test_dhcp.py (+35/-1) cloudinit/net/tests/test_init.py (+51/-1) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Server Team CI bot | continuous-integration | Approve | |
Mina Galić (community) | Needs Information | ||
Chad Smith | Pending | ||
Review via email: mp+358876@code.launchpad.net |
Commit message
net: Ephemeral*Network: add connectivity check via URL
We add a new Optional parameter: connectivity_url
This is used in __enter__ to verify if a connection already exists.
If it does exist, no operations are performed.
Description of the change
Server Team CI bot (server-team-bot) wrote : | # |
Server Team CI bot (server-team-bot) wrote : | # |
FAILED: Continuous integration, rev:0bb25f3a74a
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
https:/
Executed test runs:
SUCCESS: Checkout
FAILED: Unit & Style Tests
Click here to trigger a rebuild:
https:/
- f3c4223... by =?utf-8?q?Igor_Gali=C4=87?= <email address hidden>
-
EphemeralDHCPv4: add connectivity_url parameter
..and pass it on to EphemeralIpv4Ne
twork
Mina Galić (minagalic) wrote : | # |
I'm gonna need some help here
Server Team CI bot (server-team-bot) wrote : | # |
FAILED: Continuous integration, rev:119058aadd5
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
https:/
Executed test runs:
SUCCESS: Checkout
FAILED: Unit & Style Tests
Click here to trigger a rebuild:
https:/
- 68046f6... by =?utf-8?q?Igor_Gali=C4=87?= <email address hidden>
-
Thanks to tests, discovered it's better to test connectivity ourselves
in __enter__(), *before* calling self.obtain_lease()
Otherwise we're performing too much discovery before trying to actually test
connectivity by instantiating EphemeralIPv4Network The question left now, is whether we should still pass connectivity_url to
EphemeralIPv4Network. Chances are, nothing has changed in the last sub-second,
and if it hasn't, then we're taking another 5 second penalty here.
Mina Galić (minagalic) wrote : | # |
Looks pretty okay so far, except for…
- 0291cf3... by =?utf-8?q?Igor_Gali=C4=87?= <email address hidden>
-
Remove private _connectivity_
check() we're using a public module function now
Server Team CI bot (server-team-bot) wrote : | # |
FAILED: Continuous integration, rev:5dcdff256a4
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
https:/
Executed test runs:
SUCCESS: Checkout
FAILED: Unit & Style Tests
Click here to trigger a rebuild:
https:/
Mina Galić (minagalic) wrote : | # |
should we pass connectivity_url from EphemeralDhcp4N
Server Team CI bot (server-team-bot) wrote : | # |
FAILED: Continuous integration, rev:a3b483d25a8
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
https:/
Executed test runs:
SUCCESS: Checkout
FAILED: Unit & Style Tests
Click here to trigger a rebuild:
https:/
Chad Smith (chad.smith) wrote : | # |
Here is a patch with some unit test cleanup and unit test adds for the new function you added.
I also adding a bit of checking on the url param passed to has_url_
Unit test adds and functionality changes below
http://
Chad Smith (chad.smith) wrote : | # |
The integration tests also voted failure on your branch because you didn't import UrlError in net/__init__.py. running tox locally on your system would have shown this if you have unit tests on the new function that was added.
- f846655... by Chad Smith
-
unit test cleanup; add unit test for has_url_
connectivity Also added a bit of checking on the url param passed to has_url_
connectivity
function since we don't want callsites to stuff in the wrong type of content.
Server Team CI bot (server-team-bot) wrote : | # |
FAILED: Continuous integration, rev:7cba05e77a3
https:/
Executed test runs:
SUCCESS: Checkout
FAILED: Unit & Style Tests
Click here to trigger a rebuild:
https:/
Server Team CI bot (server-team-bot) wrote : | # |
FAILED: Continuous integration, rev:2605bf0efab
https:/
Executed test runs:
SUCCESS: Checkout
FAILED: Unit & Style Tests
Click here to trigger a rebuild:
https:/
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:f8466558de7
https:/
Executed test runs:
SUCCESS: Checkout
SUCCESS: Unit & Style Tests
SUCCESS: Ubuntu LTS: Build
SUCCESS: Ubuntu LTS: Integration
IN_PROGRESS: Declarative: Post Actions
Click here to trigger a rebuild:
https:/
Preview Diff
1 | diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py | |||
2 | index ad98a59..3642fb1 100644 | |||
3 | --- a/cloudinit/net/__init__.py | |||
4 | +++ b/cloudinit/net/__init__.py | |||
5 | @@ -12,6 +12,7 @@ import re | |||
6 | 12 | 12 | ||
7 | 13 | from cloudinit.net.network_state import mask_to_net_prefix | 13 | from cloudinit.net.network_state import mask_to_net_prefix |
8 | 14 | from cloudinit import util | 14 | from cloudinit import util |
9 | 15 | from cloudinit.url_helper import UrlError, readurl | ||
10 | 15 | 16 | ||
11 | 16 | LOG = logging.getLogger(__name__) | 17 | LOG = logging.getLogger(__name__) |
12 | 17 | SYS_CLASS_NET = "/sys/class/net/" | 18 | SYS_CLASS_NET = "/sys/class/net/" |
13 | @@ -647,16 +648,36 @@ def get_ib_hwaddrs_by_interface(): | |||
14 | 647 | return ret | 648 | return ret |
15 | 648 | 649 | ||
16 | 649 | 650 | ||
17 | 651 | def has_url_connectivity(url): | ||
18 | 652 | """Return true when the instance has access to the provided URL | ||
19 | 653 | |||
20 | 654 | Logs a warning if url is not the expected format. | ||
21 | 655 | """ | ||
22 | 656 | if not any([url.startswith('http://'), url.startswith('https://')]): | ||
23 | 657 | LOG.warning( | ||
24 | 658 | "Ignoring connectivity check. Expected URL beginning with http*://" | ||
25 | 659 | " received '%s'", url) | ||
26 | 660 | return False | ||
27 | 661 | try: | ||
28 | 662 | readurl(url, timeout=5) | ||
29 | 663 | except UrlError: | ||
30 | 664 | return False | ||
31 | 665 | return True | ||
32 | 666 | |||
33 | 667 | |||
34 | 650 | class EphemeralIPv4Network(object): | 668 | class EphemeralIPv4Network(object): |
35 | 651 | """Context manager which sets up temporary static network configuration. | 669 | """Context manager which sets up temporary static network configuration. |
36 | 652 | 670 | ||
38 | 653 | No operations are performed if the provided interface is already connected. | 671 | No operations are performed if the provided interface already has the |
39 | 672 | specified configuration. | ||
40 | 673 | This can be verified with the connectivity_url. | ||
41 | 654 | If unconnected, bring up the interface with valid ip, prefix and broadcast. | 674 | If unconnected, bring up the interface with valid ip, prefix and broadcast. |
42 | 655 | If router is provided setup a default route for that interface. Upon | 675 | If router is provided setup a default route for that interface. Upon |
43 | 656 | context exit, clean up the interface leaving no configuration behind. | 676 | context exit, clean up the interface leaving no configuration behind. |
44 | 657 | """ | 677 | """ |
45 | 658 | 678 | ||
47 | 659 | def __init__(self, interface, ip, prefix_or_mask, broadcast, router=None): | 679 | def __init__(self, interface, ip, prefix_or_mask, broadcast, router=None, |
48 | 680 | connectivity_url=None): | ||
49 | 660 | """Setup context manager and validate call signature. | 681 | """Setup context manager and validate call signature. |
50 | 661 | 682 | ||
51 | 662 | @param interface: Name of the network interface to bring up. | 683 | @param interface: Name of the network interface to bring up. |
52 | @@ -665,6 +686,8 @@ class EphemeralIPv4Network(object): | |||
53 | 665 | prefix. | 686 | prefix. |
54 | 666 | @param broadcast: Broadcast address for the IPv4 network. | 687 | @param broadcast: Broadcast address for the IPv4 network. |
55 | 667 | @param router: Optionally the default gateway IP. | 688 | @param router: Optionally the default gateway IP. |
56 | 689 | @param connectivity_url: Optionally, a URL to verify if a usable | ||
57 | 690 | connection already exists. | ||
58 | 668 | """ | 691 | """ |
59 | 669 | if not all([interface, ip, prefix_or_mask, broadcast]): | 692 | if not all([interface, ip, prefix_or_mask, broadcast]): |
60 | 670 | raise ValueError( | 693 | raise ValueError( |
61 | @@ -675,6 +698,8 @@ class EphemeralIPv4Network(object): | |||
62 | 675 | except ValueError as e: | 698 | except ValueError as e: |
63 | 676 | raise ValueError( | 699 | raise ValueError( |
64 | 677 | 'Cannot setup network: {0}'.format(e)) | 700 | 'Cannot setup network: {0}'.format(e)) |
65 | 701 | |||
66 | 702 | self.connectivity_url = connectivity_url | ||
67 | 678 | self.interface = interface | 703 | self.interface = interface |
68 | 679 | self.ip = ip | 704 | self.ip = ip |
69 | 680 | self.broadcast = broadcast | 705 | self.broadcast = broadcast |
70 | @@ -683,6 +708,13 @@ class EphemeralIPv4Network(object): | |||
71 | 683 | 708 | ||
72 | 684 | def __enter__(self): | 709 | def __enter__(self): |
73 | 685 | """Perform ephemeral network setup if interface is not connected.""" | 710 | """Perform ephemeral network setup if interface is not connected.""" |
74 | 711 | if self.connectivity_url: | ||
75 | 712 | if has_url_connectivity(self.connectivity_url): | ||
76 | 713 | LOG.debug( | ||
77 | 714 | 'Skip ephemeral network setup, instance has connectivity' | ||
78 | 715 | ' to %s', self.connectivity_url) | ||
79 | 716 | return | ||
80 | 717 | |||
81 | 686 | self._bringup_device() | 718 | self._bringup_device() |
82 | 687 | if self.router: | 719 | if self.router: |
83 | 688 | self._bringup_router() | 720 | self._bringup_router() |
84 | diff --git a/cloudinit/net/dhcp.py b/cloudinit/net/dhcp.py | |||
85 | index bdc5799..0db991d 100644 | |||
86 | --- a/cloudinit/net/dhcp.py | |||
87 | +++ b/cloudinit/net/dhcp.py | |||
88 | @@ -11,7 +11,8 @@ import re | |||
89 | 11 | import signal | 11 | import signal |
90 | 12 | 12 | ||
91 | 13 | from cloudinit.net import ( | 13 | from cloudinit.net import ( |
93 | 14 | EphemeralIPv4Network, find_fallback_nic, get_devicelist) | 14 | EphemeralIPv4Network, find_fallback_nic, get_devicelist, |
94 | 15 | has_url_connectivity) | ||
95 | 15 | from cloudinit.net.network_state import mask_and_ipv4_to_bcast_addr as bcip | 16 | from cloudinit.net.network_state import mask_and_ipv4_to_bcast_addr as bcip |
96 | 16 | from cloudinit import temp_utils | 17 | from cloudinit import temp_utils |
97 | 17 | from cloudinit import util | 18 | from cloudinit import util |
98 | @@ -37,13 +38,21 @@ class NoDHCPLeaseError(Exception): | |||
99 | 37 | 38 | ||
100 | 38 | 39 | ||
101 | 39 | class EphemeralDHCPv4(object): | 40 | class EphemeralDHCPv4(object): |
103 | 40 | def __init__(self, iface=None): | 41 | def __init__(self, iface=None, connectivity_url=None): |
104 | 41 | self.iface = iface | 42 | self.iface = iface |
105 | 42 | self._ephipv4 = None | 43 | self._ephipv4 = None |
106 | 43 | self.lease = None | 44 | self.lease = None |
107 | 45 | self.connectivity_url = connectivity_url | ||
108 | 44 | 46 | ||
109 | 45 | def __enter__(self): | 47 | def __enter__(self): |
111 | 46 | """Setup sandboxed dhcp context.""" | 48 | """Setup sandboxed dhcp context, unless connectivity_url can already be |
112 | 49 | reached.""" | ||
113 | 50 | if self.connectivity_url: | ||
114 | 51 | if has_url_connectivity(self.connectivity_url): | ||
115 | 52 | LOG.debug( | ||
116 | 53 | 'Skip ephemeral DHCP setup, instance has connectivity' | ||
117 | 54 | ' to %s', self.connectivity_url) | ||
118 | 55 | return | ||
119 | 47 | return self.obtain_lease() | 56 | return self.obtain_lease() |
120 | 48 | 57 | ||
121 | 49 | def __exit__(self, excp_type, excp_value, excp_traceback): | 58 | def __exit__(self, excp_type, excp_value, excp_traceback): |
122 | @@ -86,6 +95,8 @@ class EphemeralDHCPv4(object): | |||
123 | 86 | kwargs = dict([(k, self.lease.get(v)) for k, v in nmap.items()]) | 95 | kwargs = dict([(k, self.lease.get(v)) for k, v in nmap.items()]) |
124 | 87 | if not kwargs['broadcast']: | 96 | if not kwargs['broadcast']: |
125 | 88 | kwargs['broadcast'] = bcip(kwargs['prefix_or_mask'], kwargs['ip']) | 97 | kwargs['broadcast'] = bcip(kwargs['prefix_or_mask'], kwargs['ip']) |
126 | 98 | if self.connectivity_url: | ||
127 | 99 | kwargs['connectivity_url'] = self.connectivity_url | ||
128 | 89 | ephipv4 = EphemeralIPv4Network(**kwargs) | 100 | ephipv4 = EphemeralIPv4Network(**kwargs) |
129 | 90 | ephipv4.__enter__() | 101 | ephipv4.__enter__() |
130 | 91 | self._ephipv4 = ephipv4 | 102 | self._ephipv4 = ephipv4 |
131 | diff --git a/cloudinit/net/tests/test_dhcp.py b/cloudinit/net/tests/test_dhcp.py | |||
132 | index db25b6f..cd3e732 100644 | |||
133 | --- a/cloudinit/net/tests/test_dhcp.py | |||
134 | +++ b/cloudinit/net/tests/test_dhcp.py | |||
135 | @@ -1,15 +1,17 @@ | |||
136 | 1 | # This file is part of cloud-init. See LICENSE file for license information. | 1 | # This file is part of cloud-init. See LICENSE file for license information. |
137 | 2 | 2 | ||
138 | 3 | import httpretty | ||
139 | 3 | import os | 4 | import os |
140 | 4 | import signal | 5 | import signal |
141 | 5 | from textwrap import dedent | 6 | from textwrap import dedent |
142 | 6 | 7 | ||
143 | 8 | import cloudinit.net as net | ||
144 | 7 | from cloudinit.net.dhcp import ( | 9 | from cloudinit.net.dhcp import ( |
145 | 8 | InvalidDHCPLeaseFileError, maybe_perform_dhcp_discovery, | 10 | InvalidDHCPLeaseFileError, maybe_perform_dhcp_discovery, |
146 | 9 | parse_dhcp_lease_file, dhcp_discovery, networkd_load_leases) | 11 | parse_dhcp_lease_file, dhcp_discovery, networkd_load_leases) |
147 | 10 | from cloudinit.util import ensure_file, write_file | 12 | from cloudinit.util import ensure_file, write_file |
148 | 11 | from cloudinit.tests.helpers import ( | 13 | from cloudinit.tests.helpers import ( |
150 | 12 | CiTestCase, mock, populate_dir, wrap_and_call) | 14 | CiTestCase, HttprettyTestCase, mock, populate_dir, wrap_and_call) |
151 | 13 | 15 | ||
152 | 14 | 16 | ||
153 | 15 | class TestParseDHCPLeasesFile(CiTestCase): | 17 | class TestParseDHCPLeasesFile(CiTestCase): |
154 | @@ -321,3 +323,35 @@ class TestSystemdParseLeases(CiTestCase): | |||
155 | 321 | '9': self.lxd_lease}) | 323 | '9': self.lxd_lease}) |
156 | 322 | self.assertEqual({'1': self.azure_parsed, '9': self.lxd_parsed}, | 324 | self.assertEqual({'1': self.azure_parsed, '9': self.lxd_parsed}, |
157 | 323 | networkd_load_leases(self.lease_d)) | 325 | networkd_load_leases(self.lease_d)) |
158 | 326 | |||
159 | 327 | |||
160 | 328 | class TestEphemeralDhcpNoNetworkSetup(HttprettyTestCase): | ||
161 | 329 | |||
162 | 330 | @mock.patch('cloudinit.net.dhcp.maybe_perform_dhcp_discovery') | ||
163 | 331 | def test_ephemeral_dhcp_no_network_if_url_connectivity(self, m_dhcp): | ||
164 | 332 | """No EphemeralDhcp4 network setup when connectivity_url succeeds.""" | ||
165 | 333 | url = 'http://example.org/index.html' | ||
166 | 334 | |||
167 | 335 | httpretty.register_uri(httpretty.GET, url) | ||
168 | 336 | with net.dhcp.EphemeralDHCPv4(connectivity_url=url) as lease: | ||
169 | 337 | self.assertIsNone(lease) | ||
170 | 338 | # Ensure that no teardown happens: | ||
171 | 339 | m_dhcp.assert_not_called() | ||
172 | 340 | |||
173 | 341 | @mock.patch('cloudinit.net.dhcp.util.subp') | ||
174 | 342 | @mock.patch('cloudinit.net.dhcp.maybe_perform_dhcp_discovery') | ||
175 | 343 | def test_ephemeral_dhcp_setup_network_if_url_connectivity( | ||
176 | 344 | self, m_dhcp, m_subp): | ||
177 | 345 | """No EphemeralDhcp4 network setup when connectivity_url succeeds.""" | ||
178 | 346 | url = 'http://example.org/index.html' | ||
179 | 347 | fake_lease = { | ||
180 | 348 | 'interface': 'eth9', 'fixed-address': '192.168.2.2', | ||
181 | 349 | 'subnet-mask': '255.255.0.0'} | ||
182 | 350 | m_dhcp.return_value = [fake_lease] | ||
183 | 351 | m_subp.return_value = ('', '') | ||
184 | 352 | |||
185 | 353 | httpretty.register_uri(httpretty.GET, url, body={}, status=404) | ||
186 | 354 | with net.dhcp.EphemeralDHCPv4(connectivity_url=url) as lease: | ||
187 | 355 | self.assertEqual(fake_lease, lease) | ||
188 | 356 | # Ensure that dhcp discovery occurs | ||
189 | 357 | m_dhcp.called_once_with() | ||
190 | diff --git a/cloudinit/net/tests/test_init.py b/cloudinit/net/tests/test_init.py | |||
191 | index 58e0a59..f55c31e 100644 | |||
192 | --- a/cloudinit/net/tests/test_init.py | |||
193 | +++ b/cloudinit/net/tests/test_init.py | |||
194 | @@ -2,14 +2,16 @@ | |||
195 | 2 | 2 | ||
196 | 3 | import copy | 3 | import copy |
197 | 4 | import errno | 4 | import errno |
198 | 5 | import httpretty | ||
199 | 5 | import mock | 6 | import mock |
200 | 6 | import os | 7 | import os |
201 | 8 | import requests | ||
202 | 7 | import textwrap | 9 | import textwrap |
203 | 8 | import yaml | 10 | import yaml |
204 | 9 | 11 | ||
205 | 10 | import cloudinit.net as net | 12 | import cloudinit.net as net |
206 | 11 | from cloudinit.util import ensure_file, write_file, ProcessExecutionError | 13 | from cloudinit.util import ensure_file, write_file, ProcessExecutionError |
208 | 12 | from cloudinit.tests.helpers import CiTestCase | 14 | from cloudinit.tests.helpers import CiTestCase, HttprettyTestCase |
209 | 13 | 15 | ||
210 | 14 | 16 | ||
211 | 15 | class TestSysDevPath(CiTestCase): | 17 | class TestSysDevPath(CiTestCase): |
212 | @@ -458,6 +460,22 @@ class TestEphemeralIPV4Network(CiTestCase): | |||
213 | 458 | self.assertEqual(expected_setup_calls, m_subp.call_args_list) | 460 | self.assertEqual(expected_setup_calls, m_subp.call_args_list) |
214 | 459 | m_subp.assert_has_calls(expected_teardown_calls) | 461 | m_subp.assert_has_calls(expected_teardown_calls) |
215 | 460 | 462 | ||
216 | 463 | @mock.patch('cloudinit.net.readurl') | ||
217 | 464 | def test_ephemeral_ipv4_no_network_if_url_connectivity( | ||
218 | 465 | self, m_readurl, m_subp): | ||
219 | 466 | """No network setup is performed if we can successfully connect to | ||
220 | 467 | connectivity_url.""" | ||
221 | 468 | params = { | ||
222 | 469 | 'interface': 'eth0', 'ip': '192.168.2.2', | ||
223 | 470 | 'prefix_or_mask': '255.255.255.0', 'broadcast': '192.168.2.255', | ||
224 | 471 | 'connectivity_url': 'http://example.org/index.html'} | ||
225 | 472 | |||
226 | 473 | with net.EphemeralIPv4Network(**params): | ||
227 | 474 | self.assertEqual([mock.call('http://example.org/index.html', | ||
228 | 475 | timeout=5)], m_readurl.call_args_list) | ||
229 | 476 | # Ensure that no teardown happens: | ||
230 | 477 | m_subp.assert_has_calls([]) | ||
231 | 478 | |||
232 | 461 | def test_ephemeral_ipv4_network_noop_when_configured(self, m_subp): | 479 | def test_ephemeral_ipv4_network_noop_when_configured(self, m_subp): |
233 | 462 | """EphemeralIPv4Network handles exception when address is setup. | 480 | """EphemeralIPv4Network handles exception when address is setup. |
234 | 463 | 481 | ||
235 | @@ -619,3 +637,35 @@ class TestApplyNetworkCfgNames(CiTestCase): | |||
236 | 619 | def test_apply_v2_renames_raises_runtime_error_on_unknown_version(self): | 637 | def test_apply_v2_renames_raises_runtime_error_on_unknown_version(self): |
237 | 620 | with self.assertRaises(RuntimeError): | 638 | with self.assertRaises(RuntimeError): |
238 | 621 | net.apply_network_config_names(yaml.load("version: 3")) | 639 | net.apply_network_config_names(yaml.load("version: 3")) |
239 | 640 | |||
240 | 641 | |||
241 | 642 | class TestHasURLConnectivity(HttprettyTestCase): | ||
242 | 643 | |||
243 | 644 | def setUp(self): | ||
244 | 645 | super(TestHasURLConnectivity, self).setUp() | ||
245 | 646 | self.url = 'http://fake/' | ||
246 | 647 | self.kwargs = {'allow_redirects': True, 'timeout': 5.0} | ||
247 | 648 | |||
248 | 649 | @mock.patch('cloudinit.net.readurl') | ||
249 | 650 | def test_url_timeout_on_connectivity_check(self, m_readurl): | ||
250 | 651 | """A timeout of 5 seconds is provided when reading a url.""" | ||
251 | 652 | self.assertTrue( | ||
252 | 653 | net.has_url_connectivity(self.url), 'Expected True on url connect') | ||
253 | 654 | |||
254 | 655 | def test_true_on_url_connectivity_success(self): | ||
255 | 656 | httpretty.register_uri(httpretty.GET, self.url) | ||
256 | 657 | self.assertTrue( | ||
257 | 658 | net.has_url_connectivity(self.url), 'Expected True on url connect') | ||
258 | 659 | |||
259 | 660 | @mock.patch('requests.Session.request') | ||
260 | 661 | def test_true_on_url_connectivity_timeout(self, m_request): | ||
261 | 662 | """A timeout raised accessing the url will return False.""" | ||
262 | 663 | m_request.side_effect = requests.Timeout('Fake Connection Timeout') | ||
263 | 664 | self.assertFalse( | ||
264 | 665 | net.has_url_connectivity(self.url), | ||
265 | 666 | 'Expected False on url timeout') | ||
266 | 667 | |||
267 | 668 | def test_true_on_url_connectivity_failure(self): | ||
268 | 669 | httpretty.register_uri(httpretty.GET, self.url, body={}, status=404) | ||
269 | 670 | self.assertFalse( | ||
270 | 671 | net.has_url_connectivity(self.url), 'Expected False on url fail') |
FAILED: Continuous integration, rev:3f711fd9cbd e2e4fb62a02d019 e21770dd3e242c /code.launchpad .net/~i. galic/cloud- init/+git/ cloud-init/ +merge/ 358876/ +edit-commit- message
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
https:/ /jenkins. ubuntu. com/server/ job/cloud- init-ci/ 446/
Executed test runs:
SUCCESS: Checkout
FAILED: Unit & Style Tests
Click here to trigger a rebuild: /jenkins. ubuntu. com/server/ job/cloud- init-ci/ 446/rebuild
https:/