Delete HA metadata proxy PID and config with elevated privileges

Both files cannot be deleted with the default permissions because
those files are created by the "root" user.

Conflicts:
    neutron/agent/metadata/driver.py
    neutron/tests/functional/agent/l3/framework.py
    neutron/tests/unit/agent/dhcp/test_agent.py

Change-Id: I73dd37b3104fac8d3172f520f71cffd85d040c4b
Closes-Bug: #1907695
(cherry picked from commit 0a0f647ea0)
This commit is contained in:
Rodolfo Alonso Hernandez 2020-12-10 16:59:46 +00:00 committed by Slawek Kaplonski
parent 87fce78fee
commit 28cf6786f4
7 changed files with 55 additions and 20 deletions

View File

@ -113,7 +113,8 @@ class ProcessManager(MonitoredProcess):
utils.execute(cmd, run_as_root=self.run_as_root)
# In the case of shutting down, remove the pid file
if sig == '9':
fileutils.delete_if_exists(self.get_pid_file_name())
utils.delete_if_exists(self.get_pid_file_name(),
run_as_root=self.run_as_root)
elif pid:
LOG.debug('%(service)s process for %(uuid)s pid %(pid)d is stale, '
'ignoring signal %(signal)s',

View File

@ -38,6 +38,7 @@ from neutron._i18n import _
from neutron.agent.linux import xenapi_root_helper
from neutron.common import utils
from neutron.conf.agent import common as config
from neutron.privileged.agent.linux import utils as priv_utils
from neutron import wsgi
@ -394,6 +395,14 @@ def is_effective_group(group_id_or_name):
return group_id_or_name == effective_group_name
def delete_if_exists(path, run_as_root=False):
"""Delete a path, executed as normal user or with elevated privileges"""
if run_as_root:
priv_utils.delete_if_exists(path)
else:
fileutils.delete_if_exists(path)
class UnixDomainHTTPConnection(httplib.HTTPConnection):
"""Connection class for HTTP over UNIX domain socket."""
def __init__(self, host, port=None, strict=None, timeout=None,

View File

@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import errno
import grp
import os
import pwd
@ -30,6 +29,7 @@ from neutron._i18n import _
from neutron.agent.l3 import ha_router
from neutron.agent.l3 import namespaces
from neutron.agent.linux import external_process
from neutron.agent.linux import utils as linux_utils
LOG = logging.getLogger(__name__)
@ -163,13 +163,7 @@ class HaproxyConfigurator(object):
cfg_path = os.path.join(
HaproxyConfigurator.get_config_path(state_path),
"%s.conf" % uuid)
try:
os.unlink(cfg_path)
except OSError as ex:
# It can happen that this function is called but metadata proxy
# was never spawned so its config file won't exist
if ex.errno != errno.ENOENT:
raise
linux_utils.delete_if_exists(cfg_path, run_as_root=True)
class MetadataDriver(object):

View File

@ -12,9 +12,11 @@
# License for the specific language governing permissions and limitations
# under the License.
import os
import re
from oslo_concurrency import processutils
from oslo_utils import fileutils
from neutron import privileged
@ -40,3 +42,8 @@ def _find_listen_pids_namespace(namespace):
if m:
pids.add(m.group('pid'))
return list(pids)
@privileged.default.entrypoint
def delete_if_exists(path, remove=os.unlink):
fileutils.delete_if_exists(path, remove=remove)

View File

@ -15,6 +15,7 @@
import copy
import functools
import os
import mock
import netaddr
@ -435,12 +436,15 @@ class L3AgentTestFramework(base.BaseSudoTestCase):
def _namespace_exists(self, namespace):
return ip_lib.network_namespace_exists(namespace)
def _metadata_proxy_exists(self, conf, router):
pm = external_process.ProcessManager(
def _metadata_proxy(self, conf, router):
return external_process.ProcessManager(
conf,
router.router_id,
router.ns_name,
service=metadata_driver.HAPROXY_SERVICE)
def _metadata_proxy_exists(self, conf, router):
pm = self._metadata_proxy(conf, router)
return pm.active
def device_exists_with_ips_and_mac(self, expected_device, name_getter,
@ -501,9 +505,19 @@ class L3AgentTestFramework(base.BaseSudoTestCase):
# then the devices and iptable rules have also been deleted,
# so there's no need to check that explicitly.
self.assertFalse(self._namespace_exists(router.ns_name))
common_utils.wait_until_true(
lambda: not self._metadata_proxy_exists(self.agent.conf, router),
timeout=10)
try:
common_utils.wait_until_true(
lambda: not self._metadata_proxy_exists(self.agent.conf,
router),
timeout=10)
except common_utils.WaitTimeout:
pm = self._metadata_proxy(self.agent.conf, router)
pid_file = pm.get_pid_file_name()
if os.path.exists(pid_file):
msg = 'PID file %s still exists and it should not.' % pid_file
else:
msg = 'PID file %s is not present.' % pid_file
self.fail(msg)
def _assert_snat_chains(self, router):
self.assertFalse(router.iptables_manager.is_chain_empty(

View File

@ -34,6 +34,7 @@ from neutron.agent.dhcp import agent as dhcp_agent
from neutron.agent import dhcp_agent as entry
from neutron.agent.linux import dhcp
from neutron.agent.linux import interface
from neutron.agent.linux import utils as linux_utils
from neutron.agent.metadata import driver as metadata_driver
from neutron.common import config as common_config
from neutron.common import utils
@ -759,6 +760,12 @@ class TestDhcpAgentEventHandler(base.BaseTestCase):
self.mock_resize_p = mock.patch('neutron.agent.dhcp.agent.'
'DhcpAgent._resize_process_pool')
self.mock_resize = self.mock_resize_p.start()
self.mock_wait_until_address_ready_p = mock.patch(
'neutron.agent.linux.ip_lib.'
'IpAddrCommand.wait_until_address_ready')
self.mock_wait_until_address_ready_p.start()
mock.patch.object(linux_utils, 'delete_if_exists').start()
self.addCleanup(self.mock_wait_until_address_ready_p.stop)
def _process_manager_constructor_call(self, ns=FAKE_NETWORK_DHCP_NS):
return mock.call(conf=cfg.CONF,

View File

@ -55,6 +55,7 @@ from neutron.agent.linux import ip_lib
from neutron.agent.linux import iptables_manager
from neutron.agent.linux import pd
from neutron.agent.linux import ra
from neutron.agent.linux import utils as linux_utils
from neutron.agent.metadata import driver as metadata_driver
from neutron.agent import rpc as agent_rpc
from neutron.conf.agent import common as agent_config
@ -3060,9 +3061,10 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
dvr_snat_ns.SNAT_NS_PREFIX + 'foo']
other_namespaces = ['unknown']
self._cleanup_namespace_test(stale_namespaces,
[],
other_namespaces)
with mock.patch.object(linux_utils, 'delete_if_exists'):
self._cleanup_namespace_test(stale_namespaces,
[],
other_namespaces)
def test_cleanup_namespace_with_registered_router_ids(self):
stale_namespaces = [namespaces.NS_PREFIX + 'cccc',
@ -3072,9 +3074,10 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
{'id': 'aaaa', 'distributed': False}]
other_namespaces = ['qdhcp-aabbcc', 'unknown']
self._cleanup_namespace_test(stale_namespaces,
router_list,
other_namespaces)
with mock.patch.object(linux_utils, 'delete_if_exists'):
self._cleanup_namespace_test(stale_namespaces,
router_list,
other_namespaces)
def test_create_dvr_gateway(self):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)