Changing file owner when upgrading mariadb

When we upgrade mariadb version we mount volumes with data and
config files.

As we use new images we cannot make assumption that UIDs are the same
as on the old image so we set a new files and directories owner.

Two new functions have been added: _restore_directory() and
_restore_home_directory() in class Manager which are responsible to
copy files from the volume to the instance file system and to change
owner and group of the files.

The new function is located in base Manager class as it very likely
that other datastores may use it as well.

Co-Authored-By: Przemysław Godek <p.godek@partner.samsung.com>
Change-Id: I3c39f51b471081eeabed55070dc91807544a2dda
Story: #2005398
Task: #30391
Signed-off-by: Kasper Hasior <k.hasior@samsung.com>
This commit is contained in:
Kasper Hasior 2019-04-03 13:09:51 +02:00
parent f4e17a34b9
commit a1df0dbb03
5 changed files with 70 additions and 8 deletions

View File

@ -16,6 +16,7 @@
import inspect
import operator
import os
import pwd
import re
import stat
import tempfile
@ -861,3 +862,8 @@ def is_mount(path):
directory_dev = get_device(path, as_root=True)
parent_dev = get_device(os.path.join(path, '..'), as_root=True)
return directory_dev != parent_dev
def get_current_user():
"""Returns name of the current OS user"""
return pwd.getpwuid(os.getuid())[0]

View File

@ -16,6 +16,7 @@
import abc
import operator
import os
from oslo_config import cfg as oslo_cfg
from oslo_log import log as logging
@ -409,6 +410,21 @@ class Manager(periodic_task.PeriodicTasks):
"""
pass
def _restore_directory(self, restore_dir, target_dir, owner=None):
restore_path = os.path.join(restore_dir, ".")
operating_system.copy(restore_path, target_dir,
preserve=True, as_root=True)
if owner is not None:
operating_system.chown(path=target_dir, user=owner, group=owner,
recursive=True, as_root=True)
def _restore_home_directory(self, saved_home_dir):
home_dir = os.path.expanduser("~")
home_owner = operating_system.get_current_user()
self._restore_directory(restore_dir=saved_home_dir,
target_dir=home_dir,
owner=home_owner)
#################
# Service related
#################

View File

@ -278,17 +278,20 @@ class MySqlManager(manager.Manager):
self.mount_volume(context, mount_point=upgrade_info['mount_point'],
device_path=upgrade_info['device'],
write_to_fstab=True)
operating_system.chown(path=upgrade_info['mount_point'],
user=service.MYSQL_OWNER,
group=service.MYSQL_OWNER,
recursive=True, as_root=True)
self._restore_home_directory(upgrade_info['home_save'])
if operating_system.exists(upgrade_info['save_etc_dir'],
is_directory=True, as_root=True):
operating_system.copy("%s/." % upgrade_info['save_etc_dir'],
"/etc", preserve=True, as_root=True)
self._restore_directory(upgrade_info['save_etc_dir'], "/etc")
self._restore_directory("%s/." % upgrade_info['save_dir'],
"/etc/mysql")
operating_system.copy("%s/." % upgrade_info['save_dir'], "/etc/mysql",
preserve=True, as_root=True)
operating_system.copy("%s/." % upgrade_info['home_save'],
os.path.expanduser('~'),
preserve=True, as_root=True)
self.configuration_manager.refresh_cache()
app.start_mysql()
app.status.end_restart()

View File

@ -81,9 +81,10 @@ class BaseDbStatus(object):
# Set the value of __prepared_completed based on the existence of
# the file. This is required as the state is cached so this method
# must be called any time the existence of the file changes.
self.__prepare_completed = os.path.isfile(
is_file = os.path.isfile(
guestagent_utils.build_file_path(
self.GUESTAGENT_DIR, self.PREPARE_END_FILENAME))
self.__prepare_completed = is_file if is_file else None
def begin_install(self):
"""First call of the DB prepare."""

View File

@ -484,6 +484,42 @@ class ManagerTest(trove_testtools.TestCase):
error_occurred=True,
post_processing=ANY)
@patch.object(operating_system, 'copy')
@patch.object(operating_system, 'chown')
def test_restore_directory_with_owner(self, chown_mock, copy_mock):
restore_dir = '/restore_directory'
restore_files = '/restore_directory/.'
target_dir = '/target_directory'
owner = 'owner'
self.manager._restore_directory(restore_dir, target_dir, owner)
copy_mock.assert_called_once_with(restore_files, target_dir,
preserve=True, as_root=True)
chown_mock.assert_called_once_with(path=target_dir, user=owner,
group=owner, recursive=True,
as_root=True)
@patch.object(operating_system, 'copy')
@patch.object(operating_system, 'chown')
def test_restore_directory_without_owner(self, chown_mock, copy_mock):
restore_dir = '/restore_directory'
restore_files = '/restore_directory/.'
target_dir = '/target_directory'
self.manager._restore_directory(restore_dir, target_dir)
copy_mock.assert_called_once_with(restore_files, target_dir,
preserve=True, as_root=True)
chown_mock.assert_not_called()
@patch.object(manager.Manager, '_restore_directory')
@patch.object(operating_system, 'get_current_user', return_value='trove')
def test_restore_home_directory(self, os_mock, restore_mock):
saved_home_dir = '/old_home'
with patch.object(os.path, 'expanduser', return_value='/home/trove'):
self.manager._restore_home_directory(saved_home_dir)
os_mock.assert_any_call()
restore_mock.assert_called_once_with(restore_dir=saved_home_dir,
target_dir='/home/trove',
owner='trove')
def test_module_list(self):
with patch.object(module_manager.ModuleManager, 'read_module_results',
return_value=[