Set lock_path correctly.
[openstack-build/neutron-build.git] / neutron / tests / functional / agent / l2 / base.py
1 # Copyright (c) 2015 Red Hat, Inc.
2 # Copyright (c) 2015 SUSE Linux Products GmbH
3 # All Rights Reserved.
4 #
5 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
6 #    not use this file except in compliance with the License. You may obtain
7 #    a copy of the License at
8 #
9 #         http://www.apache.org/licenses/LICENSE-2.0
10 #
11 #    Unless required by applicable law or agreed to in writing, software
12 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 #    License for the specific language governing permissions and limitations
15 #    under the License.
16
17 import random
18
19 import eventlet
20 import mock
21 from oslo_config import cfg
22 from oslo_utils import uuidutils
23
24 from neutron.agent.common import config as agent_config
25 from neutron.agent.common import ovs_lib
26 from neutron.agent.l2.extensions import manager as ext_manager
27 from neutron.agent.linux import interface
28 from neutron.agent.linux import polling
29 from neutron.agent.linux import utils as agent_utils
30 from neutron.common import config as common_config
31 from neutron.common import constants as n_const
32 from neutron.common import utils
33 from neutron.plugins.common import constants as p_const
34 from neutron.plugins.ml2.drivers.openvswitch.agent.common import config \
35     as ovs_config
36 from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants
37 from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \
38     import br_int
39 from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \
40     import br_phys
41 from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \
42     import br_tun
43 from neutron.plugins.ml2.drivers.openvswitch.agent import ovs_neutron_agent \
44     as ovs_agent
45 from neutron.tests.common import net_helpers
46 from neutron.tests.functional.agent.linux import base
47
48
49 class OVSAgentTestFramework(base.BaseOVSLinuxTestCase):
50
51     def setUp(self):
52         super(OVSAgentTestFramework, self).setUp()
53         agent_rpc = ('neutron.plugins.ml2.drivers.openvswitch.agent.'
54                      'ovs_neutron_agent.OVSPluginApi')
55         mock.patch(agent_rpc).start()
56         mock.patch('neutron.agent.rpc.PluginReportStateAPI').start()
57         self.br_int = base.get_rand_name(n_const.DEVICE_NAME_MAX_LEN,
58                                          prefix='br-int')
59         self.br_tun = base.get_rand_name(n_const.DEVICE_NAME_MAX_LEN,
60                                          prefix='br-tun')
61         self.br_phys = base.get_rand_name(n_const.DEVICE_NAME_MAX_LEN,
62                                           prefix='br-phys')
63         patch_name_len = n_const.DEVICE_NAME_MAX_LEN - len("-patch-tun")
64         self.patch_tun = "%s-patch-tun" % self.br_int[patch_name_len:]
65         self.patch_int = "%s-patch-int" % self.br_tun[patch_name_len:]
66         self.ovs = ovs_lib.BaseOVS()
67         self.config = self._configure_agent()
68         self.driver = interface.OVSInterfaceDriver(self.config)
69         self.namespace = self.useFixture(net_helpers.NamespaceFixture()).name
70
71     def _get_config_opts(self):
72         config = cfg.ConfigOpts()
73         config.register_opts(common_config.core_opts)
74         config.register_opts(interface.OPTS)
75         config.register_opts(ovs_config.ovs_opts, "OVS")
76         config.register_opts(ovs_config.agent_opts, "AGENT")
77         agent_config.register_interface_driver_opts_helper(config)
78         agent_config.register_agent_state_opts_helper(config)
79         ext_manager.register_opts(config)
80         return config
81
82     def _configure_agent(self):
83         config = self._get_config_opts()
84         config.set_override(
85             'interface_driver',
86             'neutron.agent.linux.interface.OVSInterfaceDriver')
87         config.set_override('integration_bridge', self.br_int, "OVS")
88         config.set_override('ovs_integration_bridge', self.br_int)
89         config.set_override('tunnel_bridge', self.br_tun, "OVS")
90         config.set_override('int_peer_patch_port', self.patch_tun, "OVS")
91         config.set_override('tun_peer_patch_port', self.patch_int, "OVS")
92         config.set_override('host', 'ovs-agent')
93         return config
94
95     def _bridge_classes(self):
96         return {
97             'br_int': br_int.OVSIntegrationBridge,
98             'br_phys': br_phys.OVSPhysicalBridge,
99             'br_tun': br_tun.OVSTunnelBridge
100         }
101
102     def create_agent(self, create_tunnels=True):
103         if create_tunnels:
104             tunnel_types = [p_const.TYPE_VXLAN]
105         else:
106             tunnel_types = None
107         bridge_mappings = ['physnet:%s' % self.br_phys]
108         self.config.set_override('tunnel_types', tunnel_types, "AGENT")
109         self.config.set_override('polling_interval', 1, "AGENT")
110         self.config.set_override('prevent_arp_spoofing', False, "AGENT")
111         self.config.set_override('local_ip', '192.168.10.1', "OVS")
112         self.config.set_override('bridge_mappings', bridge_mappings, "OVS")
113         # Physical bridges should be created prior to running
114         self._bridge_classes()['br_phys'](self.br_phys).create()
115         agent = ovs_agent.OVSNeutronAgent(self._bridge_classes(),
116                                           self.config)
117         self.addCleanup(self.ovs.delete_bridge, self.br_int)
118         if tunnel_types:
119             self.addCleanup(self.ovs.delete_bridge, self.br_tun)
120         self.addCleanup(self.ovs.delete_bridge, self.br_phys)
121         agent.sg_agent = mock.Mock()
122         agent.ancillary_brs = []
123         return agent
124
125     def _mock_get_events(self, agent, polling_manager, ports):
126         get_events = polling_manager.get_events
127         p_ids = [p['id'] for p in ports]
128
129         def filter_events():
130             events = get_events()
131             filtered_ports = []
132             for dev in events['added']:
133                 iface_id = agent.int_br.portid_from_external_ids(
134                     dev.get('external_ids', []))
135                 if iface_id in p_ids:
136                     # if the event is not about a port that was created by
137                     # this test, we filter the event out. Since these tests are
138                     # not run in isolation processing all the events might make
139                     # some test fail ( e.g. the agent might keep resycing
140                     # because it keeps finding not ready ports that are created
141                     # by other tests)
142                     filtered_ports.append(dev)
143             return {'added': filtered_ports, 'removed': events['removed']}
144         polling_manager.get_events = mock.Mock(side_effect=filter_events)
145
146     def start_agent(self, agent, ports=None, unplug_ports=None):
147         if unplug_ports is None:
148             unplug_ports = []
149         if ports is None:
150             ports = []
151         self.setup_agent_rpc_mocks(agent, unplug_ports)
152         polling_manager = polling.InterfacePollingMinimizer()
153         self._mock_get_events(agent, polling_manager, ports)
154         self.addCleanup(polling_manager.stop)
155         polling_manager.start()
156         agent_utils.wait_until_true(
157             polling_manager._monitor.is_active)
158         agent.check_ovs_status = mock.Mock(
159             return_value=constants.OVS_NORMAL)
160         t = eventlet.spawn(agent.rpc_loop, polling_manager)
161
162         def stop_agent(agent, rpc_loop_thread):
163             agent.run_daemon_loop = False
164             rpc_loop_thread.wait()
165
166         self.addCleanup(stop_agent, agent, t)
167         return polling_manager
168
169     def _create_test_port_dict(self):
170         return {'id': uuidutils.generate_uuid(),
171                 'mac_address': utils.get_random_mac(
172                     'fa:16:3e:00:00:00'.split(':')),
173                 'fixed_ips': [{
174                     'ip_address': '10.%d.%d.%d' % (
175                          random.randint(3, 254),
176                          random.randint(3, 254),
177                          random.randint(3, 254))}],
178                 'vif_name': base.get_rand_name(
179                     self.driver.DEV_NAME_LEN, self.driver.DEV_NAME_PREFIX)}
180
181     def _create_test_network_dict(self):
182         return {'id': uuidutils.generate_uuid(),
183                 'tenant_id': uuidutils.generate_uuid()}
184
185     def _plug_ports(self, network, ports, agent, ip_len=24):
186         for port in ports:
187             self.driver.plug(
188                 network.get('id'), port.get('id'), port.get('vif_name'),
189                 port.get('mac_address'),
190                 agent.int_br.br_name, namespace=self.namespace)
191             ip_cidrs = ["%s/%s" % (port.get('fixed_ips')[0][
192                 'ip_address'], ip_len)]
193             self.driver.init_l3(port.get('vif_name'), ip_cidrs,
194                                 namespace=self.namespace)
195
196     def _unplug_ports(self, ports, agent):
197         for port in ports:
198             self.driver.unplug(
199                 port.get('vif_name'), agent.int_br.br_name, self.namespace)
200
201     def _get_device_details(self, port, network):
202         dev = {'device': port['id'],
203                'port_id': port['id'],
204                'network_id': network['id'],
205                'network_type': 'vlan',
206                'physical_network': 'physnet',
207                'segmentation_id': 1,
208                'fixed_ips': port['fixed_ips'],
209                'device_owner': 'compute',
210                'port_security_enabled': True,
211                'security_groups': ['default'],
212                'admin_state_up': True}
213         return dev
214
215     def assert_bridge(self, br, exists=True):
216         self.assertEqual(exists, self.ovs.bridge_exists(br))
217
218     def assert_patch_ports(self, agent):
219
220         def get_peer(port):
221             return agent.int_br.db_get_val(
222                 'Interface', port, 'options', check_error=True)
223
224         agent_utils.wait_until_true(
225             lambda: get_peer(self.patch_int) == {'peer': self.patch_tun})
226         agent_utils.wait_until_true(
227             lambda: get_peer(self.patch_tun) == {'peer': self.patch_int})
228
229     def assert_bridge_ports(self):
230         for port in [self.patch_tun, self.patch_int]:
231             self.assertTrue(self.ovs.port_exists(port))
232
233     def assert_vlan_tags(self, ports, agent):
234         for port in ports:
235             res = agent.int_br.db_get_val('Port', port.get('vif_name'), 'tag')
236             self.assertTrue(res)
237
238     def _expected_plugin_rpc_call(self, call, expected_devices, is_up=True):
239         """Helper to check expected rpc call are received
240
241         :param call: The call to check
242         :param expected_devices: The device for which call is expected
243         :param is_up: True if expected_devices are devices that are set up,
244                False if expected_devices are devices that are set down
245         """
246         if is_up:
247             rpc_devices = [
248                 dev for args in call.call_args_list for dev in args[0][1]]
249         else:
250             rpc_devices = [
251                 dev for args in call.call_args_list for dev in args[0][2]]
252         return not (set(expected_devices) - set(rpc_devices))
253
254     def create_test_ports(self, amount=3, **kwargs):
255         ports = []
256         for x in range(amount):
257             ports.append(self._create_test_port_dict(**kwargs))
258         return ports
259
260     def _mock_update_device(self, context, devices_up, devices_down, agent_id,
261                             host=None):
262         dev_up = []
263         dev_down = []
264         for port in self.ports:
265             if devices_up and port['id'] in devices_up:
266                 dev_up.append(port['id'])
267             if devices_down and port['id'] in devices_down:
268                 dev_down.append({'device': port['id'], 'exists': True})
269         return {'devices_up': dev_up,
270                 'failed_devices_up': [],
271                 'devices_down': dev_down,
272                 'failed_devices_down': []}
273
274     def setup_agent_rpc_mocks(self, agent, unplug_ports):
275         def mock_device_details(context, devices, agent_id, host=None):
276             details = []
277             for port in self.ports:
278                 if port['id'] in devices:
279                     dev = self._get_device_details(
280                         port, self.network)
281                     details.append(dev)
282             ports_to_unplug = [x for x in unplug_ports if x['id'] in devices]
283             if ports_to_unplug:
284                 self._unplug_ports(ports_to_unplug, self.agent)
285             return {'devices': details, 'failed_devices': []}
286
287         (agent.plugin_rpc.get_devices_details_list_and_failed_devices.
288             side_effect) = mock_device_details
289         agent.plugin_rpc.update_device_list.side_effect = (
290             self._mock_update_device)
291
292     def _prepare_resync_trigger(self, agent):
293         def mock_device_raise_exception(context, devices_up, devices_down,
294                                         agent_id, host=None):
295             agent.plugin_rpc.update_device_list.side_effect = (
296                 self._mock_update_device)
297             raise Exception('Exception to trigger resync')
298
299         self.agent.plugin_rpc.update_device_list.side_effect = (
300             mock_device_raise_exception)
301
302     def wait_until_ports_state(self, ports, up, timeout=60):
303         port_ids = [p['id'] for p in ports]
304         agent_utils.wait_until_true(
305             lambda: self._expected_plugin_rpc_call(
306                 self.agent.plugin_rpc.update_device_list, port_ids, up),
307             timeout=timeout)
308
309     def setup_agent_and_ports(self, port_dicts, create_tunnels=True,
310                               trigger_resync=False):
311         self.ports = port_dicts
312         self.agent = self.create_agent(create_tunnels=create_tunnels)
313         self.polling_manager = self.start_agent(self.agent, ports=self.ports)
314         self.network = self._create_test_network_dict()
315         if trigger_resync:
316             self._prepare_resync_trigger(self.agent)
317         self._plug_ports(self.network, self.ports, self.agent)