import logging

from parallels.core import messages
from parallels.core.actions.get_progress import GetProgressAction
from parallels.core.actions.hosting_settings.convert.change_hosting_subscription_web_ips import \
	ChangeHostingSubscriptionWebIPs
from parallels.core.actions.hosting_settings.convert.change_subscription_mail_ips import ChangeSubscriptionMailIPs
from parallels.core.actions.list_ip_addresses import ListIPAddresses
from parallels.core.actions.post_migration_checks.print_report_after_transfer import \
	PrintPostMigrationReportAfterTransfer
from parallels.core.actions.post_migration_checks.test_all_after_transfer import TestAllAfterTransfer
from parallels.core.workflow.extension import WorkflowExtensionBase
from parallels.plesk.source.plesk.actions.suspend_subscriptions import SuspendSubscriptions
from parallels.core.actions.hosting_settings.check.check_database_conflicts import CheckDatabaseConflicts
from parallels.core.actions.hosting_settings.convert.fix_windows_php53_isapi import FixWindowsPHP53ISAPI
from parallels.core.actions.hosting_settings.import_backups import ImportBackups
from parallels.core.actions.hosting_settings.remove_imported_backups import RemoveImportedBackups
from parallels.core.actions.hosting_settings.restore_subscription_hosting_settings import \
	RestoreSubscriptionHostingSettings
from parallels.core.actions.import_plans_not_supported import ImportPlansNotSupported
from parallels.core.actions.migration_list.check_migration_list_not_exists_for_generation \
	import CheckMigrationListNotExistsForGeneration
from parallels.core.actions.migration_list.check_migration_list_exists_for_migration \
	import CheckMigrationListExistsForMigration
from parallels.core.actions.migration_list.generate import GenerateMigrationList
from parallels.core.actions.migration_list.write import WriteMigrationList
from parallels.core.actions.print_subscription_status import PrintSubscriptionStatus
from parallels.core.actions.quick_check_cli_options import QuickCheckCLIOptions
from parallels.core.actions.read_ip_mapping import ReadIPMapping
from parallels.core.actions.callback import CallbackAction
from parallels.core.actions.transfer_agent.stop import Stop as StopTransferAgent
from parallels.core.actions.transfer_agent.start import Start as StartTransferAgent
from parallels.core.actions.shutdown_windows_rsync_servers import ShutdownWindowsRsyncServers
from parallels.core.actions.utils.logging_properties \
	import LoggingProperties
from parallels.core.actions.base.legacy_action \
	import LegacyAction
from parallels.core.actions.base.compound_action \
	import CompoundAction
from parallels.core.actions.base.entry_point_action \
	import EntryPointAction
from parallels.core.actions.close_ssh_connections import CloseSSHConnections
from parallels.core.actions.hosting_settings.convert.dns \
	import DNS as ActionHostingSettingsConvertDNS
from parallels.plesk.source.plesk.actions.content.web.check_target_web_hosting \
	import CheckTargetWebHosting
from parallels.core.actions.backup.create_converted \
	import CreateConverted
from parallels.core.actions.backup.save_converted \
	import SaveConverted
from parallels.core.actions.backup.remove_content \
	import RemoveContent
from parallels.core.actions.hosting_settings.convert.remap_databases \
	import RemapDatabases
from parallels.core.actions.hosting_settings.convert.remove_subscription_to_plan_relation \
	import RemoveSubscriptionToPlanRelation
from parallels.core.actions.hosting_settings.convert.remove_subscription_default_db_server \
	import RemoveSubscriptionDefaultDBServer
from parallels.core.actions.hosting_settings.convert.remove_subscription_limits_and_permissions \
	import RemoveSubscriptionLimitsAndPermissions
from parallels.core.actions.hosting_settings.convert.change_webmail_to_horde \
	import ChangeWebmailToHorde
from parallels.core.actions.hosting_settings.convert.remove_subscription_external_id \
	import RemoveSubscriptionExternalId
from parallels.core.actions.hosting_settings.convert.change_sysuser_password \
	import ChangeSysuserPassword
from parallels.core.actions.hosting_settings.convert.change_smartermail_password \
	import ChangeSmartermailPassword
from parallels.core.actions.hosting_settings.convert.change_sysuser_login \
	import ChangeSysuserLogin
from parallels.core.actions.hosting_settings.restore_sysuser_logins \
	import RestoreSysuserLogins
from parallels.core.actions.hosting_settings.check.email_empty_password \
	import EmailEmptyPassword
from parallels.core.actions.dns.forwarding.set_dns_forwarding_not_supported \
	import SetDNSForwardingNotSupported
from parallels.core.actions.dns.forwarding.undo_dns_forwarding_not_supported \
	import UndoDNSForwardingNotSupported
from parallels.core.actions.dns.timings.set_dns_timings_not_supported \
	import SetDNSTimingsNotSupported
from parallels.core.actions.remove_ssh_keys \
	import RemoveSSHKeys
from parallels.core.actions.content.mail.copy_content \
	import CopyMailContent
from parallels.core.actions.content.database.copy_database_content \
	import CopyDatabaseContent
from parallels.core.utils.backup_adapter import SubscriptionBackup
from parallels.core.utils.backup_adapter import SubscriptionBackupRaw
from parallels.core.actions.hosting_analyser.analyse import AnalyseHosting
from parallels.core.actions.uninstall_dump_agent import UninstallDumpAgentAction


logger = logging.getLogger(__name__)


class SharedHostingWorkflowExtension(WorkflowExtensionBase):
	"""Common workflow for shared hosting migration"""

	def extend_workflow(self, workflow):
		self._configure_shared_actions(workflow)
		self._configure_entry_points(workflow)

	def _configure_shared_actions(self, workflow):
		self._configure_shared_action_fetch_source(workflow)
		self._configure_shared_action_fetch_source_shallow(workflow)
		self._configure_shared_action_fetch_target(workflow)
		self._configure_shared_action_check_infrastructure(workflow)
		self._configure_shared_action_sync_web_content_assets(workflow)
		self._configure_shared_action_copy_web_files(workflow)
		self._configure_shared_action_copy_web_content(workflow)
		self._configure_shared_action_copy_mail_content(workflow)
		self._configure_shared_action_analyse_hosting(workflow)
		self._configure_shared_action_cleanup(workflow)
		self._configure_shared_action_copy_db_content(workflow)
		self._configure_shared_action_copy_content(workflow)
		self._configure_shared_action_check_updates(workflow)
		self._configure_shared_action_check_connections(workflow)
		self._configure_shared_action_check_sources(workflow)
		self._configure_shared_action_check_target(workflow)
		self._configure_shared_action_check_target_licenses(workflow)
		self._configure_shared_action_read_migration_list(workflow)
		self._configure_shared_action_read_ip_mapping(workflow)
		self._configure_shared_action_convert(workflow)
		self._configure_shared_action_convert_silent(workflow)
		self._configure_shared_action_verify_hosting(workflow)
		self._configure_shared_action_finalize(workflow)
		self._configure_shared_action_convert_hosting(workflow)
		self._configure_shared_action_initial_pre_checks(workflow)
		self._configure_shared_action_post_migration_finalize(workflow)
		self._configure_shared_action_post_migration_prepare(workflow)

	def _configure_entry_points(self, workflow):
		self._configure_entry_point_get_progress(workflow)
		self._configure_entry_point_callback(workflow)
		self._configure_entry_point_start_transfer_agent(workflow)
		self._configure_entry_point_analyse_hosting(workflow)
		self._configure_entry_point_generate_migration_list(workflow)
		self._configure_entry_point_write_migration_list(workflow)
		self._configure_entry_point_check(workflow)
		self._configure_entry_point_check_infrastructure(workflow)
		self._configure_entry_point_check_target_licenses(workflow)
		self._configure_entry_point_import_resellers(workflow)
		self._configure_entry_point_import_plans(workflow)
		self._configure_entry_point_transfer_accounts(workflow)
		self._configure_entry_point_copy_content(workflow)
		self._configure_entry_point_copy_mail_content(workflow)
		self._configure_entry_point_copy_web_content(workflow)
		self._configure_entry_point_copy_db_content(workflow)
		self._configure_entry_point_verify_hosting(workflow)
		self._configure_entry_point_set_dns_forwarding(workflow)
		self._configure_entry_point_undo_dns_forwarding(workflow)
		self._configure_entry_point_set_low_dns_timings(workflow)
		self._configure_entry_point_test_all(workflow)
		self._configure_entry_point_test_sites(workflow)
		self._configure_entry_point_test_dns(workflow)
		self._configure_entry_point_test_mail(workflow)
		self._configure_entry_point_test_users(workflow)
		self._configure_entry_point_test_databases(workflow)
		self._configure_entry_point_test_services(workflow)
		self._configure_entry_point_list_ip_addresses(workflow)

	@staticmethod
	def _configure_shared_action_fetch_source(workflow):
		workflow.add_shared_action('fetch-source', CompoundAction(
			description=messages.FETCH_INFORMATION_FROM_SOURCE_PANEL))

	@staticmethod
	def _configure_shared_action_fetch_source_shallow(workflow):
		# By default, consider shallow backup is the same as full backup,
		# and fetch source shallow is the same as fetch source
		workflow.add_shared_action(
			'fetch-source-shallow',
			workflow.get_shared_action('fetch-source')
		)

	@staticmethod
	def _configure_shared_action_fetch_target(workflow):
		workflow.add_shared_action('fetch-target', LegacyAction(
			description=messages.FETCH_INFORMATION_FROM_TARGET_SERVERS,
			function=lambda ctx: ctx.migrator._fetch(ctx.options)
		))

	@staticmethod
	def _configure_shared_action_check_infrastructure(workflow):
		workflow.add_shared_action('check-infrastructure', LegacyAction(
			description=messages.CHECK_INFRASTRUCTURE_CONNECTIONS_AND_DISK_SPACE,
			function=lambda ctx: ctx.migrator.check_infrastructure(ctx.options)
		))

	@staticmethod
	def _configure_shared_action_copy_content(workflow):
		workflow.add_shared_action('copy-content', CompoundAction(
			description=messages.COPY_WEB_DATABASE_AND_MAIL_CONTENT,
			run_by_subscription=True
		))
		workflow.get_shared_action('copy-content').insert_action(
			'web', workflow.get_shared_action_pointer('copy-web-content')
		)
		workflow.get_shared_action('copy-content').insert_action(
			'database', workflow.get_shared_action_pointer('copy-db-content')
		)
		workflow.get_shared_action('copy-content').insert_action(
			'mail', workflow.get_shared_action_pointer('copy-mail-content')
		)

	@staticmethod
	def _configure_shared_action_copy_web_files(workflow):
		workflow.add_shared_action('copy-web-files', CompoundAction(
			description=messages.ACTION_COPY_WEB_FILES
		))

	@staticmethod
	def _configure_shared_action_copy_web_content(workflow):
		workflow.add_shared_action('copy-web-content', CompoundAction(
			description=messages.COPY_WEB_FILES_AND_SYNC_WEB))
		workflow.get_shared_action('copy-web-content').insert_action(
			'copy-web-files', workflow.get_shared_action('copy-web-files')
		)
		workflow.get_shared_action('copy-web-content').insert_action(
			'web-assets', workflow.get_shared_action('sync-web-content-assets')
		)

	@staticmethod
	def _configure_shared_action_sync_web_content_assets(workflow):
		workflow.add_shared_action('sync-web-content-assets', CompoundAction(
			description=messages.ACTION_SYNC_WEB_CONTENT_ASSESTS
		))

	@staticmethod
	def _configure_shared_action_copy_mail_content(workflow):
		workflow.add_shared_action('copy-mail-content', CopyMailContent())

	@staticmethod
	def _configure_shared_action_analyse_hosting(workflow):
		workflow.add_shared_action('analyse-hosting', AnalyseHosting())

	@staticmethod
	def _configure_shared_action_cleanup(workflow):
		workflow.add_shared_action('cleanup', CompoundAction(
			description='Perform final clean up',
			logging_properties=LoggingProperties(compound=False)
		))
		workflow.get_shared_action('cleanup').insert_action(
			'uninstall-agent', UninstallDumpAgentAction()
		)
		workflow.get_shared_action('cleanup').insert_action(
			'remove-ssh-keys', RemoveSSHKeys()
		)
		workflow.get_shared_action('cleanup').insert_action(
			'close-ssh-connections', CloseSSHConnections()
		)
		workflow.get_shared_action('cleanup').insert_action(
			'shutdown-windows-rsync-servers', ShutdownWindowsRsyncServers()
		)
		workflow.get_shared_action('cleanup').insert_action(
			'shutdown-windows-agents', StopTransferAgent()
		)

	@staticmethod
	def _configure_shared_action_copy_db_content(workflow):
		workflow.add_shared_action('copy-db-content', CopyDatabaseContent())

	@staticmethod
	def _configure_shared_action_check_updates(workflow):
		workflow.add_shared_action('check-updates', LegacyAction(
			description=messages.ACTION_CHECK_MIGRATOR_UPDATES,
			function=lambda ctx: ctx.migrator._check_updates(),
			is_critical=False
		))

	@staticmethod
	def _configure_shared_action_check_connections(workflow):
		workflow.add_shared_action('check-connections', LegacyAction(
			description=messages.ACTION_CHECK_CONNECTIONS,
			function=lambda ctx: ctx.migrator._check_connections(ctx.options)
		))

	@staticmethod
	def _configure_shared_action_check_sources(workflow):
		workflow.add_shared_action('check-sources', LegacyAction(
			description=messages.ACTION_CHECK_SOURCE_CONNECTIONS,
			function=lambda ctx: ctx.migrator._check_sources()
		))

	@staticmethod
	def _configure_shared_action_check_target(workflow):
		workflow.add_shared_action('check-target', LegacyAction(
			description=messages.ACTION_CHECK_TARGET_CONNECTIONS,
			function=lambda ctx: ctx.migrator._check_target()
		))

	@staticmethod
	def _configure_shared_action_check_target_licenses(workflow):
		workflow.add_shared_action('check-target-licenses', CompoundAction())

	@staticmethod
	def _configure_shared_action_read_migration_list(workflow):
		workflow.add_shared_action('read-migration-list', LegacyAction(
			description=messages.ACTION_READ_MIGRATION_LIST,
			function=lambda ctx: ctx.migrator._read_migration_list_lazy(ctx.options)
		))

	@staticmethod
	def _configure_shared_action_read_ip_mapping(workflow):
		workflow.add_shared_action('read-ip-mapping', ReadIPMapping())

	@staticmethod
	def _configure_shared_action_convert(workflow):
		workflow.add_shared_action('convert', LegacyAction(
			description=messages.CONVERT_CLIENTS_AND_SUBSCRIPTIONS,
			function=lambda ctx: ctx.migrator.convert(ctx.options)
		))

	@staticmethod
	def _configure_shared_action_convert_silent(workflow):
		workflow.add_shared_action('convert-silent', LegacyAction(
			description=messages.CONVERT_CLIENTS_AND_SUBSCRIPTIONS_1,
			function=lambda ctx: ctx.migrator.convert(
				ctx.options,  # we do not want to see pre-migration and conversion
				# messages when calling commands except for  # 'transfer-accounts' and 'check', because user
				# should already executed 'transfer-accounts',  # or 'check' commands, which displayed these messages
				merge_pre_migration_report=False
			)
		))

	@staticmethod
	def _configure_shared_action_verify_hosting(workflow):
		workflow.add_shared_action('verify-hosting', CompoundAction(
			description=messages.ACTION_VERIFY_HOSTING
		))

	@staticmethod
	def _configure_shared_action_finalize(workflow):
		workflow.add_shared_action('finalize', LegacyAction(
			description=messages.COUNT_MIGRATION_STATISTICS_PRINT_REPORT,
			function=lambda ctx: ctx.migrator._finalize(True, ctx.options),
			logging_properties=LoggingProperties(info_log=False),
			is_critical=False,
		))

	@staticmethod
	def _configure_shared_action_post_migration_prepare(workflow):
		workflow.add_shared_action('post-migration-prepare', CompoundAction())
		workflow.get_shared_action('post-migration-prepare').insert_action(
			'check-migration-list', CheckMigrationListExistsForMigration()
		)
		workflow.get_shared_action('post-migration-prepare').insert_actions(
			workflow.get_shared_action('initial-pre-checks').get_all_actions()
		)
		workflow.get_shared_action('post-migration-prepare').insert_action(
			'fetch-source-shallow',
			workflow.get_shared_action_pointer('fetch-source-shallow')
		)
		workflow.get_shared_action('post-migration-prepare').insert_action(
			'read-migration-list',
			workflow.get_shared_action_pointer('read-migration-list')
		)
		workflow.get_shared_action('post-migration-prepare').insert_action(
			'read-ip-mapping',
			workflow.get_shared_action_pointer('read-ip-mapping')
		)
		workflow.get_shared_action('post-migration-prepare').insert_action(
			'fetch-source',
			workflow.get_shared_action('fetch-source')
		)
		workflow.get_shared_action('post-migration-prepare').insert_action(
			'fetch-target',
			workflow.get_shared_action_pointer('fetch-target')
		)
		workflow.get_shared_action('post-migration-prepare').insert_action(
			'read-migration-list',
			workflow.get_shared_action('read-migration-list')
		)
		workflow.get_shared_action('post-migration-prepare').insert_action(
			'convert',
			workflow.get_shared_action_pointer('convert-silent')
		)
		workflow.get_shared_action('post-migration-prepare').insert_action(
			'convert',
			workflow.get_shared_action_pointer('convert-hosting')
		)

	@staticmethod
	def _configure_shared_action_post_migration_finalize(workflow):
		workflow.add_shared_action('post-migration-finalize', CompoundAction())
		workflow.get_shared_action('post-migration-finalize').insert_action(
			'cleanup', workflow.get_shared_action('cleanup')
		)
		workflow.get_shared_action('post-migration-finalize').insert_action(
			'finalize',
			workflow.get_shared_action('finalize')
		)

	@staticmethod
	def _configure_shared_action_initial_pre_checks(workflow):
		workflow.add_shared_action('initial-pre-checks', CompoundAction())
		workflow.get_shared_action('initial-pre-checks').insert_action(
			'check-cli-options', QuickCheckCLIOptions()
		)
		workflow.get_shared_action('initial-pre-checks').insert_action(
			'check-updates',
			workflow.get_shared_action('check-updates')
		)
		workflow.get_shared_action('initial-pre-checks').insert_action(
			'check-connections',
			workflow.get_shared_action_pointer('check-connections')
		)
		workflow.get_shared_action('initial-pre-checks').insert_action(
			'check-target-licenses',
			workflow.get_shared_action('check-target-licenses')
		)

	@staticmethod
	def _configure_entry_point_generate_migration_list(workflow):
		workflow.add_entry_point('generate-migration-list', EntryPointAction())

		workflow.get_path('generate-migration-list').insert_action(
			'check-migration-list-exists', CheckMigrationListNotExistsForGeneration()
		)
		workflow.get_path('generate-migration-list').insert_action(
			'check-updates',
			workflow.get_shared_action('check-updates')
		)
		workflow.get_path('generate-migration-list').insert_action(
			'check-connections',
			workflow.get_shared_action_pointer('check-connections')
		)
		workflow.get_path('generate-migration-list').insert_action(
			'check-target-licenses',
			workflow.get_shared_action('check-target-licenses')
		)
		workflow.get_path('generate-migration-list').insert_action(
			'fetch-source',
			workflow.get_shared_action_pointer('fetch-source-shallow')
		)
		workflow.get_path('generate-migration-list').insert_action(
			'generate-migration-list', GenerateMigrationList(),
		)
		workflow.get_path('generate-migration-list').insert_action(
			'analyse-hosting', workflow.get_shared_action('analyse-hosting')
		)

		workflow.get_path('generate-migration-list').insert_action(
			'cleanup', workflow.get_shared_action('cleanup')
		)
		workflow.get_path('generate-migration-list').register_overall_shutdown('cleanup')

	@staticmethod
	def _configure_entry_point_write_migration_list(workflow):
		workflow.add_entry_point('write-migration-list', EntryPointAction())
		workflow.get_path('write-migration-list').insert_action(
			'check-migration-list-exists', CheckMigrationListNotExistsForGeneration()
		)
		workflow.get_path('write-migration-list').insert_action(
			'write-migration-list', WriteMigrationList(),
		)
		workflow.get_path('write-migration-list').insert_action(
			'cleanup', workflow.get_shared_action('cleanup')
		)
		workflow.get_path('write-migration-list').register_overall_shutdown('cleanup')

	@staticmethod
	def _configure_entry_point_check(workflow):
		workflow.add_entry_point('check', EntryPointAction())
		workflow.get_path('check').insert_action(
			'check-cli-options', QuickCheckCLIOptions()
		)
		workflow.get_path('check').insert_action(
			'check-migration-list', CheckMigrationListExistsForMigration()
		)
		workflow.get_path('check').insert_action(
			'check-updates',
			workflow.get_shared_action('check-updates')
		)
		workflow.get_path('check').insert_action(
			'check-connections',
			workflow.get_shared_action_pointer('check-connections')
		)
		workflow.get_path('check').insert_action(
			'check-target-licenses',
			workflow.get_shared_action('check-target-licenses')
		)
		workflow.get_path('check').insert_action(
			'fetch-source-shallow',
			workflow.get_shared_action_pointer('fetch-source-shallow')
		)
		workflow.get_path('check').insert_action(
			'read-migration-list',
			workflow.get_shared_action_pointer('read-migration-list')
		)
		workflow.get_path('check').insert_action(
			'read-ip-mapping',
			workflow.get_shared_action_pointer('read-ip-mapping')
		)
		workflow.get_path('check').insert_action(
			'fetch-source',
			workflow.get_shared_action('fetch-source')
		)
		workflow.get_path('check').insert_action(
			'fetch-target',
			workflow.get_shared_action_pointer('fetch-target')
		)
		workflow.get_path('check').insert_action('check-data', CompoundAction())
		workflow.get_path('check/check-data').insert_action('check-conflicts', LegacyAction(
			description=messages.CHECK_CONFLICTS_FOR_CLIENTS_SUBSCRIPTIONS_RESELLER,
			function=lambda ctx: ctx.migrator._convert_model(
				ctx.pre_check_report, ctx.target_existing_objects,
				ctx.options, soft_check=True
			)
		))
		workflow.get_path('check/check-data').insert_action(
			'check-email-empty-password',
			EmailEmptyPassword(SubscriptionBackupRaw())
		)
		workflow.get_path('check').insert_action(
			'cleanup', workflow.get_shared_action('cleanup')
		)
		workflow.get_path('check').insert_action(
			'print-report', LegacyAction(
				description=messages.ACTION_PRINT_PRE_MIGRATION_ERROR,
				function=lambda ctx: ctx.migrator.print_report(
					ctx.pre_check_report, "pre_migration_report_tree",
					show_no_issue_branches=False
				),
				is_critical=False
			)
		)
		workflow.get_path('check').register_overall_shutdown('cleanup')

	@staticmethod
	def _configure_entry_point_check_infrastructure(workflow):
		workflow.add_entry_point('check-infrastructure', EntryPointAction())
		workflow.get_path('check-infrastructure').insert_action(
			'check-infrastructure',
			workflow.get_shared_action_pointer('check-infrastructure')
		)

	@staticmethod
	def _configure_entry_point_check_target_licenses(workflow):
		workflow.add_entry_point('check-target-licenses', EntryPointAction())
		workflow.get_path('check-target-licenses').insert_action(
			'check-target-licenses',
			workflow.get_shared_action_pointer('check-target-licenses')
		)

	@staticmethod
	def _configure_entry_point_import_resellers(workflow):
		workflow.add_entry_point('import-resellers', EntryPointAction())
		workflow.get_path('import-resellers').insert_actions(
			workflow.get_shared_action('initial-pre-checks').get_all_actions()
		)
		workflow.get_path('import-resellers').insert_action(
			'fetch-source',
			workflow.get_shared_action('fetch-source')
		)
		workflow.get_path('import-resellers').insert_action(
			'import-resellers',
			LegacyAction(
				description='Import resellers',
				function=lambda ctx: ctx.migrator._import_resellers(ctx.options)
			)
		)
		workflow.get_path('import-resellers').insert_action(
			'cleanup',
			workflow.get_shared_action('cleanup')
		)
		workflow.get_path('import-resellers').register_overall_shutdown('cleanup')

	@staticmethod
	def _configure_entry_point_import_plans(workflow):
		workflow.add_entry_point('import-plans', EntryPointAction())
		workflow.get_path('import-plans').insert_action(
			'check-target-panel', ImportPlansNotSupported()
		)

	@staticmethod
	def _configure_shared_action_convert_hosting(workflow):
		workflow.add_shared_action('convert-hosting', CompoundAction(
			description=messages.CONVERT_HOSTING_SETTINGS_TARGET_PANEL_FORMAT,
			run_by_subscription=False, # run by layer for better logging, no sense to run by subscription
			logging_properties=LoggingProperties(compound=False)
		))
		convert_hosting = workflow.get_shared_action(
			'convert-hosting'
		)
		convert_hosting.insert_actions([
			('create-converted-backup', CreateConverted(SubscriptionBackup())),
			('convert-dns', ActionHostingSettingsConvertDNS()),
			('remap-databases', RemapDatabases(SubscriptionBackup())),
			('remove-subscription-to-plan-relation', RemoveSubscriptionToPlanRelation(SubscriptionBackup())),
			('remove-subscription-default-db-server', RemoveSubscriptionDefaultDBServer(SubscriptionBackup())),
			('remove-subscription-limits-and-permissions',
				RemoveSubscriptionLimitsAndPermissions(SubscriptionBackup())),
			('change-webmail-to-horde', ChangeWebmailToHorde(SubscriptionBackup())),
			(
				'change-hosting-subscription-web-ips',
				ChangeHostingSubscriptionWebIPs(SubscriptionBackup())
			),
			(
				'change-subscription-mail-ips',
				ChangeSubscriptionMailIPs(SubscriptionBackup())
			),
			('remove-subscription-external-id', RemoveSubscriptionExternalId(SubscriptionBackup())),
			('change-sysuser-password', ChangeSysuserPassword(SubscriptionBackup())),
			('change-smartermail-password', ChangeSmartermailPassword(SubscriptionBackup())),
			('fix-windows-php53-isapi', FixWindowsPHP53ISAPI(SubscriptionBackup())),
			('check-database-conflicts', CheckDatabaseConflicts(SubscriptionBackup())),
			('backup-remove-content', RemoveContent(SubscriptionBackup())),
			('check-email-empty-password', EmailEmptyPassword(SubscriptionBackup())),
			('save-backup', SaveConverted(SubscriptionBackup())),
		])

	@staticmethod
	def _configure_entry_point_transfer_accounts(workflow):
		workflow.add_entry_point('transfer-accounts', EntryPointAction())
		workflow.get_path('transfer-accounts').insert_action(
			'check-cli-options', QuickCheckCLIOptions()
		)
		workflow.get_path('transfer-accounts').insert_action(
			'check-migration-list', CheckMigrationListExistsForMigration()
		)
		workflow.get_path('transfer-accounts').insert_action(
			'check-updates',
			workflow.get_shared_action('check-updates')
		)
		workflow.get_path('transfer-accounts').insert_action(
			'check-connections',
			workflow.get_shared_action_pointer('check-connections')
		)
		workflow.get_path('transfer-accounts').insert_action(
			'check-target-licenses',
			workflow.get_shared_action_pointer('check-target-licenses')
		)
		workflow.get_path('transfer-accounts').insert_action(
			'fetch-source-shallow',
			workflow.get_shared_action_pointer('fetch-source-shallow')
		)
		workflow.get_path('transfer-accounts').insert_action(
			'read-migration-list',
			workflow.get_shared_action_pointer('read-migration-list')
		)
		workflow.get_path('transfer-accounts').insert_action(
			'read-ip-mapping',
			workflow.get_shared_action_pointer('read-ip-mapping')
		)
		workflow.get_path('transfer-accounts').insert_action(
			'fetch-source', workflow.get_shared_action('fetch-source')
		)
		workflow.get_path('transfer-accounts').insert_action(
			'fetch-target',
			workflow.get_shared_action_pointer('fetch-target')
		)
		workflow.get_path('transfer-accounts').insert_action(
			'convert',
			workflow.get_shared_action_pointer('convert')
		)
		workflow.get_path('transfer-accounts').insert_action('check-main-node-disk-space-requirements', LegacyAction(
			description=messages.CHECK_DISK_SPACE_REQUIREMENTS_FOR_MAIN,
			function=lambda ctx: ctx.migrator.check_main_node_disk_space_requirements(ctx.options)
		))
		workflow.get_path('transfer-accounts').insert_action('suspend-source-subscription', SuspendSubscriptions())
		workflow.get_path('transfer-accounts').insert_action(
			'restore', CompoundAction("Restore")
		)
		workflow.get_path('transfer-accounts').insert_action('set-windows-security-policy', LegacyAction(
			description=messages.SET_SECURITY_POLICY_WINDOWS_NODES,
			function=lambda ctx: ctx.migrator.set_security_policy()
		))
		workflow.get_path('transfer-accounts').insert_action(
			'restore-hosting', CompoundAction("Restore hosting settings")
		)
		workflow.get_path('transfer-accounts/restore-hosting').insert_action(
			'convert-hosting',
			workflow.get_shared_action('convert-hosting')
		)
		workflow.get_path('transfer-accounts/restore-hosting').insert_action(
			'restore-sysuser-logins', CompoundAction(
				description=messages.RESTORE_LOGINS_SYSTEM_USERS,
				run_by_subscription=False
			)
		)
		workflow.get_path('transfer-accounts/restore-hosting/restore-sysuser-logins').insert_action(
			'change-sysuser-logins', RestoreSysuserLogins()
		)
		workflow.get_path('transfer-accounts/restore-hosting/restore-sysuser-logins').insert_action(
			'change-backup', ChangeSysuserLogin(SubscriptionBackup())
		)
		workflow.get_path('transfer-accounts/restore-hosting/restore-sysuser-logins').insert_action(
			'save-backup', SaveConverted(SubscriptionBackup()),
		)
		workflow.get_path('transfer-accounts/restore-hosting').insert_action(
			'windows-refresh-components', LegacyAction(
				description=messages.REFRESH_COMPONENTS_LIST_TARGET_WINDOWS_SERVERS,
				function=lambda ctx: ctx.migrator._refresh_service_node_components_for_windows(),
				logging_properties=LoggingProperties(compound=False),
				is_critical=False,
			)
		)
		workflow.get_path('transfer-accounts/restore-hosting').insert_action(
			'import-backups', ImportBackups()
		)
		workflow.get_path('transfer-accounts/restore-hosting').insert_action(
			'restore-hosting-settings', RestoreSubscriptionHostingSettings()
		)
		workflow.get_path('transfer-accounts').insert_action(
			'verify-hosting', workflow.get_shared_action_pointer('verify-hosting')
		)
		workflow.get_path('transfer-accounts').insert_action(
			'copy-content', workflow.get_shared_action_pointer('copy-content')
		)
		workflow.get_shared_action('sync-web-content-assets').insert_action(
			'check-target-web-hosting', CheckTargetWebHosting()
		)
		workflow.get_path('transfer-accounts').insert_action(
			'print-subscription-report', PrintSubscriptionStatus()
		)
		workflow.get_path('transfer-accounts').insert_action(
			'restore-status', LegacyAction(
				description=messages.RESTORE_STATUS_SUSPENDED_CLIENTS_AND_SUBSCRIPTIONS,
				function=lambda ctx: ctx.migrator.restore_status(
					ctx.options, finalize=False
				),
				logging_properties=LoggingProperties(compound=False),
				is_critical=False
			)
		)
		workflow.get_path('transfer-accounts').insert_action(
			'remove-imported-backups', RemoveImportedBackups()
		)
		workflow.get_path('transfer-accounts').insert_action(
			'restore-windows-security-policy', LegacyAction(
				description=messages.RESTORE_SECURITY_POLICY_WINDOWS_NODES,
				function=lambda ctx: ctx.migrator.restore_security_policy(),
				logging_properties=LoggingProperties(compound=False),
				is_critical=False,
		))
		workflow.get_path('transfer-accounts').insert_action(
			'restart-iis-for-idn-domains', LegacyAction(
				description=messages.ACTION_RESTART_IIS_FOR_IDN_DOMAINS,
				function=lambda ctx: ctx.migrator._fix_iis_idn_401_error(),
				logging_properties=LoggingProperties(compound=False),
				is_critical=False
			)
		)
		workflow.get_path('transfer-accounts').insert_action(
			'test-all', TestAllAfterTransfer()
		)
		workflow.get_path('transfer-accounts').insert_action(
			'test-all', PrintPostMigrationReportAfterTransfer()
		)
		workflow.get_path('transfer-accounts').insert_action(
			'cleanup', workflow.get_shared_action('cleanup')
		)
		workflow.get_path('transfer-accounts').insert_action(
			'finalize',
			workflow.get_shared_action('finalize')
		)

		workflow.get_path('transfer-accounts').register_shutdown(
			'set-windows-security-policy',
			'restore-windows-security-policy'
		)
		workflow.get_path('transfer-accounts').register_overall_shutdown('cleanup')

	@staticmethod
	def _configure_entry_point_copy_content(workflow):
		workflow.add_entry_point('copy-content', EntryPointAction())
		workflow.get_path('copy-content').insert_actions(
			workflow.get_shared_action('post-migration-prepare').get_all_actions()
		)
		workflow.get_path('copy-content').insert_action(
			'copy-content',
			workflow.get_shared_action_pointer('copy-content')
		)
		workflow.get_path('copy-content').insert_actions(
			workflow.get_shared_action('post-migration-finalize').get_all_actions()
		)
		workflow.get_path('copy-content').register_overall_shutdown('cleanup')

	@staticmethod
	def _configure_entry_point_copy_mail_content(workflow):
		workflow.add_entry_point('copy-mail-content', EntryPointAction())
		workflow.get_path('copy-mail-content').insert_actions(
			workflow.get_shared_action('post-migration-prepare').get_all_actions()
		)
		workflow.get_path('copy-mail-content').insert_action(
			'copy-mail-content',
			workflow.get_shared_action_pointer('copy-mail-content')
		)
		workflow.get_path('copy-mail-content').insert_actions(
			workflow.get_shared_action('post-migration-finalize').get_all_actions()
		)
		workflow.get_path('copy-mail-content').register_overall_shutdown('cleanup')

	@staticmethod
	def _configure_entry_point_copy_web_content(workflow):
		workflow.add_entry_point('copy-web-content', EntryPointAction())
		workflow.get_path('copy-web-content').insert_actions(
			workflow.get_shared_action('post-migration-prepare').get_all_actions()
		)
		workflow.get_path('copy-web-content').insert_action(
			'copy-web-content',
			workflow.get_shared_action_pointer('copy-web-content')
		)
		workflow.get_path('copy-web-content').insert_actions(
			workflow.get_shared_action('post-migration-finalize').get_all_actions()
		)
		workflow.get_path('copy-web-content').register_overall_shutdown('cleanup')

	@staticmethod
	def _configure_entry_point_copy_db_content(workflow):
		workflow.add_entry_point('copy-db-content', EntryPointAction())
		workflow.get_path('copy-db-content').insert_actions(
			workflow.get_shared_action('post-migration-prepare').get_all_actions()
		)
		workflow.get_path('copy-db-content').insert_action(
			'copy-db-content',
			workflow.get_shared_action_pointer('copy-db-content')
		)
		workflow.get_path('copy-db-content').insert_actions(
			workflow.get_shared_action('post-migration-finalize').get_all_actions()
		)
		workflow.get_path('copy-db-content').register_overall_shutdown('cleanup')

	@staticmethod
	def _configure_entry_point_verify_hosting(workflow):
		workflow.add_entry_point('verify-hosting', EntryPointAction())
		workflow.get_path('verify-hosting').insert_actions(
			workflow.get_shared_action('post-migration-prepare').get_all_actions()
		)
		workflow.get_path('verify-hosting').insert_action(
			'verify-hosting',
			workflow.get_shared_action_pointer('verify-hosting')
		)
		workflow.get_path('verify-hosting').insert_actions(
			workflow.get_shared_action('post-migration-finalize').get_all_actions()
		)
		workflow.get_path('verify-hosting').register_overall_shutdown('cleanup')

	@staticmethod
	def _configure_entry_point_get_progress(workflow):
		workflow.add_entry_point('get-progress', EntryPointAction())
		workflow.get_path('get-progress').insert_action('get-progress', GetProgressAction())

	@staticmethod
	def _configure_entry_point_callback(workflow):
		workflow.add_entry_point('callback', EntryPointAction())
		workflow.get_path('callback').insert_action('callback', CallbackAction())

	@staticmethod
	def _configure_entry_point_start_transfer_agent(workflow):
		workflow.add_entry_point('start-transfer-agent', EntryPointAction())
		workflow.get_path('start-transfer-agent').insert_action('start-transfer-agent', StartTransferAgent())

	@staticmethod
	def _configure_entry_point_analyse_hosting(workflow):
		workflow.add_entry_point('analyse-hosting', EntryPointAction())
		workflow.get_path('analyse-hosting').insert_action(
			'analyse-hosting',
			workflow.get_shared_action_pointer('analyse-hosting')
		)

	@staticmethod
	def _configure_entry_point_set_dns_forwarding(workflow):
		# Set up the DNS forwarding.
		#
		# Classic DNS forwarding just does not work by its design: source Plesk
		# server is authoritative for its zones - according to registrar - and
		# will not forward queries about these zones anywhere.  So the DNS
		# forwarding we do by turning source Plesk into slave mode for the
		# migrated zones.
		#
		# This step is separate from transfer-accounts because the
		# steps are following:
		# - transfer-accounts
		# - disable access to both source and target servers for the migrated
		# subscriptions MANUALLY
		# - set up DNS forwarding
		workflow.add_entry_point('set-dns-forwarding', EntryPointAction())
		workflow.get_path('set-dns-forwarding').insert_action(
			'check-source-not-supported', SetDNSForwardingNotSupported()
		)

	@staticmethod
	def _configure_entry_point_undo_dns_forwarding(workflow):
		workflow.add_entry_point('undo-dns-forwarding', EntryPointAction())
		# By default we don't have DNS forwarding support.
		# Should be overridden in child workflow for panels which support DNS forwarding.
		workflow.get_path('undo-dns-forwarding').insert_action(
			'check-source-not-supported', UndoDNSForwardingNotSupported()
		)

	@staticmethod
	def _configure_entry_point_set_low_dns_timings(workflow):
		# Set up low DNS timings
		workflow.add_entry_point('set-low-dns-timings', EntryPointAction())
		workflow.get_path('set-low-dns-timings').insert_action(
			'check-source-not-supported', SetDNSTimingsNotSupported()
		)

	@staticmethod
	def _configure_entry_point_test_all(workflow):
		workflow.add_entry_point('test-all', EntryPointAction())
		workflow.get_path('test-all').insert_actions(
			workflow.get_shared_action('post-migration-prepare').get_all_actions()
		)
		workflow.get_path('test-all').insert_action(
			'test-all',
			LegacyAction(
				description=messages.CHECK_THAT_SERVICES_AND_TRANSFERRED_DOMAINS,
				function=lambda ctx: ctx.migrator._test_all(ctx.options)
			)
		)
		workflow.get_path('test-all').insert_action(
			'cleanup', workflow.get_shared_action('cleanup')
		)
		workflow.get_path('test-all').insert_action(
			'print_report', LegacyAction(
				description=messages.ACTION_PRINT_REPORT,
				function=lambda ctx: ctx.migrator._print_post_migration_check_report('test_all_report'),
				logging_properties=LoggingProperties(info_log=False),
				is_critical=False
			)
		)
		workflow.get_path('test-all').register_overall_shutdown('cleanup')

	@staticmethod
	def _configure_entry_point_test_sites(workflow):
		workflow.add_entry_point('test-sites', EntryPointAction())
		workflow.get_path('test-sites').insert_actions(
			workflow.get_shared_action('post-migration-prepare').get_all_actions()
		)
		workflow.get_path('test-sites').insert_action(
			'test-sites',
			LegacyAction(
				description=messages.CHECKING_WHETHER_TRANSFERRED_WEBSITES_OPERATE_PROPERLY,
				function=lambda ctx: ctx.migrator._test_sites(ctx.options)
			)
		)
		workflow.get_path('test-sites').insert_action(
			'cleanup', workflow.get_shared_action('cleanup')
		)
		workflow.get_path('test-sites').insert_action(
			'print_report', LegacyAction(
				description=messages.ACTION_PRINT_REPORT,
				function=lambda ctx: ctx.migrator._print_post_migration_check_report('test_sites_report'),
				logging_properties=LoggingProperties(info_log=False),
				is_critical=False
			)
		)
		workflow.get_path('test-sites').register_overall_shutdown('cleanup')

	@staticmethod
	def _configure_entry_point_test_dns(workflow):
		workflow.add_entry_point('test-dns', EntryPointAction())
		workflow.get_path('test-dns').insert_actions(
			workflow.get_shared_action('post-migration-prepare').get_all_actions()
		)
		workflow.get_path('test-dns').insert_action(
			'test-dns',
			LegacyAction(
				description=messages.CHECK_THAT_DNS_QUERIES_FOR_TRANSFERRED,
				function=lambda ctx: ctx.migrator._test_dns(ctx.options)
			)
		)
		workflow.get_path('test-dns').insert_action(
			'cleanup', workflow.get_shared_action('cleanup')
		)
		workflow.get_path('test-dns').insert_action(
			'print_report', LegacyAction(
				description=messages.ACTION_PRINT_REPORT,
				function=lambda ctx: ctx.migrator._print_post_migration_check_report('test_dns_report'),
				logging_properties=LoggingProperties(info_log=False),
				is_critical=False
			)
		)
		workflow.get_path('test-dns').register_overall_shutdown('cleanup')

	@staticmethod
	def _configure_entry_point_test_mail(workflow):
		workflow.add_entry_point('test-mail', EntryPointAction())
		workflow.get_path('test-mail').insert_actions(
			workflow.get_shared_action('post-migration-prepare').get_all_actions()
		)
		workflow.get_path('test-mail').insert_action(
			'test-mail',
			LegacyAction(
				description=messages.CHECK_WHETHER_IMAP_SMTP_AND_POP,
				function=lambda ctx: ctx.migrator._test_mail(ctx.options)
			)
		)
		workflow.get_path('test-mail').insert_action(
			'cleanup', workflow.get_shared_action('cleanup')
		)
		workflow.get_path('test-mail').insert_action(
			'print_report', LegacyAction(
				description=messages.ACTION_PRINT_REPORT,
				function=lambda ctx: ctx.migrator._print_post_migration_check_report('test_mail_report'),
				logging_properties=LoggingProperties(info_log=False),
				is_critical=False
			)
		)
		workflow.get_path('test-mail').register_overall_shutdown('cleanup')

	@staticmethod
	def _configure_entry_point_test_users(workflow):
		workflow.add_entry_point('test-users', EntryPointAction())
		workflow.get_path('test-users').insert_actions(
			workflow.get_shared_action('post-migration-prepare').get_all_actions()
		)
		workflow.get_path('test-users').insert_action(
			'test-users',
			LegacyAction(
				description=messages.ACTIONS_TEST_USERS,
				function=lambda ctx: ctx.migrator._test_users(ctx.options)
			)
		)
		workflow.get_path('test-users').insert_action(
			'cleanup', workflow.get_shared_action('cleanup')
		)
		workflow.get_path('test-users').insert_action(
			'print_report', LegacyAction(
				description=messages.ACTION_PRINT_REPORT,
				function=lambda ctx: ctx.migrator._print_post_migration_check_report('test_users_report'),
				logging_properties=LoggingProperties(info_log=False),
				is_critical=False
			)
		)
		workflow.get_path('test-users').register_overall_shutdown('cleanup')

	@staticmethod
	def _configure_entry_point_test_databases(workflow):
		workflow.add_entry_point('test-databases', EntryPointAction())
		workflow.get_path('test-databases').insert_actions(
			workflow.get_shared_action('post-migration-prepare').get_all_actions()
		)
		workflow.get_path('test-databases').insert_action(
			'test-databases',
			LegacyAction(
				description=messages.CHECK_WHETHER_DATABASES_WERE_COPIED_CORRECTLY,
				function=lambda ctx: ctx.migrator._test_databases(ctx.options)
			)
		)
		workflow.get_path('test-databases').insert_action(
			'cleanup', workflow.get_shared_action('cleanup')
		)
		workflow.get_path('test-databases').insert_action(
			'print_report', LegacyAction(
				description=messages.ACTION_PRINT_REPORT,
				function=lambda ctx: ctx.migrator._print_post_migration_check_report('test_databases_report'),
				logging_properties=LoggingProperties(info_log=False),
				is_critical=False
			)
		)
		workflow.get_path('test-databases').register_overall_shutdown('cleanup')

	@staticmethod
	def _configure_entry_point_test_services(workflow):
		workflow.add_entry_point('test-services', EntryPointAction())

		workflow.get_path('test-services').insert_action(
			'check-updates',
			workflow.get_shared_action('check-updates')
		)
		workflow.get_path('test-services').insert_action(
			'check-sources',
			workflow.get_shared_action('check-sources')
		)
		workflow.get_path('test-services').insert_action(
			'check-target',
			workflow.get_shared_action('check-target')
		)
		workflow.get_path('test-services').insert_action(
			'check-target-licenses',
			workflow.get_shared_action('check-target-licenses')
		)
		workflow.get_path('test-services').insert_action(
			'test-services',
			LegacyAction(
				description=messages.CHECKING_WHETHER_SERVICE_OPERATE_PROPERLY,
				function=lambda ctx: ctx.migrator._test_services(ctx.options)
			)
		)
		workflow.get_path('test-services').insert_action(
			'cleanup', workflow.get_shared_action('cleanup')
		)
		workflow.get_path('test-services').insert_action(
			'print_report', LegacyAction(
				description=messages.ACTION_PRINT_REPORT,
				function=lambda ctx: ctx.migrator._print_test_services_report(),
				logging_properties=LoggingProperties(info_log=False),
				is_critical=False
			)
		)
		workflow.get_path('test-services').register_overall_shutdown('cleanup')

	@staticmethod
	def _configure_entry_point_list_ip_addresses(workflow):
		workflow.add_entry_point('list-ip-addresses', EntryPointAction())
		workflow.get_path('list-ip-addresses').insert_action(
			'list-ip-addresses', ListIPAddresses()
		)