Browse Source

Wait up to 30 seconds until network link is UP

Network checker must wait up to 30 seconds for
network link readiness, because by default all
non-admin interfaces are turned off on slaves
in 'discover' state.

Change-Id: Idfdab5e81182c95836b40e460106f1e775658cf8
Closes-bug: #1529985
Artem Panchenko 3 years ago
parent
commit
0589710474

+ 18
- 0
network_checker/consts.py View File

@@ -0,0 +1,18 @@
1
+#    Copyright 2016 Mirantis, Inc.
2
+#
3
+#    This program is free software; you can redistribute it and/or modify
4
+#    it under the terms of the GNU General Public License as published by
5
+#    the Free Software Foundation; either version 2 of the License, or
6
+#    (at your option) any later version.
7
+#
8
+#    This program is distributed in the hope that it will be useful,
9
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
+#    GNU General Public License for more details.
12
+#
13
+#    You should have received a copy of the GNU General Public License along
14
+#    with this program; if not, write to the Free Software Foundation, Inc.,
15
+#    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
+
17
+# seconds to wait for link protocol is up after network interface enabling
18
+LINK_UP_TIMEOUT = 30

+ 24
- 0
network_checker/net_check/api.py View File

@@ -46,6 +46,7 @@ from scapy import error
46 46
 
47 47
 from scapy.utils import PcapReader
48 48
 
49
+from network_checker import consts
49 50
 from network_checker.net_check.utils import signal_timeout
50 51
 
51 52
 
@@ -191,6 +192,11 @@ class Actor(object):
191 192
             "dev", set_iface,
192 193
             "up"])
193 194
 
195
+    def _check_iface_ready(self, iface, vid=None):
196
+        check_iface = self._iface_name(iface, vid)
197
+        output = self._execute(['ip', '-o', 'link', 'show', check_iface])
198
+        return 'state UP' in '\n'.join(output)
199
+
194 200
     def _ensure_iface_up(self, iface, vid=None):
195 201
         """Ensures interface is with vid up."""
196 202
         if not self._try_iface_up(iface, vid):
@@ -208,6 +214,21 @@ class Actor(object):
208 214
                                                                    str(vid))
209 215
                 )
210 216
 
217
+    def _ensure_iface_ready(self, iface, vid=None):
218
+        self.logger.debug('Waiting %s seconds for %s interface (VLAN %s) '
219
+                          'is UP...', consts.LINK_UP_TIMEOUT, iface, vid)
220
+        deadline = time.time() + consts.LINK_UP_TIMEOUT
221
+        while time.time() < deadline:
222
+            if self._check_iface_ready(iface, vid):
223
+                self.logger.debug('Interface %s (VLAN %s) is UP', iface, vid)
224
+                return
225
+            time.sleep(1)
226
+        raise ActorException(
227
+            self.logger,
228
+            "Link protocol on interface %s with vid %s isn't UP" % (iface,
229
+                                                                    str(vid))
230
+        )
231
+
211 232
     def _ensure_iface_down(self, iface, vid=None):
212 233
         set_iface = self._iface_name(iface, vid)
213 234
         if self.iface_down_after.get(set_iface, False):
@@ -315,6 +336,7 @@ class Actor(object):
315 336
     def _ensure_viface_create_and_up(self, iface, vid):
316 337
         self._ensure_viface_create(iface, vid)
317 338
         self._ensure_iface_up(iface, vid)
339
+        self._ensure_iface_ready(iface, vid)
318 340
 
319 341
     def _ensure_viface_down_and_remove(self, iface, vid):
320 342
         self._ensure_iface_down(iface, vid)
@@ -366,6 +388,7 @@ class Sender(Actor):
366 388
     def _run(self):
367 389
         for iface, vlan in self._iface_vlan_iterator():
368 390
             self._ensure_iface_up(iface)
391
+            self._ensure_iface_ready(iface)
369 392
         self._send_packets()
370 393
         self._log_ifaces("Interfaces just after sending probing packages")
371 394
         for iface in self._iface_iterator():
@@ -441,6 +464,7 @@ class Listener(Actor):
441 464
 
442 465
         for iface in self._iface_iterator():
443 466
             self._ensure_iface_up(iface)
467
+            self._ensure_iface_ready(iface)
444 468
             if iface not in sniffers:
445 469
                 listeners.append(self.get_probe_frames(iface))
446 470
                 listeners.append(self.get_probe_frames(iface, vlan=True))

+ 18
- 0
url_access_checker/consts.py View File

@@ -0,0 +1,18 @@
1
+#    Copyright 2016 Mirantis, Inc.
2
+#
3
+#    This program is free software; you can redistribute it and/or modify
4
+#    it under the terms of the GNU General Public License as published by
5
+#    the Free Software Foundation; either version 2 of the License, or
6
+#    (at your option) any later version.
7
+#
8
+#    This program is distributed in the hope that it will be useful,
9
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
+#    GNU General Public License for more details.
12
+#
13
+#    You should have received a copy of the GNU General Public License along
14
+#    with this program; if not, write to the Free Software Foundation, Inc.,
15
+#    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
+
17
+# seconds to wait for link protocol is up after network interface enabling
18
+LINK_UP_TIMEOUT = 30

+ 17
- 0
url_access_checker/network.py View File

@@ -16,9 +16,11 @@
16 16
 
17 17
 from contextlib import contextmanager
18 18
 from logging import getLogger
19
+import time
19 20
 
20 21
 import netifaces
21 22
 
23
+from url_access_checker import consts
22 24
 from url_access_checker.errors import CommandFailed
23 25
 from url_access_checker.utils import execute
24 26
 
@@ -57,6 +59,11 @@ def check_up(iface):
57 59
     return 'UP' in stdout
58 60
 
59 61
 
62
+def check_ready(iface):
63
+    rc, stdout, _ = execute(['ip', '-o', 'link', 'show', iface])
64
+    return 'state UP' in stdout
65
+
66
+
60 67
 def log_network_info(stage):
61 68
     logger.info('Logging networking info at %s', stage)
62 69
     stdout = execute(['ip', 'a'])[1]
@@ -80,6 +87,16 @@ class Eth(object):
80 87
                 msg = 'Cannot up interface {0}. Err: {1}'.format(
81 88
                     self.iface, err)
82 89
                 raise CommandFailed(msg)
90
+        logger.info('Waiting %s seconds for %s interface is UP...',
91
+                    consts.LINK_UP_TIMEOUT, self.iface)
92
+        deadline = time.time() + consts.LINK_UP_TIMEOUT
93
+        while time.time() < deadline:
94
+            if check_ready(self.iface):
95
+                logger.info('Interface %s is UP', self.iface)
96
+                return
97
+            time.sleep(1)
98
+        raise CommandFailed('Link protocol on interface %s '
99
+                            'isn\'t UP'.format(self.iface))
83 100
 
84 101
     def teardown(self):
85 102
         if self.is_up is False:

+ 43
- 2
url_access_checker/tests/unit/test_with_network_setup.py View File

@@ -22,11 +22,15 @@ from mock import patch
22 22
 import netifaces
23 23
 
24 24
 from url_access_checker import cli
25
+from url_access_checker import consts
26
+from url_access_checker import errors
27
+from url_access_checker import network
25 28
 
26 29
 
27 30
 @patch('url_access_checker.network.execute')
28 31
 @patch('url_access_checker.network.netifaces.gateways')
29 32
 @patch('requests.get', Mock(status_code=200))
33
+@patch('url_access_checker.network.check_ready')
30 34
 @patch('url_access_checker.network.check_up')
31 35
 @patch('url_access_checker.network.check_exist')
32 36
 @patch('url_access_checker.network.check_ifaddress_present')
@@ -37,11 +41,13 @@ class TestVerificationWithNetworkSetup(unittest.TestCase):
37 41
         for expected, executed in zip(expected_items, received_items):
38 42
             self.assertEqual(expected, executed)
39 43
 
40
-    def test_verification_route(self, mifaddr, mexist, mup, mgat, mexecute):
44
+    def test_verification_route(self, mifaddr, mexist, mup, mready, mgat,
45
+                                mexecute):
41 46
         mexecute.return_value = (0, '', '')
42 47
         mup.return_value = True
43 48
         mexist.return_value = True
44 49
         mifaddr.return_value = False
50
+        mready.return_value = True
45 51
 
46 52
         default_gw, default_iface = '172.18.0.1', 'eth2'
47 53
         mgat.return_value = {
@@ -71,11 +77,13 @@ class TestVerificationWithNetworkSetup(unittest.TestCase):
71 77
 
72 78
         self.assert_by_items(mexecute.call_args_list, execute_stack)
73 79
 
74
-    def test_verification_vlan(self, mifaddr, mexist, mup, mgat, mexecute):
80
+    def test_verification_vlan(self, mifaddr, mexist, mup, mready, mgat,
81
+                               mexecute):
75 82
         mexecute.return_value = (0, '', '')
76 83
         mup.return_value = False
77 84
         mexist.return_value = False
78 85
         mifaddr.return_value = False
86
+        mready.return_value = True
79 87
 
80 88
         default_gw, default_iface = '172.18.0.1', 'eth2'
81 89
         mgat.return_value = {
@@ -114,3 +122,36 @@ class TestVerificationWithNetworkSetup(unittest.TestCase):
114 122
             call(['ip', 'ro'])]
115 123
 
116 124
         self.assert_by_items(mexecute.call_args_list, execute_stack)
125
+
126
+
127
+@patch('url_access_checker.network.check_up')
128
+class TestInterafceSetup(unittest.TestCase):
129
+
130
+    def assert_raises_message(self, exc_type, msg, func, *args, **kwargs):
131
+        with self.assertRaises(exc_type) as e:
132
+            func(*args, **kwargs)
133
+        self.assertEqual(str(e.exception), msg)
134
+
135
+    @patch('url_access_checker.network.execute')
136
+    def test_interface_ready(self, mexecute, mup):
137
+        mexecute.return_value = (0, 'state UP', '')
138
+        mup.return_value = True
139
+
140
+        iface = 'eth1'
141
+        consts.LINK_UP_TIMEOUT = 1
142
+
143
+        self.assertTrue(network.check_ready(iface))
144
+
145
+    @patch('url_access_checker.network.check_ready')
146
+    def test_negative_interface_down(self, mready, mup):
147
+        mup.return_value = True
148
+        mready.return_value = False
149
+
150
+        iface = 'eth1'
151
+        consts.LINK_UP_TIMEOUT = 1
152
+
153
+        self.assert_raises_message(
154
+            errors.CommandFailed,
155
+            'Link protocol on interface %s isn\'t UP'.format(iface),
156
+            lambda: network.Eth(iface).setup()
157
+        )

Loading…
Cancel
Save