diff --git a/trove/guestagent/common/operating_system.py b/trove/guestagent/common/operating_system.py index 89446d1130..6142168f7b 100644 --- a/trove/guestagent/common/operating_system.py +++ b/trove/guestagent/common/operating_system.py @@ -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] diff --git a/trove/guestagent/datastore/manager.py b/trove/guestagent/datastore/manager.py index 3c35b26595..c91d5517e7 100644 --- a/trove/guestagent/datastore/manager.py +++ b/trove/guestagent/datastore/manager.py @@ -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 ################# diff --git a/trove/guestagent/datastore/mysql_common/manager.py b/trove/guestagent/datastore/mysql_common/manager.py index f26d429980..535fef0339 100644 --- a/trove/guestagent/datastore/mysql_common/manager.py +++ b/trove/guestagent/datastore/mysql_common/manager.py @@ -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() diff --git a/trove/guestagent/datastore/service.py b/trove/guestagent/datastore/service.py index aec1e24e22..fb6c698d9a 100644 --- a/trove/guestagent/datastore/service.py +++ b/trove/guestagent/datastore/service.py @@ -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.""" diff --git a/trove/tests/unittests/guestagent/test_manager.py b/trove/tests/unittests/guestagent/test_manager.py index c8bc796e36..938f8e0fcd 100644 --- a/trove/tests/unittests/guestagent/test_manager.py +++ b/trove/tests/unittests/guestagent/test_manager.py @@ -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=[