--- admin/plib/modules/panel-migrator/backend/lib/python/parallels/core/messages/__init__.py.orig +++ admin/plib/modules/panel-migrator/backend/lib/python/parallels/core/messages/__init__.py @@ -2596,6 +2596,18 @@ FAILED_TO_GET_INFO_ABOUT_USER = single_line_message(""" USER_DOES_NOT_EXIST_ON_SERVER = single_line_message(""" System user '{user}' does not exists on {server}. """) +FAILED_TO_DETECT_CAGEFS_STATUS = multi_line_message(""" + Failed to detect whether CageFS is enabled or disabled on {server}. Migrator will consider that it is disabled. + Reason: {reason} +""") +FAILED_TO_DISABLE_CAGEFS = multi_line_message(""" + Failed to disable CageFS for temporary user '{username}' required to transfer files on {server}. + If there are issues with file transfer, that could be the cause. + Reason: {reason} +""") +CAGEFS_IS_ENABLED = single_line_message(""" + CageFS is enabled on {server}, migrator will disable it for all temporary system users needed to copy content +""") USER_EMPTY_UID = single_line_message(""" User '{user}' at {server} has empty UID. Check that information about the user is correct at /etc/passwd file. """) --- admin/plib/modules/panel-migrator/backend/lib/python/parallels/core/utils/user_ssh_access_pool.py.orig +++ admin/plib/modules/panel-migrator/backend/lib/python/parallels/core/utils/user_ssh_access_pool.py @@ -7,8 +7,9 @@ import itertools from parallels.core import messages, MigrationError, MigrationNoRepeatError from parallels.core import safe_format +from parallels.core.runners.base import BaseRunner from parallels.core.runners.exceptions.non_zero_exit_code import NonZeroExitCodeException -from parallels.core.utils.common import is_empty +from parallels.core.utils.common import is_empty, cached from parallels.core.utils.common.logging import create_safe_logger from parallels.core.utils.common_constants import PASSWD_FIELD_UID, PASSWD_FIELD_GID, PASSWD_FIELD_HOMEDIR from parallels.core.utils.entity import Entity @@ -255,8 +256,8 @@ class UserSSHAccessPool(object): runner.remove_file(public_key_filepath) return public_key_contents - @staticmethod - def _create_user(server, username, uid, gid): + @classmethod + def _create_user(cls, server, username, uid, gid): """Create system user for SSH access at specified server with specified username, user ID and group ID :type server: parallels.core.connections.server.Server @@ -265,11 +266,57 @@ class UserSSHAccessPool(object): :type gid: str | unicode """ with server.runner() as runner: + assert isinstance(runner, BaseRunner) runner.sh( u'useradd {username} ' u'-m -g {gid} -o -u {uid} -s /bin/sh', dict(username=username, uid=uid, gid=gid) ) + # CageFS is a CloudLinux feature which allows to restrict access to files of other users. + # When it is enabled, it is not possible to properly configure SSH for temporary user + # to copy files. So we disable CageFS for the temporary user. + if cls._is_cagefs_enabled(server): + try: + runner.sh( + u'{cagefsctl} --disable {username}', + dict(cagefsctl=cls.CAGEFS_BINARY, username=username) + ) + except Exception as e: + logger.debug(messages.LOG_EXCEPTION, exc_info=True) + logger.fwarn( + messages.FAILED_TO_DISABLE_CAGEFS, + reason=unicode(e), username=username, server=server.description() + ) + + @classmethod + @cached + def _is_cagefs_enabled(cls, server): + with server.runner() as runner: + assert isinstance(runner, BaseRunner) + if runner.file_exists(cls.CAGEFS_BINARY): + try: + _, output, _ = runner.sh_unchecked( + '{cagefsctl} --cagefs-status', + dict(cagefsctl=cls.CAGEFS_BINARY) + ) + if 'enabled' in output.lower(): + logger.fdebug(messages.CAGEFS_IS_ENABLED, server=server.description()) + return True + else: + return False + except Exception as e: + logger.debug(messages.LOG_EXCEPTION, exc_info=True) + logger.fwarn( + messages.FAILED_TO_DETECT_CAGEFS_STATUS, + reason=unicode(e), server=server.description() + ) + # Failed to detect status - consider that CageFS is disabled + return False + else: + # No CageFS binary, most probably it is not CloudLinux or CageFS is not installed + return False + + CAGEFS_BINARY = '/usr/sbin/cagefsctl' @staticmethod def _get_user_passwd_info(server, username):