Migrate "dhcp_release" to oslo.privsep
Story: #2007686 Task: #39976 Change-Id: I3414d06b9c6dfe549e79aab5fbe52c8f3ffd63f7
This commit is contained in:
parent
c6e5e119b8
commit
e332054d63
@ -20,8 +20,6 @@ kill_dnsmasq_script: CommandFilter, dnsmasq-kill, root
|
|||||||
|
|
||||||
ovs-vsctl: CommandFilter, ovs-vsctl, root
|
ovs-vsctl: CommandFilter, ovs-vsctl, root
|
||||||
mm-ctl: CommandFilter, mm-ctl, root
|
mm-ctl: CommandFilter, mm-ctl, root
|
||||||
dhcp_release: CommandFilter, dhcp_release, root
|
|
||||||
dhcp_release6: CommandFilter, dhcp_release6, root
|
|
||||||
|
|
||||||
# haproxy
|
# haproxy
|
||||||
haproxy: RegExpFilter, haproxy, root, haproxy, -f, .*
|
haproxy: RegExpFilter, haproxy, root, haproxy, -f, .*
|
||||||
|
@ -27,6 +27,7 @@ from neutron_lib.api.definitions import extra_dhcp_opt as edo_ext
|
|||||||
from neutron_lib import constants
|
from neutron_lib import constants
|
||||||
from neutron_lib import exceptions
|
from neutron_lib import exceptions
|
||||||
from neutron_lib.utils import file as file_utils
|
from neutron_lib.utils import file as file_utils
|
||||||
|
from oslo_concurrency import processutils
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_utils import excutils
|
from oslo_utils import excutils
|
||||||
from oslo_utils import fileutils
|
from oslo_utils import fileutils
|
||||||
@ -42,6 +43,7 @@ from neutron.agent.linux import iptables_manager
|
|||||||
from neutron.cmd import runtime_checks as checks
|
from neutron.cmd import runtime_checks as checks
|
||||||
from neutron.common import utils as common_utils
|
from neutron.common import utils as common_utils
|
||||||
from neutron.ipam import utils as ipam_utils
|
from neutron.ipam import utils as ipam_utils
|
||||||
|
from neutron.privileged.agent.linux import dhcp as priv_dhcp
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -515,7 +517,8 @@ class Dnsmasq(DhcpLocalProcess):
|
|||||||
|
|
||||||
def _is_dhcp_release6_supported(self):
|
def _is_dhcp_release6_supported(self):
|
||||||
if self._IS_DHCP_RELEASE6_SUPPORTED is None:
|
if self._IS_DHCP_RELEASE6_SUPPORTED is None:
|
||||||
self._IS_DHCP_RELEASE6_SUPPORTED = checks.dhcp_release6_supported()
|
self._IS_DHCP_RELEASE6_SUPPORTED = (
|
||||||
|
priv_dhcp.dhcp_release6_supported())
|
||||||
if not self._IS_DHCP_RELEASE6_SUPPORTED:
|
if not self._IS_DHCP_RELEASE6_SUPPORTED:
|
||||||
LOG.warning("dhcp_release6 is not present on this system, "
|
LOG.warning("dhcp_release6 is not present on this system, "
|
||||||
"will not call it again.")
|
"will not call it again.")
|
||||||
@ -530,24 +533,27 @@ class Dnsmasq(DhcpLocalProcess):
|
|||||||
def _release_lease(self, mac_address, ip, ip_version, client_id=None,
|
def _release_lease(self, mac_address, ip, ip_version, client_id=None,
|
||||||
server_id=None, iaid=None):
|
server_id=None, iaid=None):
|
||||||
"""Release a DHCP lease."""
|
"""Release a DHCP lease."""
|
||||||
|
try:
|
||||||
if ip_version == constants.IP_VERSION_6:
|
if ip_version == constants.IP_VERSION_6:
|
||||||
if not self._is_dhcp_release6_supported():
|
if not self._is_dhcp_release6_supported():
|
||||||
return
|
return
|
||||||
cmd = ['dhcp_release6', '--iface', self.interface_name,
|
|
||||||
'--ip', ip, '--client-id', client_id,
|
params = {'interface_name': self.interface_name,
|
||||||
'--server-id', server_id, '--iaid', iaid]
|
'ip_address': ip, 'client_id': client_id,
|
||||||
|
'server_id': server_id, 'iaid': iaid,
|
||||||
|
'namespace': self.network.namespace}
|
||||||
|
priv_dhcp.dhcp_release6(**params)
|
||||||
else:
|
else:
|
||||||
cmd = ['dhcp_release', self.interface_name, ip, mac_address]
|
params = {'interface_name': self.interface_name,
|
||||||
if client_id:
|
'ip_address': ip, 'mac_address': mac_address,
|
||||||
cmd.append(client_id)
|
'client_id': client_id,
|
||||||
ip_wrapper = ip_lib.IPWrapper(namespace=self.network.namespace)
|
'namespace': self.network.namespace}
|
||||||
try:
|
priv_dhcp.dhcp_release(**params)
|
||||||
ip_wrapper.netns.execute(cmd, run_as_root=True)
|
except (processutils.ProcessExecutionError, OSError) as e:
|
||||||
except RuntimeError as e:
|
|
||||||
# when failed to release single lease there's
|
# when failed to release single lease there's
|
||||||
# no need to propagate error further
|
# no need to propagate error further
|
||||||
LOG.warning('DHCP release failed for %(cmd)s. '
|
LOG.warning('DHCP release failed for params %(params)s. '
|
||||||
'Reason: %(e)s', {'cmd': cmd, 'e': e})
|
'Reason: %(e)s', {'params': params, 'e': e})
|
||||||
|
|
||||||
def _output_config_files(self):
|
def _output_config_files(self):
|
||||||
self._output_hosts_file()
|
self._output_hosts_file()
|
||||||
|
@ -25,19 +25,6 @@ LOG = logging.getLogger(__name__)
|
|||||||
# which would be run at system setup time. Please consider writing a
|
# which would be run at system setup time. Please consider writing a
|
||||||
# sanity check instead.
|
# sanity check instead.
|
||||||
|
|
||||||
|
|
||||||
def dhcp_release6_supported():
|
|
||||||
try:
|
|
||||||
cmd = ['dhcp_release6', '--help']
|
|
||||||
env = {'LC_ALL': 'C'}
|
|
||||||
agent_utils.execute(cmd, addl_env=env)
|
|
||||||
except (OSError, RuntimeError, IndexError, ValueError) as e:
|
|
||||||
LOG.debug("Exception while checking dhcp_release6. "
|
|
||||||
"Exception: %s", e)
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def dnsmasq_host_tag_support():
|
def dnsmasq_host_tag_support():
|
||||||
cmd = ['dnsmasq', '--test', '--dhcp-host=tag:foo']
|
cmd = ['dnsmasq', '--test', '--dhcp-host=tag:foo']
|
||||||
env = {'LC_ALL': 'C', 'PATH': '/sbin:/usr/sbin'}
|
env = {'LC_ALL': 'C', 'PATH': '/sbin:/usr/sbin'}
|
||||||
|
@ -33,10 +33,10 @@ from neutron.agent.linux import external_process
|
|||||||
from neutron.agent.linux import ip_lib
|
from neutron.agent.linux import ip_lib
|
||||||
from neutron.agent.linux import keepalived
|
from neutron.agent.linux import keepalived
|
||||||
from neutron.agent.linux import utils as agent_utils
|
from neutron.agent.linux import utils as agent_utils
|
||||||
from neutron.cmd import runtime_checks
|
|
||||||
from neutron.common import utils as common_utils
|
from neutron.common import utils as common_utils
|
||||||
from neutron.plugins.ml2.drivers.openvswitch.agent.common \
|
from neutron.plugins.ml2.drivers.openvswitch.agent.common \
|
||||||
import constants as ovs_const
|
import constants as ovs_const
|
||||||
|
from neutron.privileged.agent.linux import dhcp as priv_dhcp
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -239,7 +239,7 @@ def ovs_qos_direct_port_supported():
|
|||||||
|
|
||||||
|
|
||||||
def dhcp_release6_supported():
|
def dhcp_release6_supported():
|
||||||
return runtime_checks.dhcp_release6_supported()
|
return priv_dhcp.dhcp_release6_supported()
|
||||||
|
|
||||||
|
|
||||||
def bridge_firewalling_enabled():
|
def bridge_firewalling_enabled():
|
||||||
|
@ -28,3 +28,12 @@ default = priv_context.PrivContext(
|
|||||||
caps.CAP_DAC_READ_SEARCH,
|
caps.CAP_DAC_READ_SEARCH,
|
||||||
caps.CAP_SYS_PTRACE],
|
caps.CAP_SYS_PTRACE],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
dhcp_release_cmd = priv_context.PrivContext(
|
||||||
|
__name__,
|
||||||
|
cfg_section='privsep_dhcp_release',
|
||||||
|
pypath=__name__ + '.dhcp_release_cmd',
|
||||||
|
capabilities=[caps.CAP_SYS_ADMIN,
|
||||||
|
caps.CAP_NET_ADMIN]
|
||||||
|
)
|
||||||
|
48
neutron/privileged/agent/linux/dhcp.py
Normal file
48
neutron/privileged/agent/linux/dhcp.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# 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 oslo_concurrency import processutils
|
||||||
|
|
||||||
|
from neutron import privileged
|
||||||
|
|
||||||
|
|
||||||
|
@privileged.dhcp_release_cmd.entrypoint
|
||||||
|
def dhcp_release(interface_name, ip_address, mac_address, client_id,
|
||||||
|
namespace=None):
|
||||||
|
cmd = []
|
||||||
|
if namespace:
|
||||||
|
cmd += ['ip', 'netns', 'exec', namespace]
|
||||||
|
cmd += ['dhcp_release', interface_name, ip_address, mac_address]
|
||||||
|
if client_id:
|
||||||
|
cmd += client_id
|
||||||
|
log_errors = processutils.LOG_FINAL_ERROR
|
||||||
|
return processutils.execute(*cmd, log_errors=log_errors)
|
||||||
|
|
||||||
|
|
||||||
|
@privileged.dhcp_release_cmd.entrypoint
|
||||||
|
def dhcp_release6(interface_name, ip_address, client_id, server_id, iaid,
|
||||||
|
namespace=None):
|
||||||
|
cmd = []
|
||||||
|
if namespace:
|
||||||
|
cmd += ['ip', 'netns', 'exec', namespace]
|
||||||
|
cmd += ['dhcp_release6', '--iface', interface_name, '--ip', ip_address,
|
||||||
|
'--client-id', client_id, '--server-id', server_id, '--iaid', iaid]
|
||||||
|
log_errors = processutils.LOG_FINAL_ERROR
|
||||||
|
return processutils.execute(*cmd, log_errors=log_errors)
|
||||||
|
|
||||||
|
|
||||||
|
@privileged.dhcp_release_cmd.entrypoint
|
||||||
|
def dhcp_release6_supported():
|
||||||
|
cmd = ['dhcp_release6', '--help']
|
||||||
|
result = processutils.execute(*cmd, check_exit_code=False,
|
||||||
|
env_variables={'LC_ALL': 'C'})
|
||||||
|
return not bool(result[1])
|
@ -34,6 +34,7 @@ from neutron.cmd import runtime_checks as checks
|
|||||||
from neutron.conf.agent import common as config
|
from neutron.conf.agent import common as config
|
||||||
from neutron.conf.agent import dhcp as dhcp_config
|
from neutron.conf.agent import dhcp as dhcp_config
|
||||||
from neutron.conf import common as base_config
|
from neutron.conf import common as base_config
|
||||||
|
from neutron.privileged.agent.linux import dhcp as priv_dhcp
|
||||||
from neutron.tests import base
|
from neutron.tests import base
|
||||||
|
|
||||||
|
|
||||||
@ -2244,19 +2245,24 @@ class TestDnsmasq(TestBase):
|
|||||||
'server_id': 'server_id'}
|
'server_id': 'server_id'}
|
||||||
},
|
},
|
||||||
{}])
|
{}])
|
||||||
ipw = mock.patch(
|
mock_dhcp_release = mock.patch.object(priv_dhcp,
|
||||||
'neutron.agent.linux.ip_lib.IpNetnsCommand.execute').start()
|
'dhcp_release').start()
|
||||||
|
mock_dhcp_release6 = mock.patch.object(priv_dhcp,
|
||||||
|
'dhcp_release6').start()
|
||||||
|
mock_dhcp_release6_supported = mock.patch.object(
|
||||||
|
priv_dhcp, 'dhcp_release6_supported').start()
|
||||||
dnsmasq._release_unused_leases()
|
dnsmasq._release_unused_leases()
|
||||||
# Verify that dhcp_release is called both for ipv4 and ipv6 addresses.
|
# Verify that dhcp_release is called both for ipv4 and ipv6 addresses.
|
||||||
self.assertEqual(2, ipw.call_count)
|
self.assertEqual(1, mock_dhcp_release.call_count)
|
||||||
ipw.assert_has_calls([mock.call(['dhcp_release6',
|
self.assertEqual(1, mock_dhcp_release6.call_count)
|
||||||
'--iface', None, '--ip', ip1,
|
mock_dhcp_release.assert_called_once_with(
|
||||||
'--client-id', 'client_id',
|
interface_name=None, ip_address=ip2, mac_address=mac2,
|
||||||
'--server-id', 'server_id',
|
client_id=None, namespace=dnsmasq.network.namespace)
|
||||||
'--iaid', 0xff],
|
mock_dhcp_release6.assert_called_once_with(
|
||||||
run_as_root=True)])
|
interface_name=None, ip_address=ip1, client_id='client_id',
|
||||||
ipw.assert_has_calls([mock.call(['dhcp_release', None, ip2, mac2],
|
server_id='server_id', iaid=0xff,
|
||||||
run_as_root=True), ])
|
namespace=dnsmasq.network.namespace)
|
||||||
|
mock_dhcp_release6_supported.assert_called_once_with()
|
||||||
|
|
||||||
def test_release_for_ipv6_lease_no_dhcp_release6(self):
|
def test_release_for_ipv6_lease_no_dhcp_release6(self):
|
||||||
dnsmasq = self._get_dnsmasq(FakeDualNetwork())
|
dnsmasq = self._get_dnsmasq(FakeDualNetwork())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user