from parallels.core import messages
from parallels.core import safe_format
from parallels.core.actions.base.common_action import CommonAction
from parallels.core.reports.model.issue import Issue
from parallels.core.runners.base import BaseRunner


class CheckSSHOptionsAction(CommonAction):
    """Check source SSH server configuration for options which could block migration.

    The only checked option now is "AllowUsers", which may block connection for users created
    to copy web content securely (plesk-migrator-*).
    """

    def get_description(self):
        """Get short description of action as string

        :rtype: str | unicode
        """
        return messages.CHECK_SSH_OPTIONS_ACTION_DESCRIPTION

    def get_failure_message(self, global_context):
        """Get message for situation when action failed

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :rtype: str | unicode
        """
        return messages.CHECK_SSH_OPTIONS_ACTION_FAILURE

    def is_critical(self):
        """If action is critical or not

        If action is critical and it failed, migration tool completely stops.
        Otherwise it proceeds to the next steps of migrations.

        :rtype: bool
        """
        return False

    def filter_action(self, global_context):
        """Check whether we should run this action or not. By default True - action should be executed.

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :rtype: bool
        """
        return len(self._get_source_web_servers(global_context)) > 0

    def run(self, global_context):
        """Run action

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :rtype: None
        """
        for source_web_server in self._get_source_web_servers(global_context):
            self._check_web_server(global_context, source_web_server)

    @staticmethod
    def _get_source_web_servers(global_context):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :rtype: set[parallels.core.connections.source_server.SourceServer]
        """
        source_web_servers = set()

        for subscription in global_context.iter_all_subscriptions():
            if subscription.web_source_server is None:
                continue

            if subscription.web_source_server.is_windows():
                continue

            source_web_servers.add(subscription.web_source_server)

        return source_web_servers

    @staticmethod
    def _check_web_server(global_context, server):
        """
        :type server: parallels.core.connections.source_server.SourceServer
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :rtype: None
        """
        sshd_config = u'/etc/ssh/sshd_config'

        has_allow_users = False

        with server.runner() as runner:
            assert isinstance(runner, BaseRunner)
            if not runner.file_exists(sshd_config):
                return

            contents = runner.get_file_contents(sshd_config)

            for line in contents.split("\n"):
                line = line.strip().lower()
                if line.startswith('#'):
                    continue

                if 'allowusers' in line:
                    has_allow_users = True
                    if 'plesk-migrator' in line:
                        return

        if has_allow_users:
            global_context.pre_check_report.add_issue(
                u'ssh-allow-users-options',
                Issue.SEVERITY_ERROR,
                safe_format(
                    messages.SSH_ALLOW_USERS_OPTION,
                    server=server.description(),
                    sshd_config=sshd_config
                ), u''
            )
