from parallels.plesk.source.legacy import messages
import logging
import os

import parallels.plesk.source.legacy
from parallels.core.utils.unix_utils import format_command
from parallels.core.utils import migrator_utils
from parallels.core import run_and_check_local_command
from parallels.core import MigrationError
from parallels.core.utils.pmm.agent import PmmMigrationAgentBase, DumpAll


class UnixPmmMigrationAgent(PmmMigrationAgentBase):
	""" A wrapper for legacy migration agents."""
	logger = logging.getLogger(__name__)

	def __init__(self, global_context, server, migrator_pmm_dir, settings, cli_options):
		"""Object constructor.

		Arguments:
			global_context: registry for access to global migration storage
			server: an instance of class 'SourceServer'
			migrator_pmm_dir: a directory with migration agent app code
			settings: a config.ini section with source server settings
			cli_options: migration agent CLI options
		"""

		self.migrator_pmm_dir = migrator_pmm_dir
		self.settings = settings
		self.cli_options = cli_options

		super(UnixPmmMigrationAgent, self).__init__(global_context, server)

	@property
	def common_pmm_dir(self):
		return migrator_utils.get_package_extras_file_path(parallels.plesk.source.legacy, 'plesk_11_5_pmm_shared')

	def _run(self, dump_xml_filename, dump_log_filename, selection=DumpAll()):
		"""Run migration agent on a source panel and download the results.
		
		Execute the agent which puts results into XML dump file.
		Download dump XML file and log file to specified locations:
		- dump_xml_filename - local filename to put dump XML to
		- dump_log_filename - local filename to put dump log to

		Raise MigrationError in case of any failure.
		"""
		self._run_agent_script(
			script_filename=self.settings.agent_script_name,
			local_data_filename=dump_xml_filename, remote_data_filename='dump.xml',
			local_log_filename=dump_log_filename, remote_log_filename='dump.log',
			log_step_info_msg=messages.LOG_STEP_CREATE_SOURCE_PANEL_DUMP_XML,
			log_execute_msg=messages.EXECUTE_CREATE_DUMP_XML,
			log_download_data_file_msg=messages.LOG_DOWNLOAD_DUMP_LOG,
			log_download_log_file_msg=messages.LOG_DUMP_XML_TO,
			error_run_script_msg=messages.ERROR_CREATING_DUMP,
			error_download_log_msg=messages.ERROR_DOWNLOADING_DUMP_LOG,
		)

	def check(self):
		"""Execute pre-migration checks on a source panel.

		Raise MigrationError in case of any failure.

		Returns:
			Path to generated report file.
		"""
		self._run_agent_script(
			script_filename='PreMigration.pl',
			local_data_filename=self.check_report_file,
			remote_data_filename='pre-migration.xml',
			local_log_filename=self.check_log_file,
			remote_log_filename='pre-migration.log',
			log_step_info_msg=messages.RUN_PRE_MIGRATION_CHECKS,
			log_execute_msg=messages.EXECUTE_PREMIGRATION_SCRIPT,
			log_download_data_file_msg=messages.DOWNLOAD_PRE_MIGRATION_LOG,
			log_download_log_file_msg=messages.DOWNLOAD_PREMIGRATION_REPORT,
			error_run_script_msg=messages.ERROR_PERFORMING_PRE_MIGRATION,
			error_download_log_msg=messages.ERROR_DOWNLOADING_PRE_MIGRATION_LOG
		)

		return self.check_report_file

	def _run_agent_script(
		self,
		script_filename,
		local_data_filename, remote_data_filename,
		local_log_filename, remote_log_filename,
		log_step_info_msg, log_execute_msg,
		log_download_data_file_msg,
		log_download_log_file_msg,
		error_run_script_msg,
		error_download_log_msg
	):
		self.logger.info(log_step_info_msg)

		try:
			with self._source_server.runner() as runner:
				self.logger.debug(log_execute_msg)
				try:
					runner.sh(
						ur'cd {path}; perl {script} %s > {log} 2>&1' % (
							self.cli_options
						),
						{
							'path':	self.agent_dir,
							'script': script_filename,
							'log': remote_log_filename,
						}
					)
					self.logger.debug(
						log_download_data_file_msg, local_data_filename
					)
					runner.get_file(
						os.path.join(
							self.agent_dir, 
							remote_data_filename
						),
						local_data_filename
					)
				finally:  # always try to download log, even if script failed
					try:
						self.logger.debug(
							log_download_log_file_msg, local_log_filename
						)
						runner.get_file( 
							os.path.join(
								self.agent_dir, 
								remote_log_filename
							),
							local_log_filename
						)
					except Exception as e:
						self.logger.debug(messages.LOG_EXCEPTION, exc_info=True)
						self.logger.error(error_download_log_msg % e)

		except Exception as e:
			self.logger.debug(messages.LOG_EXCEPTION, exc_info=True)
			raise MigrationError(error_run_script_msg % e)

	def _deploy(self):
		"""Deploy migration agent files to a source panel server.
		
		Return path to the directory, where the agent has been deployed.
		"""

		self.logger.info(messages.DEPLOY_MIGRATION_AGENT % self._source_server.ip())

		def local_sh(command):
			return run_and_check_local_command(['/bin/sh', '-c', command])

		with self._source_server.runner() as runner:
			agent_dir = runner.mktempdir(self.settings.agent_home)

		key_pathname = self.global_context.ssh_key_pool.get(
			self._source_server, self.global_context.migrator_server
		).key_pathname
		for local_lib_dir in (self.common_pmm_dir, self.migrator_pmm_dir):
			local_sh(
				format_command(
					"rsync -rltgo "
					"-e 'ssh -i {ssh_key} -p {ssh_port} -o StrictHostKeyChecking=no -o GSSAPIAuthentication=no' "
					"{local_dir}/ {remote_ip}:{remote_dir}",
					ssh_key=key_pathname,
					ssh_port=self._source_server.settings().ssh_auth.port,
					local_dir=local_lib_dir,
					remote_ip=self._source_server.ip(),
					remote_dir=agent_dir
				)
			)
		return agent_dir

	def uninstall(self):
		"""Remove agent files from the source server."""
		with self._source_server.runner() as runner:
			if self.agent_dir:
				runner.sh('test -d {tmpdir} && rm -rf {tmpdir}', {'tmpdir': self.agent_dir})
