Skip Trilio dirs when setting ownership in /var/lib/nova

Trilio currently mounts an NFS export in /var/lib/nova to make it accessible
from within the nova_compute and nova_libvirt containers.
This can result in considerable delays when walking the directory tree to
ensure the ownership is correct.

This patch adds the ability to skip paths when recursively setting the
ownership and selinux context in /var/lib/nova. The list of paths to skip
can be set via te NovaStatedirOwnershipSkip heat parameter. This default to
the Trilio dir.

Change-Id: Ic6f053d56194613046ae0a4a908206ebb453fcf4
(cherry picked from commit c156534010)
(cherry picked from commit fbc55f02f2)
(cherry picked from commit c352a78fe0)
(cherry picked from commit f318e4e2df)
This commit is contained in:
Oliver Walsh 2020-10-09 17:28:16 +01:00
parent 511e3aece9
commit 63c522eb31
3 changed files with 61 additions and 3 deletions

View File

@ -85,6 +85,13 @@ parameters:
default: false
description: Whether config-download method is used or not.
type: boolean
NovaStatedirOwnershipSkip:
type: comma_delimited_list
description: >
List of paths relative to nova_statedir to ignore when recursively setting the
ownership and selinux context.
default:
- 'triliovault-mounts'
resources:
@ -201,6 +208,13 @@ outputs:
- ''
- - 'TRIPLEO_DEPLOY_IDENTIFIER='
- {get_param: DeployIdentifier}
- list_join:
- '='
- - 'NOVA_STATEDIR_OWNERSHIP_SKIP'
- list_join:
- ':'
- {get_param: NovaStatedirOwnershipSkip}
step_4:
map_merge:
- nova_wait_for_placement_service:

View File

@ -107,13 +107,20 @@ class NovaStatedirOwnershipManager(object):
docker nova uid/gid is not known in this context).
"""
def __init__(self, statedir, upgrade_marker='upgrade_marker',
nova_user='nova'):
nova_user='nova', exclude_paths=None):
self.statedir = statedir
self.nova_user = nova_user
self.upgrade_marker_path = os.path.join(statedir, upgrade_marker)
self.upgrade = os.path.exists(self.upgrade_marker_path)
self.exclude_paths = [self.upgrade_marker_path]
if exclude_paths is not None:
for p in exclude_paths:
if not p.startswith(os.path.sep):
p = os.path.join(self.statedir, p)
self.exclude_paths.append(p)
self.target_uid, self.target_gid = self._get_nova_ids()
self.previous_uid, self.previous_gid = self._get_previous_nova_ids()
self.id_change = (self.target_uid, self.target_gid) != \
@ -134,7 +141,7 @@ class NovaStatedirOwnershipManager(object):
for f in os.listdir(top):
pathname = os.path.join(top, f)
if pathname == self.upgrade_marker_path:
if pathname in self.exclude_paths:
continue
try:
@ -181,5 +188,12 @@ class NovaStatedirOwnershipManager(object):
LOG.info('Nova statedir ownership complete')
def get_exclude_paths():
exclude_paths = os.environ.get('NOVA_STATEDIR_OWNERSHIP_SKIP')
if exclude_paths is not None:
exclude_paths = exclude_paths.split(os.pathsep)
return exclude_paths
if __name__ == '__main__':
NovaStatedirOwnershipManager('/var/lib/nova').run()
NovaStatedirOwnershipManager('/var/lib/nova', exclude_paths=get_exclude_paths())

View File

@ -15,12 +15,14 @@
import contextlib
import mock
import os
from os import stat as orig_stat
import six
import stat
from oslotest import base
from docker_config_scripts.nova_statedir_ownership import get_exclude_paths # noqa: E402
from docker_config_scripts.nova_statedir_ownership import \
NovaStatedirOwnershipManager # noqa: E402
from docker_config_scripts.nova_statedir_ownership import PathManager # noqa: E402
@ -311,3 +313,31 @@ class NovaStatedirOwnershipManagerTestCase(base.BaseTestCase):
for fn, expected in six.iteritems(expected_changes):
assert_ids(testtree, fn, expected[0], expected[1])
fake_unlink.assert_called_with('/var/lib/nova/upgrade_marker')
def test_exclude_path(self):
testtree = generate_testtree1(current_uid, current_gid)
with fake_testtree(testtree) as (
fake_chown, _, fake_listdir, fake_stat, _):
manager = NovaStatedirOwnershipManager(
'/var/lib/nova',
exclude_paths=['instances/foo/bar', '/var/lib/nova/instances/foo/removeddir']
)
manager.run()
self.assertIn('/var/lib/nova/instances/foo/bar', manager.exclude_paths)
self.assertIn('/var/lib/nova/instances/foo/removeddir', manager.exclude_paths)
self.assertNotIn(mock.call('/var/lib/nova/instances/foo/bar'), fake_stat.call_args_list)
self.assertNotIn(mock.call('/var/lib/nova/instances/foo/bar'), fake_chown.call_args_list)
self.assertNotIn(mock.call('/var/lib/nova/instances/foo/removeddir'), fake_stat.call_args_list)
self.assertNotIn(mock.call('/var/lib/nova/instances/foo/removeddir'), fake_chown.call_args_list)
self.assertNotIn(mock.call('/var/lib/nova/instances/foo/removeddir'), fake_listdir.call_args_list)
@mock.patch.dict(os.environ, {'NOVA_STATEDIR_OWNERSHIP_SKIP': 'foo:bar:foo/bar/baz'})
def test_get_exclude_paths(self):
expected = [
'foo',
'bar',
'foo/bar/baz'
]
exclude_paths = get_exclude_paths()
self.assertEqual(exclude_paths, expected)