Ovs agent can't start on Windows because of validate_local_ip

Change I4b4527c28d0738890e33b343c9e17941e780bc24 introduced a
validate_local_ip sanity check for the local_ip to see that it
belongs to the host.

This method uses linux specific implementation that fails on windows.

This patch fixes this bug by adding a implementation for
validate_local_ip that works on windows as well, using netifaces.

Change-Id: Ia8299512687d9d7135fe013fbb38f2b28d54125d
Closes-Bug: #1497940
This commit is contained in:
Adelina Tuvenie 2015-09-23 17:59:11 -07:00
parent c6ab89aee3
commit 371e8aa076
9 changed files with 211 additions and 2 deletions

View File

@ -0,0 +1,27 @@
# Copyright 2016 Cloudbase Solutions.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import os
if os.name == 'nt':
from neutron.agent.windows import ip_lib
else:
from neutron.agent.linux import ip_lib
OPTS = ip_lib.OPTS
IPWrapper = ip_lib.IPWrapper
IPDevice = ip_lib.IPDevice

View File

@ -0,0 +1,59 @@
# Copyright 2016 Cloudbase Solutions.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import netifaces
from oslo_log import log as logging
from neutron._i18n import _LE
LOG = logging.getLogger(__name__)
OPTS = []
class IPWrapper(object):
def get_device_by_ip(self, ip):
if not ip:
return
for device in self.get_devices():
if device.device_has_ip(ip):
return device
def get_devices(self):
try:
return [IPDevice(iface) for iface in netifaces.interfaces()]
except (OSError, MemoryError):
LOG.error(_LE("Failed to get network interfaces."))
return []
class IPDevice(object):
def __init__(self, name):
self.device_name = name
def device_has_ip(self, ip):
try:
addresses = [ip_addr['addr'] for ip_addr in
netifaces.ifaddresses(self.device_name).get(
netifaces.AF_INET, [])]
return ip in addresses
except OSError:
LOG.error(_LE("Failed to get ip addresses for interface: %s."),
self.device_name)
return False

View File

@ -29,11 +29,11 @@ import six
from six import moves
from neutron._i18n import _, _LE, _LI, _LW
from neutron.agent.common import ip_lib
from neutron.agent.common import ovs_lib
from neutron.agent.common import polling
from neutron.agent.common import utils
from neutron.agent.l2.extensions import manager as ext_manager
from neutron.agent.linux import ip_lib
from neutron.agent import rpc as agent_rpc
from neutron.agent import securitygroups_rpc as sg_rpc
from neutron.api.rpc.callbacks import resources

View File

@ -0,0 +1,30 @@
# Copyright 2016 Cloudbase Solutions.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutron.agent.windows import ip_lib
from neutron.tests import base
WRONG_IP = '0.0.0.0'
TEST_IP = '127.0.0.1'
class IpLibTestCase(base.BaseTestCase):
def test_ipwrapper_get_device_by_ip_None(self):
self.assertIsNone(ip_lib.IPWrapper().get_device_by_ip(WRONG_IP))
def test_ipwrapper_get_device_by_ip(self):
ip_dev = ip_lib.IPWrapper().get_device_by_ip(TEST_IP)
self.assertEqual('lo', ip_dev.device_name)

View File

@ -0,0 +1,92 @@
# Copyright 2016 Cloudbase Solutions.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
import netifaces
from neutron.agent.windows import ip_lib
from neutron.tests import base
class TestIpWrapper(base.BaseTestCase):
def test_get_device_by_ip_no_ip(self):
ret = ip_lib.IPWrapper().get_device_by_ip(None)
self.assertIsNone(ret)
@mock.patch.object(ip_lib.IPWrapper, 'get_devices')
def test_get_device_by_ip(self, mock_get_devices):
mock_dev1 = mock.MagicMock()
mock_dev2 = mock.MagicMock()
mock_dev1.device_has_ip.return_value = False
mock_dev2.device_has_ip.return_value = True
mock_get_devices.return_value = [mock_dev1, mock_dev2]
ret = ip_lib.IPWrapper().get_device_by_ip('fake_ip')
self.assertEqual(mock_dev2, ret)
@mock.patch.object(ip_lib.IPWrapper, 'get_devices')
def test_get_device_by_ip_exception(self, mock_get_devices):
mock_get_devices.side_effects = OSError
ret = ip_lib.IPWrapper().get_device_by_ip(mock.sentinel.fake_ip)
self.assertIsNone(ret)
@mock.patch('netifaces.interfaces')
def test_get_devices(self, mock_interfaces):
mock_interfaces.return_value = [mock.sentinel.dev1,
mock.sentinel.dev2]
ret = ip_lib.IPWrapper().get_devices()
self.assertEqual(mock.sentinel.dev1, ret[0].device_name)
self.assertEqual(mock.sentinel.dev2, ret[1].device_name)
@mock.patch('netifaces.interfaces')
def test_get_devices_error(self, mock_interfaces):
mock_interfaces.side_effects = OSError
ret = ip_lib.IPWrapper().get_devices()
self.assertEqual([], ret)
class TestIpDevice(base.BaseTestCase):
@mock.patch('netifaces.ifaddresses')
def test_device_has_ip(self, mock_netifaces):
mock_address = {'addr': mock.sentinel.fake_addr}
mock_netifaces.return_value = {netifaces.AF_INET: [mock_address]}
ret = ip_lib.IPDevice("fake_dev").device_has_ip(
mock.sentinel.fake_addr)
self.assertTrue(ret)
@mock.patch('netifaces.ifaddresses')
def test_device_has_ip_false(self, mock_netifaces):
mock_netifaces.return_value = {}
ret = ip_lib.IPDevice("fake_dev").device_has_ip(
mock.sentinel.fake_addr)
self.assertFalse(ret)
@mock.patch('netifaces.ifaddresses')
def test_device_has_ip_error(self, mock_netifaces):
mock_netifaces.side_effects = OSError
ret = ip_lib.IPDevice("fake_dev").device_has_ip(
mock.sentinel.fake_addr)
self.assertFalse(ret)

View File

@ -21,8 +21,8 @@ from oslo_config import cfg
from oslo_log import log
import six
from neutron.agent.common import ip_lib
from neutron.agent.common import ovs_lib
from neutron.agent.linux import ip_lib
from neutron.common import constants as n_const
from neutron.plugins.common import constants as p_const
from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants

View File

@ -16,6 +16,7 @@ requests!=2.9.0,>=2.8.1 # Apache-2.0
Jinja2>=2.8 # BSD License (3 clause)
keystonemiddleware!=4.1.0,>=4.0.0 # Apache-2.0
netaddr!=0.7.16,>=0.7.12 # BSD
netifaces>=0.10.4 # MIT
neutron-lib>=0.0.1 # Apache-2.0
python-neutronclient>=2.6.0 # Apache-2.0
retrying!=1.3.0,>=1.2.3 # Apache-2.0