diff --git a/neutron/agent/common/ip_lib.py b/neutron/agent/common/ip_lib.py index df9ca9fd946..027c0c1fbf5 100644 --- a/neutron/agent/common/ip_lib.py +++ b/neutron/agent/common/ip_lib.py @@ -13,27 +13,11 @@ # License for the specific language governing permissions and limitations # under the License. -import os - -from oslo_log import log as logging +from neutron.agent.linux import ip_lib +from neutron.conf.agent import linux -if os.name == 'nt': - from neutron.agent.windows import ip_lib - from neutron.conf.agent import windows - OPTS = windows.IP_LIB_OPTS_WINDOWS -else: - from neutron.agent.linux import ip_lib - from neutron.conf.agent import linux - OPTS = linux.IP_LIB_OPTS_LINUX - - -if os.name == 'nt': - LOG = logging.getLogger(__name__) - LOG.warning("Support for Neutron on Windows operating systems " - "is deprecated since 2023.2 release and will be removed in " - "2024.2 OpenStack release.") - +OPTS = linux.IP_LIB_OPTS_LINUX IPWrapper = ip_lib.IPWrapper IPDevice = ip_lib.IPDevice diff --git a/neutron/agent/common/utils.py b/neutron/agent/common/utils.py index d2181d245e4..16811850c8a 100644 --- a/neutron/agent/common/utils.py +++ b/neutron/agent/common/utils.py @@ -13,7 +13,6 @@ # License for the specific language governing permissions and limitations # under the License. -import os import socket from eventlet import patcher @@ -23,16 +22,11 @@ from oslo_log import log as logging from oslo_utils import eventletutils from oslo_utils import timeutils +from neutron.agent.linux import utils from neutron.conf.agent import common as config from neutron.conf.agent.database import agents_db -if os.name == 'nt': - from neutron.agent.windows import utils -else: - from neutron.agent.linux import utils - - LOG = logging.getLogger(__name__) config.register_root_helper(cfg.CONF) agents_db.register_db_agents_opts() diff --git a/neutron/tests/functional/agent/windows/__init__.py b/neutron/tests/functional/agent/windows/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/neutron/tests/functional/agent/windows/test_ip_lib.py b/neutron/tests/functional/agent/windows/test_ip_lib.py deleted file mode 100644 index 07e72001987..00000000000 --- a/neutron/tests/functional/agent/windows/test_ip_lib.py +++ /dev/null @@ -1,44 +0,0 @@ -# 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.functional import base - -WRONG_IP = '0.0.0.0' -TEST_IP = '127.0.0.1' -TEST_MAC = '00:00:00:00:00:00' - - -class IpLibTestCase(base.BaseLoggingTestCase): - - 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.name) - - def test_device_has_ip(self): - not_a_device = ip_lib.IPDevice('#!#._not_a_device_bleargh!!@@@') - self.assertFalse(not_a_device.device_has_ip(TEST_IP)) - - def test_ip_link_read_mac_address(self): - ip_dev = ip_lib.IPWrapper().get_device_by_ip(TEST_IP) - self.assertEqual([TEST_MAC], ip_lib.IPLink(ip_dev).address) - - def test_ip_link_read_mac_address_wrong(self): - not_a_device = ip_lib.IPDevice('#!#._not_a_device_bleargh!!@@@') - mac_addr = ip_lib.IPLink(not_a_device).address - self.assertFalse(mac_addr) diff --git a/neutron/tests/unit/agent/windows/__init__.py b/neutron/tests/unit/agent/windows/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/neutron/tests/unit/agent/windows/test_ip_lib.py b/neutron/tests/unit/agent/windows/test_ip_lib.py deleted file mode 100644 index 9f65a2a132c..00000000000 --- a/neutron/tests/unit/agent/windows/test_ip_lib.py +++ /dev/null @@ -1,128 +0,0 @@ -# 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 unittest 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('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].name) - self.assertEqual(mock.sentinel.dev2, ret[1].name) - - @mock.patch('netifaces.interfaces') - def test_get_devices_error(self, mock_interfaces): - mock_interfaces.side_effect = OSError - ret = ip_lib.IPWrapper().get_devices() - - self.assertEqual([], ret) - - -class TestIpDevice(base.BaseTestCase): - - @mock.patch('netifaces.ifaddresses') - def test_read_ifaddresses(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").read_ifaddresses() - self.assertTrue(ret) - - @mock.patch('netifaces.ifaddresses') - def test_read_ifaddresses_no_ip(self, mock_netifaces): - mock_netifaces.return_value = {} - ret = ip_lib.IPDevice("fake_dev").read_ifaddresses() - self.assertFalse(ret) - - @mock.patch('netifaces.ifaddresses') - def test_read_ifaddresses_ip_error(self, mock_netifaces): - mock_netifaces.side_effect = OSError - ret = ip_lib.IPDevice("fake_dev").read_ifaddresses() - self.assertFalse(ret) - - @mock.patch('netifaces.ifaddresses') - def test_read_faddresses_not_found(self, mock_netifaces): - mock_netifaces.side_effect = ValueError - ret = ip_lib.IPDevice("fake_dev").read_ifaddresses() - self.assertFalse(ret) - - def test_device_has_ip(self): - mock_address = {'addr': mock.sentinel.fake_addr} - ip_device = ip_lib.IPDevice("fake_dev") - with mock.patch.object(ip_device, "read_ifaddresses", return_value=( - {netifaces.AF_INET: [mock_address]})): - ret = ip_device.device_has_ip(mock.sentinel.fake_addr) - self.assertTrue(ret) - - def test_device_has_ip_false(self): - ip_device = ip_lib.IPDevice("fake_dev") - with mock.patch.object(ip_device, "read_ifaddresses", return_value={}): - ret = ip_device.device_has_ip(mock.sentinel.fake_addr) - self.assertFalse(ret) - - def test_device_has_ip_error(self): - ip_device = ip_lib.IPDevice("fake_dev") - with mock.patch.object(ip_device, "read_ifaddresses", - return_value=None): - ret = ip_device.device_has_ip(mock.sentinel.fake_addr) - self.assertFalse(ret) - - -class TestIPLink(base.BaseTestCase): - - def setUp(self): - super(TestIPLink, self).setUp() - parent = ip_lib.IPDevice("fake_dev") - self.ip_link = ip_lib.IPLink(parent) - self.ip_link._parent.read_ifaddresses = mock.Mock() - - def test_address(self): - mock_address = {'addr': mock.sentinel.fake_addr} - self.ip_link._parent.read_ifaddresses.return_value = { - netifaces.AF_LINK: [mock_address]} - self.assertEqual([mock_address['addr']], self.ip_link.address) - - def test_address_no_address(self): - self.ip_link._parent.read_ifaddresses.return_value = { - netifaces.AF_LINK: []} - self.assertEqual([], self.ip_link.address) - - def test_address_error(self): - self.ip_link._parent.read_ifaddresses.return_value = None - self.assertFalse(self.ip_link.address) diff --git a/neutron/tests/unit/agent/windows/test_utils.py b/neutron/tests/unit/agent/windows/test_utils.py deleted file mode 100644 index c2123508d1c..00000000000 --- a/neutron/tests/unit/agent/windows/test_utils.py +++ /dev/null @@ -1,242 +0,0 @@ -# Copyright 2018 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 builtins -import io -from unittest import mock - -import ddt -import eventlet -from eventlet import tpool -from neutron_lib import exceptions - -from neutron.agent.windows import utils -from neutron.tests import base - - -class x_wmi(Exception): - def __init__(self, info='', com_error=None): - super(x_wmi, self).__init__(info) - self.info = info - self.com_error = com_error - - -@ddt.ddt -class WindowsUtilsTestCase(base.BaseTestCase): - @mock.patch('os.environ', {mock.sentinel.key0: mock.sentinel.val0}) - @mock.patch.object(utils.subprocess, 'Popen') - @mock.patch.object(tpool, 'Proxy') - @mock.patch.object(eventlet, 'getcurrent') - def test_create_process(self, mock_get_current_gt, - mock_tpool_proxy, mock_popen): - cmd = ['fake_cmd'] - - popen_obj, ret_cmd = utils.create_process( - cmd, - run_as_root=mock.sentinel.run_as_root, - addl_env={mock.sentinel.key1: mock.sentinel.val1}, - tpool_proxy=True) - - exp_env = {mock.sentinel.key0: mock.sentinel.val0, - mock.sentinel.key1: mock.sentinel.val1} - - mock_popen.assert_called_once_with( - cmd, - shell=False, - stdin=utils.subprocess.PIPE, - stdout=utils.subprocess.PIPE, - stderr=utils.subprocess.PIPE, - env=exp_env, - preexec_fn=None, - close_fds=False) - - file_type = getattr(builtins, 'file', io.IOBase) - mock_tpool_proxy.assert_called_once_with( - mock_popen.return_value, autowrap=(file_type, )) - - self.assertEqual(mock_tpool_proxy.return_value, popen_obj) - self.assertEqual(ret_cmd, cmd) - - @ddt.data({}, - {'pid': None}, - {'process_exists': True}) - @ddt.unpack - @mock.patch.object(utils, 'wmi', create=True) - def test_get_wmi_process(self, mock_wmi, - pid=mock.sentinel.pid, - process_exists=False): - mock_conn = mock_wmi.WMI.return_value - - if not pid: - exp_process = None - elif process_exists: - exp_process = mock.sentinel.wmi_obj - mock_conn.Win32_Process.return_value = [exp_process] - else: - exp_process = None - mock_conn.Win32_Process.return_value = [] - - wmi_obj = utils._get_wmi_process(pid) - self.assertEqual(exp_process, wmi_obj) - - if pid: - mock_conn.Win32_Process.assert_called_once_with(ProcessId=pid) - - @ddt.data({}, - {"hresult": 0xff, - "expect_exc": True}) - @ddt.unpack - @mock.patch.object(utils, 'wmi', create=True) - def test_get_wmi_process_exc(self, mock_wmi, expect_exc=False, - hresult=0x800703FA): - mock_conn = mock_wmi.WMI.return_value - mock_wmi.x_wmi = x_wmi - com_error = mock.Mock(hresult=hresult) - exc = x_wmi(com_error=com_error) - mock_conn.Win32_Process.side_effect = exc - - if expect_exc: - self.assertRaises( - x_wmi, utils._get_wmi_process, mock.sentinel.pid) - else: - self.assertIsNone(utils._get_wmi_process(mock.sentinel.pid)) - - @ddt.data(True, False) - @mock.patch.object(utils, '_get_wmi_process') - def test_kill_process(self, process_exists, mock_get_process): - if not process_exists: - mock_get_process.return_value = None - - utils.kill_process(mock.sentinel.pid, mock.sentinel.signal, - run_as_root=False) - - mock_get_process.assert_called_once_with(mock.sentinel.pid) - if process_exists: - mock_get_process.return_value.Terminate.assert_called_once_with() - - @ddt.data(True, False) - @mock.patch.object(utils, '_get_wmi_process') - def test_kill_process_exception(self, process_still_running, - mock_get_process): - mock_process = mock.Mock() - mock_process.Terminate.side_effect = OSError - - mock_get_process.side_effect = [ - mock_process, - mock_process if process_still_running else None] - - if process_still_running: - self.assertRaises(OSError, - utils.kill_process, - mock.sentinel.pid, - mock.sentinel.signal) - else: - utils.kill_process(mock.sentinel.pid, - mock.sentinel.signal) - - @ddt.data({'return_stder': True}, - {'returncode': 1, - 'check_exit_code': False, - 'log_fail_as_error': True}, - {'returncode': 1, - 'log_fail_as_error': True, - 'extra_ok_codes': [1]}, - {'returncode': 1, - 'log_fail_as_error': True, - 'exp_fail': True}) - @ddt.unpack - @mock.patch.object(utils, 'create_process') - @mock.patch.object(utils, 'avoid_blocking_call') - def test_execute(self, mock_avoid_blocking_call, mock_create_process, - returncode=0, check_exit_code=True, return_stder=True, - log_fail_as_error=True, extra_ok_codes=None, - exp_fail=False): - fake_stdin = 'fake_stdin' - fake_stdout = 'fake_stdout' - fake_stderr = 'fake_stderr' - - mock_popen = mock.Mock() - mock_popen.communicate.return_value = fake_stdout, fake_stderr - mock_popen.returncode = returncode - - mock_create_process.return_value = mock_popen, mock.sentinel.cmd - mock_avoid_blocking_call.side_effect = ( - lambda func, *args, **kwargs: func(*args, **kwargs)) - - args = (mock.sentinel.cmd, fake_stdin, mock.sentinel.env, - check_exit_code, return_stder, log_fail_as_error, - extra_ok_codes) - - if exp_fail: - self.assertRaises(exceptions.ProcessExecutionError, - utils.execute, - *args) - else: - ret_val = utils.execute(*args) - if return_stder: - exp_ret_val = (fake_stdout, fake_stderr) - else: - exp_ret_val = fake_stdout - - self.assertEqual(exp_ret_val, ret_val) - - mock_create_process.assert_called_once_with( - mock.sentinel.cmd, addl_env=mock.sentinel.env, - tpool_proxy=False) - mock_avoid_blocking_call.assert_called_once_with( - mock_popen.communicate, bytes(fake_stdin, 'utf-8')) - mock_popen.communicate.assert_called_once_with( - bytes(fake_stdin, 'utf-8')) - mock_popen.stdin.close.assert_called_once_with() - - def test_get_root_helper_child_pid(self): - pid = utils.get_root_helper_child_pid( - mock.sentinel.pid, - mock.sentinel.exp_cmd, - run_as_root=False) - self.assertEqual(str(mock.sentinel.pid), pid) - - @ddt.data(True, False) - @mock.patch.object(utils, '_get_wmi_process') - def test_process_is_running(self, process_running, mock_get_process): - mock_get_process.return_value = ( - mock.sentinel.wmi_obj if process_running else None) - - self.assertEqual(process_running, - utils.process_is_running(mock.sentinel.pid)) - mock_get_process.assert_called_once_with(mock.sentinel.pid) - - @ddt.data({}, - {'process_running': False}, - {'command_matches': False}) - @ddt.unpack - @mock.patch.object(utils, '_get_wmi_process') - def test_pid_invoked_with_cmdline(self, mock_get_process, - process_running=True, - command_matches=False): - exp_cmd = 'exp_cmd' - mock_process = mock.Mock() - - mock_get_process.return_value = ( - mock_process if process_running else None) - mock_process.CommandLine = ( - exp_cmd if command_matches else 'unexpected_cmd') - - exp_result = process_running and command_matches - result = utils.pid_invoked_with_cmdline(mock.sentinel.pid, - [exp_cmd]) - - self.assertEqual(exp_result, result) - mock_get_process.assert_called_once_with(mock.sentinel.pid) diff --git a/releasenotes/notes/remove-suppport-for-windows-os-fd662b7111d3d1b0.yaml b/releasenotes/notes/remove-suppport-for-windows-os-fd662b7111d3d1b0.yaml new file mode 100644 index 00000000000..45210aa2db9 --- /dev/null +++ b/releasenotes/notes/remove-suppport-for-windows-os-fd662b7111d3d1b0.yaml @@ -0,0 +1,4 @@ +--- +deprecations: + - | + Removed the support for Windows OS. diff --git a/zuul.d/base.yaml b/zuul.d/base.yaml index efd4e5b5091..5d0dbe7c2c2 100644 --- a/zuul.d/base.yaml +++ b/zuul.d/base.yaml @@ -84,7 +84,6 @@ - ^neutron/tests/unit/.*$ - ^neutron/tests/functional/.*$ - ^neutron/agent/ovn/.*$ - - ^neutron/agent/windows/.*$ - ^neutron/plugins/ml2/drivers/macvtap/.*$ - ^neutron/plugins/ml2/drivers/mech_sriov/.*$ - ^neutron/plugins/ml2/drivers/ovn/.*$ diff --git a/zuul.d/grenade.yaml b/zuul.d/grenade.yaml index 709f073a7d4..1c96c4c5370 100644 --- a/zuul.d/grenade.yaml +++ b/zuul.d/grenade.yaml @@ -19,7 +19,6 @@ - ^plugin.spec$ - ^tools/ovn_migration/.*$ - ^neutron/agent/ovn/.*$ - - ^neutron/agent/windows/.*$ - ^neutron/plugins/ml2/drivers/linuxbridge/.*$ - ^neutron/plugins/ml2/drivers/macvtap/.*$ - ^neutron/plugins/ml2/drivers/mech_sriov/.*$ @@ -234,7 +233,6 @@ - ^neutron/agent/l2/.*$ - ^neutron/agent/l3/.*$ - ^neutron/agent/metadata/.*$ - - ^neutron/agent/windows/.*$ - ^neutron/agent/dhcp_agent.py - ^neutron/agent/l3_agent.py - ^neutron/agent/metadata_agent.py diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml index 032064e1d14..4c692623933 100644 --- a/zuul.d/project.yaml +++ b/zuul.d/project.yaml @@ -44,7 +44,6 @@ - ^neutron/agent/l2/.*$ - ^neutron/agent/l3/.*$ - ^neutron/agent/metadata/.*$ - - ^neutron/agent/windows/.*$ - ^neutron/agent/dhcp_agent.py - ^neutron/agent/l3_agent.py - ^neutron/agent/metadata_agent.py diff --git a/zuul.d/rally.yaml b/zuul.d/rally.yaml index 870c2e7fa7f..4c603167fa7 100644 --- a/zuul.d/rally.yaml +++ b/zuul.d/rally.yaml @@ -66,7 +66,6 @@ - ^plugin.spec$ - ^tools/ovn_migration/.*$ - ^neutron/agent/ovn/.*$ - - ^neutron/agent/windows/.*$ - ^neutron/plugins/ml2/drivers/linuxbridge/.*$ - ^neutron/plugins/ml2/drivers/macvtap/.*$ - ^neutron/plugins/ml2/drivers/mech_sriov/.*$ @@ -109,7 +108,6 @@ - ^neutron/agent/l2/.*$ - ^neutron/agent/l3/.*$ - ^neutron/agent/metadata/.*$ - - ^neutron/agent/windows/.*$ - ^neutron/agent/dhcp_agent.py - ^neutron/agent/l3_agent.py - ^neutron/agent/metadata_agent.py diff --git a/zuul.d/tempest-multinode.yaml b/zuul.d/tempest-multinode.yaml index 1db4e502a30..dd0df163476 100644 --- a/zuul.d/tempest-multinode.yaml +++ b/zuul.d/tempest-multinode.yaml @@ -58,7 +58,6 @@ - ^plugin.spec$ - ^tools/ovn_migration/.*$ - ^neutron/agent/ovn/.*$ - - ^neutron/agent/windows/.*$ - ^neutron/plugins/ml2/drivers/linuxbridge/.*$ - ^neutron/plugins/ml2/drivers/macvtap/.*$ - ^neutron/plugins/ml2/drivers/mech_sriov/.*$ @@ -388,7 +387,6 @@ - ^neutron/agent/l2/.*$ - ^neutron/agent/l3/.*$ - ^neutron/agent/metadata/.*$ - - ^neutron/agent/windows/.*$ - ^neutron/agent/dhcp_agent.py - ^neutron/agent/l3_agent.py - ^neutron/agent/metadata_agent.py diff --git a/zuul.d/tempest-singlenode.yaml b/zuul.d/tempest-singlenode.yaml index 7dbb0f2e3d8..7e78cb77315 100644 --- a/zuul.d/tempest-singlenode.yaml +++ b/zuul.d/tempest-singlenode.yaml @@ -70,7 +70,6 @@ - ^tools/ovn_migration/.*$ - ^vagrant/.*$ - ^neutron/agent/ovn/.*$ - - ^neutron/agent/windows/.*$ - ^neutron/plugins/ml2/drivers/linuxbridge/.*$ - ^neutron/plugins/ml2/drivers/macvtap/.*$ - ^neutron/plugins/ml2/drivers/mech_sriov/.*$ @@ -133,7 +132,6 @@ - ^vagrant/.*$ - ^neutron/agent/linux/openvswitch_firewall/.*$ - ^neutron/agent/ovn/.*$ - - ^neutron/agent/windows/.*$ - ^neutron/plugins/ml2/drivers/openvswitch/.*$ - ^neutron/plugins/ml2/drivers/macvtap/.*$ - ^neutron/plugins/ml2/drivers/mech_sriov/.*$ @@ -334,7 +332,6 @@ - ^plugin.spec$ - ^tools/ovn_migration/.*$ - ^vagrant/.*$ - - ^neutron/agent/windows/.*$ - ^neutron/plugins/ml2/drivers/linuxbridge/.*$ - ^neutron/plugins/ml2/drivers/macvtap/.*$ - ^neutron/plugins/ml2/drivers/mech_sriov/.*$ @@ -595,7 +592,6 @@ - ^neutron/agent/l2/.*$ - ^neutron/agent/l3/.*$ - ^neutron/agent/metadata/.*$ - - ^neutron/agent/windows/.*$ - ^neutron/agent/dhcp_agent.py - ^neutron/agent/l3_agent.py - ^neutron/agent/metadata_agent.py