D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
opt
/
psa
/
admin
/
plib
/
modules
/
site-import
/
backend
/
lib
/
python
/
parallels
/
plesk
/
Filename :
panel.py
back
Copy
from parallels.core.logging import get_logger from parallels.core.subscription_target_info import TargetServices, SubscriptionServiceIPs, TargetServers from parallels.core.utils import plesk_api_utils from parallels.core.utils.plesk_api_utils import request_single_optional_item from parallels.core.utils.plesk_utils import get_php_handlers from parallels.plesk import messages from parallels.core import MigrationNoContextError from parallels.core.utils.common import cached, format_list from parallels.core.target_panel_base import TargetPanelBase, TargetServiceInfo from parallels.core.utils.plesk_db_credentials_fetcher import PleskDbCredentialsFetcher from parallels.plesk.connections.database_target_server import PleskDatabaseTargetServer from parallels.plesk.converter.adapter.client_subscription_converter import \ TargetPleskClientSubscriptionConverterAdapter from parallels.plesk.converter.adapter.reseller_plan_converter import PleskResellerPlanConverterAdapter from parallels.plesk.converter.hosting_plan import PleskHostingPlanAdapter from parallels.plesk.hosting_repository.model import PleskHostingRepositoryModel from parallels.plesk.target_data_model import PleskTargetSubscriptionData from parallels.plesk.utils.xml_rpc.plesk import operator as plesk_ops from parallels.plesk.utils.xml_rpc.plesk.operator.subscription import SubscriptionHostingNone from parallels.plesk.connections.target_connections import PleskTargetConnections logger = get_logger(__name__) class Panel(TargetPanelBase): @property def name(self): return messages.TARGET_PANEL_PLESK_TITLE def has_custom_subscriptions_feature(self): """Whether subscriptions not assigned to plan are allowed :rtype: bool """ return True def has_admin_reseller_plan_feature(self): """Whether admin reseller plans are supported for that target panel migration :rtype: bool """ return True def has_admin_subscriptions_feature(self): """Whether subscriptions assigned directly to admin are allowed :rtype: bool """ return True def has_reseller_subscriptions_feature(self): """Whether subscriptions assigned directly to reseller are allowed :rtype: bool """ return True def has_subscriptions_only(self, global_context): """Whether panel have subscriptions only, but not clients, resellers, plans, etc :type global_context: parallels.core.global_context.GlobalMigrationContext :rtype: bool """ return global_context.conn.target.plesk_server.is_power_user_mode def has_resellers(self, global_context): """Whether panel has resellers :type global_context: parallels.core.global_context.GlobalMigrationContext :rtype: bool """ return global_context.conn.target.plesk_server.can_manage_resellers def has_dns_forwarding(self): """Whether panel should support DNS forwarding migration feature :rtype: bool """ return True def is_test_dns_forwarding(self): """Whether to test DNS forwarding feature on post-migration checks :rtype: bool """ # Do not test DNS forwarding, as it is experimental not documented feature # and should not used by customers by default, so we should not force testing it. # Better for user, but more complex solution is to store domains for which we set DNS forwarding # and check only that domains return False def is_encrypted_passwords_supported(self): """Whether encrypted passwords (hashes) are supported when creating resellers and clients :rtype: bool """ return True @cached def get_subscription_nodes(self, global_context, subscription_name): """Get servers of subscription on target panel :type global_context: parallels.core.global_context.GlobalMigrationContext :type subscription_name: str | unicode :rtype: parallels.core.subscription_target_info.TargetServers """ plesk_server = self.get_subscription_plesk_node(global_context, subscription_name) subscription_target_services = self.get_subscription_target_services(global_context, subscription_name) database_servers = {} for db_type, db_params in subscription_target_services.db_servers.items(): if db_params is None: continue login, password = PleskDbCredentialsFetcher.get_instance().get( plesk_server, db_type, db_params ) database_servers[db_type] = PleskDatabaseTargetServer( db_type, db_params.host, db_params.port, login, password, plesk_server ) if global_context.conn.target.remote_smarter_mail_server is None: mail_server = plesk_server else: mail_server = global_context.conn.target.remote_smarter_mail_server return TargetServers( web=plesk_server, mail=mail_server, database=database_servers, dns=[plesk_server] ) @cached def get_subscription_target_services(self, global_context, subscription_name): """Get location of subscriptions's hosting services on target panel :type global_context: parallels.core.global_context.GlobalMigrationContext :type subscription_name: str | unicode :rtype: parallels.core.subscription_target_info.TargetServices """ plesk_server = self.get_subscription_plesk_node(global_context, subscription_name) plesk_api = global_context.conn.target.plesk_server.plesk_api() request = plesk_ops.SubscriptionOperator.Get( plesk_ops.SubscriptionOperator.FilterByName([subscription_name]), [ plesk_ops.SubscriptionOperator.Dataset.GEN_INFO, plesk_ops.SubscriptionOperator.Dataset.HOSTING, plesk_ops.SubscriptionOperator.Dataset.MAIL, ] ) subscription_info_response = request_single_optional_item(plesk_api, request) if subscription_info_response is None: # Subscription was not created on target Plesk yet. Predict services location by service template. return self.predict_subscription_target_services(global_context, subscription_name) subscription_info = subscription_info_response[1] hosting = subscription_info.hosting raw_dump = global_context.get_subscription(subscription_name).raw_dump if raw_dump is not None and isinstance(hosting, SubscriptionHostingNone) and raw_dump.hosting_type != 'none': # Subscription has no virtual hosting and has no information about services location. # Wa may enable hosting during migration, so here we predict target services location by service template. return self.predict_subscription_target_services(global_context, subscription_name) db_servers_info = plesk_api_utils.get_subscription_db_servers(plesk_api, subscription_name) db_servers = { server.server_type: global_context.conn.target.plesk_server.get_db_servers().get(server.server_id) for server in db_servers_info[1] } if isinstance(hosting, ( plesk_ops.SubscriptionHostingVirtual, plesk_ops.SubscriptionHostingStandardForwarding, plesk_ops.SubscriptionHostingFrameForwarding )): web_ips = SubscriptionServiceIPs(v4=hosting.ip_addresses.v4, v6=hosting.ip_addresses.v6) else: web_ips = SubscriptionServiceIPs() mail_info = subscription_info.mail if global_context.conn.target.remote_smarter_mail_ip is None: if mail_info is not None: mail_ips = SubscriptionServiceIPs(v4=mail_info.ip_addresses.v4, v6=mail_info.ip_addresses.v6) else: mail_ips = SubscriptionServiceIPs() else: mail_ips = SubscriptionServiceIPs(v4=global_context.conn.target.remote_smarter_mail_ip, v6=None) return TargetServices( web_ips=web_ips, mail_ips=mail_ips, db_servers=db_servers, dns_ips=[SubscriptionServiceIPs(v4=plesk_server.ip(), v6=None)] ) def predict_subscription_target_services(self, global_context, subscription_name): """ :type global_context: parallels.core.global_context.GlobalMigrationContext :type subscription_name: str | unicode :rtype: parallels.core.subscription_target_info.TargetServices """ subscription_database_nodes = {} subscription = global_context.get_subscription(subscription_name) service_plan = global_context.hosting_repository.service_plan.get_by_name( subscription.model.plan_name, None if subscription.model_reseller is None else subscription.model_reseller.login ) plesk_server = self._get_plesk_target_server(global_context.conn.target) database_server_types = {database.dbtype for database in subscription.raw_dump.iter_all_databases()} for database_server_type in database_server_types: target_database_server = None # try to detect target database server based on database server details, # specified as default for target service template if service_plan is not None: default_database_server = service_plan.get_database_server(database_server_type) if default_database_server is not None and plesk_server.has_database_server( default_database_server.host, default_database_server.type ): target_database_server = plesk_server.get_database_server( default_database_server.host, default_database_server.type ) # try to detect target database server based on target panel database servers settings if target_database_server is None: target_database_server = plesk_server.get_default_database_server(database_server_type) # raise exception, if unable to detect target database server if target_database_server is None: raise Exception(messages.UNABLE_TO_FIND_DB_SERVER_ON_TARGET_ISSUE % database_server_type) subscription_database_nodes[target_database_server.dbtype] = target_database_server target_subscription_data = subscription.model.target_data if isinstance(target_subscription_data, PleskTargetSubscriptionData): web_ipv4 = target_subscription_data.web_ip web_ipv6 = target_subscription_data.web_ipv6 else: web_ipv4 = None web_ipv6 = None web_ips = SubscriptionServiceIPs(v4=web_ipv4, v6=web_ipv6) return TargetServices( web_ips=web_ips, mail_ips=web_ips, db_servers=subscription_database_nodes, dns_ips=plesk_server.ip(), ) def get_subscription_plesk_node(self, global_context, subscription_name): return self._get_plesk_target_server(global_context.conn.target) def get_service_nodes(self, conn): service_nodes = [ TargetServiceInfo( service_type='web', node=self._get_plesk_target_server(conn) ), TargetServiceInfo( service_type='mail', node=self._get_plesk_target_server(conn) ), TargetServiceInfo( service_type='dns', node=self._get_plesk_target_server(conn) ) ] for result in conn.plesk_api().send( plesk_ops.DbServerOperator.Get( filter=plesk_ops.DbServerOperator.FilterAll() ) ): # We can not use the database server until credentials is not # set. Example: for postgresql credentials don't set after # install. if result.data.status == 'CREDENTIALS_NOT_SET': continue # Check only local database server. if result.data.local: service_nodes.append( TargetServiceInfo( service_type=result.data.dbtype, node=self._get_plesk_target_server(conn) ) ) return service_nodes def get_connections(self, global_context): """Get target panel connections :type global_context: parallels.core.global_context.GlobalMigrationContext """ return PleskTargetConnections(global_context.config) def get_hosting_repository(self, global_context): """Retrive hosting repository of target Plesk :type global_context: parallels.core.global_context.GlobalMigrationContext :rtype: parallels.plesk.hosting_repository.model.PleskHostingRepositoryModel """ return PleskHostingRepositoryModel(self.get_connections(global_context).plesk_server) def get_converter_adapter(self): """ :rtype: parallels.plesk.converter.adapter.client_subscription_converter.TargetPleskClientSubscriptionConverterAdapter """ return TargetPleskClientSubscriptionConverterAdapter() def get_reseller_plan_converter_adapter(self): """ :rtype: parallels.plesk.converter.adapter.reseller_plan_converter.PleskResellerPlanConverterAdapter """ return PleskResellerPlanConverterAdapter() def get_hosting_plan_adapter(self, global_context): """Retrieve hosting plan adapter :type global_context: parallels.core.global_context.GlobalMigrationContext :rtype: parallels.plesk.converter.hosting_plan.PleskHostingPlanAdapter """ plesk_server = global_context.conn.target.plesk_server plesk_api = plesk_server.plesk_api() allowed_limits = plesk_api_utils.get_service_template_allowed_limits(plesk_api) logger.debug(messages.CONVERTER_PLAN_ALLOWED_HOSTING_PLAN_LIMITS.format( hosting_plan_limits=format_list(allowed_limits) )) allowed_permissions = plesk_api_utils.get_service_template_allowed_permissions(plesk_api) logger.debug(messages.CONVERTER_PLAN_ALLOWED_HOSTING_PLAN_PERMISSIONS.format( hosting_plan_permissions=format_list(allowed_permissions) )) allowed_settings = plesk_api_utils.get_service_template_allowed_hosting_settings(plesk_api) logger.debug(messages.CONVERTER_PLAN_ALLOWED_HOSTING_PLAN_SETTINGS.format( hosting_plan_settings=format_list(allowed_settings) )) plesk_version = plesk_server.get_plesk_version() if plesk_version < (12, 5): allowed_php_handlers = None else: allowed_php_handlers = get_php_handlers(plesk_server) remote_smarter_mail = global_context.conn.target.remote_smarter_mail_server is not None allowed_webmails = global_context.hosting_repository.panel.get_available_webmails() return PleskHostingPlanAdapter( allowed_limits, allowed_permissions, allowed_settings, allowed_php_handlers, is_windows=plesk_server.is_windows(), remote_smarter_mail=remote_smarter_mail, allowed_webmails=allowed_webmails ) def get_hosting_check_messages_panel_id(self): return 'plesk' @staticmethod def _get_plesk_target_server(conn): return conn.plesk_server def check_version(self, global_context): """Check that target panel version is ok for migration purposes. Raise MigrationError otherwise. Raised exception should contain information about supported versions for migration. :type global_context: parallels.core.global_context.GlobalMigrationContext :rtype: None """ plesk_version = global_context.conn.target.plesk_server.get_plesk_version() plesk_version_str = '.'.join([str(i) for i in plesk_version]) if plesk_version < (12, 0): raise MigrationNoContextError( messages.TARGET_PLESK_VERSION_NOT_SUPPORTED % ( plesk_version_str ) ) def get_import_dump_additional_env_vars(self, global_context): """Get additional target panel-specific environment variables to pass to pmmcli when importing dump :type global_context: parallels.core.global_context.GlobalMigrationContext :rtype: dict[str, str] """ # Tell pmmcli to convert imported dump into latest format with hierarchical directory structure return {'PPA_IGNORE_FILE_MATCHING': 'true'}