Submit
Path:
~
/
/
opt
/
psa
/
admin
/
plib
/
modules
/
site-import
/
backend
/
lib
/
python
/
parallels
/
plesk
/
converter
/
File Content:
ip_mapping.py
from parallels.core.logging import get_logger from parallels.core.migration_list.entities.ip_mapping import SubscriptionIPMapping from parallels.core.reports.model.issue import Issue from parallels.core.utils.common import find_first from parallels.core.utils.common_constants import IP_EXCLUSIVE, IP_SHARED from parallels.plesk.utils.ip_utils import get_ip_address_types, PleskIPv4AddressType from parallels.plesk import messages from parallels.plesk.target_data_model import PleskTargetSubscriptionData logger = get_logger(__name__) class IPMapper(object): @staticmethod def map_ip_addresses( subscriptions, existing_objects, ip_mapping, subscriptions_mapping, report ): """Set IP addresses for subscriptions according to migration list, IP mapping file and target IP set Current implementation features and limitations: 1) If you assigned IP address manually, either with migration list or with IP mapping file, no additional checks are performed. For example, if this IP is already used by another reseller/client, migration will fail when creating subscription. No pre-migration warning will be displayed. 2) For all automatically allocated IP addresses, except for default shared IP address, we always use completely unused IP addresses - addresses which are not assigned to any client/reseller and not used by any hosting subscriptions. So, in automatic mode migrator could skip addresses which could actually be used. For example, exclusive IP addresses owned by reseller which have no hosting subscriptions will be skipped in case if we migrate subscription with exclusive IP address under that reseller. 3) In automatic mode, it is considered that all subscriptions that have the same non-default IP address are migrated at once. Otherwise, if you migrated them in several stages, they will get different IP addresses, one per each stage. 4) By default shared IP address on target we take the first shared IP address reported by ipmanage utility. Theoretically, it could be possible when default shared IP address is another one, not the first one. 5) In case of any issue, except for the lack of default shared IP address, we migrate subscription to default shared IP address. Migration won't stop, and you can reassign the IP later after migration. :type subscriptions: list[parallels.core.migrated_subscription.MigratedSubscription] :type ip_mapping: parallels.core.ip_mapping.IPMapping | None :type subscriptions_mapping: dict[str | unicode, parallels.core.migration_list.entities.subscription_info.SubscriptionMappingInfo] :type report: parallels.core.reports.model.report.Report :rtype: None """ ip_addresses_selector = IPAddressesSelector(existing_objects.ip_addresses, ip_mapping) # first, map subscriptions that have exactly specified IP address in migration list for subscription in subscriptions: subscription_mapping = subscriptions_mapping[subscription.name] subscription_report = subscription.get_report(report) for ip_type in get_ip_address_types(): ip = ip_type.get_for_ip_mapping(subscription_mapping.ips) if ip_type.is_valid_ip(ip): ip_addresses_selector.select_exact_ip( subscription, ip_type, ip, subscription_report ) # then, map subscriptions that use IP mapping (AUTO in migration list) - either with mapping file, or automatic for subscription in subscriptions: subscription_mapping = subscriptions_mapping[subscription.name] subscription_report = subscription.get_report(report) for ip_type in get_ip_address_types(): if ip_type.get_for_ip_mapping(subscription_mapping.ips) == SubscriptionIPMapping.AUTO: ip_addresses_selector.select_mapping_ip( subscription, subscription.raw_dump, ip_type, ip_type.get_default_ip(subscription.server_raw_dump), subscription_report ) # then, map subscriptions that have SHARED or DEDICATED in migration list for subscription in subscriptions: subscription_mapping = subscriptions_mapping[subscription.name] subscription_report = subscription.get_report(report) for ip_type in get_ip_address_types(): ip = ip_type.get_for_ip_mapping(subscription_mapping.ips) if ip == SubscriptionIPMapping.SHARED: ip_addresses_selector.select_default_shared_ip(subscription, ip_type, subscription_report) elif ip == SubscriptionIPMapping.DEDICATED: ip_addresses_selector.select_free_exclusive_ip( subscription, ip_type, subscription_report ) # if there are still no IP addresses assigned, use the default shared IPv4 address for subscription in subscriptions: target_data = subscription.model.target_data assert isinstance(target_data, PleskTargetSubscriptionData) subscription_report = subscription.get_report(report) if target_data.web_ipv6 is None and target_data.web_ip is None: ip_addresses_selector.select_default_shared_ip( subscription, PleskIPv4AddressType(), subscription_report, report_error=True ) class IPAddressesSelector(object): """Get IP addresses for new subscriptions :type _target_ip_addresses: list[parallels.core.utils.plesk_utils.IPAddressInfo] """ def __init__(self, ip_addresses, ip_mapping): """ :type ip_addresses: list[parallels.core.utils.plesk_utils.IPAddressInfo] :type ip_mapping: parallels.core.ip_mapping.IPMapping | None """ self._target_ip_addresses = ip_addresses # dictionary of IP owners, {ip address: (reseller login, customer login)} self._ip_owner = dict() # dictionary of automatic IP mapping, {source ip address: target ip address} self._automatic_ip_mapping = dict() # IP mapping specified by IP mapping file by customer, # parallels.core.ip_mapping.IPMapping object or None if mapping was not specified self._customer_ip_mapping = ip_mapping def select_mapping_ip( self, subscription, backup_subscription, ip_type, source_default_ip, subscription_report ): """Select IP according to IP mapping - either manual (with IP mapping file) or automatic :type subscription: parallels.core.migrated_subscription.MigratedSubscription :type backup_subscription: parallels.core.dump.data_model.Subscription :type ip_type: parallels.plesk.utils.ip_utils.PleskIPAddressType :type source_default_ip: str | unicode | None :type subscription_report: parallels.core.reports.model.report.Report :rtype: None """ source_ip = ip_type.get_for_backup_subscription(backup_subscription) source_ip_type = ip_type.get_type_for_backup_subscription(backup_subscription) if source_ip is None: # There were no IP of such type on source, then there should be no # IP of such type on target in AUTO mode return if self._customer_ip_mapping is not None and self._customer_ip_mapping.get(source_ip) is not None: target_ip = self._customer_ip_mapping.get(source_ip) ip_type.set_for_target_model_subscription(subscription.model, target_ip) self._ip_owner[target_ip] = (subscription.reseller_username, subscription.customer_username) elif source_ip not in self._automatic_ip_mapping: if source_ip_type == IP_SHARED: if source_default_ip is not None and source_ip == source_default_ip: self.select_default_shared_ip(subscription, ip_type, subscription_report) else: # find mapping for source non-default IP address next_shared_ip = find_first( self._target_ip_addresses, lambda ip: ( ip.ip_type == IP_SHARED and ip_type.is_valid_ip(ip.ip_address) and (source_default_ip is None or ip != self._get_default_shared_ip(ip_type)) and ip.ip_address not in self._automatic_ip_mapping.values() and (source_default_ip is None or ip.is_completely_free) ) ) if next_shared_ip is None: # If no IP was found - map to default shared IP, but do not report anything to customer: # we consider this situation is ok, nothing bad will happen if some shared IP address # is mapped to default shared IP address. self.select_default_shared_ip(subscription, ip_type, subscription_report) else: ip_type.set_for_target_model_subscription(subscription.model, next_shared_ip.ip_address) self._automatic_ip_mapping[source_ip] = next_shared_ip.ip_address elif source_ip_type == IP_EXCLUSIVE: next_exclusive_ip = find_first( self._target_ip_addresses, lambda ip: ( ip.ip_type == IP_EXCLUSIVE and ip_type.is_valid_ip(ip.ip_address) and ip.ip_address not in self._automatic_ip_mapping.values() and ( # not owned by anybody self._ip_owner.get(ip.ip_address) is None or # owned by this current reseller and client self._ip_owner.get(ip.ip_address) == ( subscription.reseller_username, subscription.customer_username ) ) and ip.is_completely_free ) ) if next_exclusive_ip is None: # If no IP was found - map to default shared IP self._report_no_more_free_exclusive_ips(ip_type, subscription_report) self.select_default_shared_ip(subscription, ip_type, subscription_report) else: ip_type.set_for_target_model_subscription(subscription.model, next_exclusive_ip.ip_address) self._automatic_ip_mapping[source_ip] = next_exclusive_ip.ip_address self._ip_owner[next_exclusive_ip.ip_address] = ( subscription.reseller_username, subscription.customer_username ) else: ip_type.set_for_target_model_subscription(subscription.model, self._automatic_ip_mapping[source_ip]) def select_default_shared_ip(self, subscription, ip_type, subscription_report, report_error=False): """Select default shared IP address for subscription :type subscription: parallels.core.migrated_subscription.MigratedSubscription :type ip_type: parallels.plesk.utils.ip_utils.PleskIPAddressType :type subscription_report: parallels.core.reports.model.report.Report :type report_error: bool :rtype: None """ shared_ip = self._get_default_shared_ip(ip_type) if shared_ip is None: if report_error: self._report_no_shared_ip_error(ip_type, subscription_report) else: self._report_no_shared_ip_warning(ip_type, subscription_report) else: ip_type.set_for_target_model_subscription(subscription.model, shared_ip.ip_address) logger.debug(messages.IP_MAPPING_ASSIGNED_DEFAULT_IP, shared_ip.ip_address, subscription.name) def select_free_exclusive_ip(self, subscription, ip_type, subscription_report): """Select new free exclusive IP address for subscription :type subscription: parallels.core.migrated_subscription.MigratedSubscription :type ip_type: parallels.plesk.utils.ip_utils.PleskIPAddressType :type subscription_report parallels.core.reports.model.report.Report :rtype: None """ ip_address = find_first( self._target_ip_addresses, lambda ip: ( ip.ip_type == IP_EXCLUSIVE and ip.ip_address not in self._ip_owner and ip_type.is_valid_ip(ip.ip_address) and ip.is_completely_free ) ) if ip_address is None: self._report_no_free_new_exclusive_ip(ip_type, subscription_report) self.select_default_shared_ip(subscription, ip_type, subscription_report) else: ip_type.set_for_target_model_subscription(subscription.model, ip_address.ip_address) self._ip_owner[ip_address.ip_address] = (subscription.reseller_username, subscription.customer_username) def select_exact_ip( self, subscription, ip_type, ip_address, subscription_report ): """Select exactly specified IP address for subscription :type subscription: parallels.core.migrated_subscription.MigratedSubscription :type ip_type: parallels.plesk.utils.ip_utils.PleskIPAddressType :type ip_address: str | unicode :type subscription_report parallels.core.reports.model.report.Report :rtype: None """ target_ip = find_first( self._target_ip_addresses, lambda ip: ip.ip_address == ip_address ) if target_ip is None: self._report_no_such_ip_address(ip_address, ip_type, subscription_report) self.select_default_shared_ip(subscription, ip_type, subscription_report) else: ip_type.set_type_for_target_model_subscription(subscription.model, target_ip.ip_type) logger.debug(messages.IP_MAPPING_SUBSCRIPTION_ASSIGNED_IPS, target_ip.ip_address, target_ip.ip_type) if target_ip.ip_type == IP_SHARED: ip_type.set_for_target_model_subscription(subscription.model, target_ip.ip_address) elif target_ip.ip_type == IP_EXCLUSIVE: owner = self._ip_owner.get(ip_address) if owner is not None: existing_owner_reseller, existing_owner_client = owner if ( existing_owner_client != subscription.customer_username or existing_owner_reseller != subscription.reseller_username ): self._report_ip_assigned_to_another_owner(ip_address, ip_type, subscription_report) self.select_default_shared_ip(subscription, ip_type, subscription_report) else: ip_type.set_for_target_model_subscription(subscription.model, target_ip.ip_address) else: self._ip_owner[ip_address] = (subscription.reseller_username, subscription.customer_username) ip_type.set_for_target_model_subscription(subscription.model, target_ip.ip_address) def _get_default_shared_ip(self, ip_type): """Get default shared IP address of specified type :type ip_type: parallels.core.utils.ip_utils.IPAddressType :rtype: parallels.core.utils.plesk_utils.IPAddressInfo """ shared_ip = find_first( self._target_ip_addresses, lambda ip: ip.ip_type == IP_SHARED and ip_type.is_valid_ip(ip.ip_address) ) return shared_ip @staticmethod def _report_ip_assigned_to_another_owner(ip_address, ip_type, subscription_report): """ :type ip_type: parallels.core.utils.ip_utils.IPAddressType :type subscription_report parallels.core.reports.model.report.Report :rtype: None """ subscription_report.add_issue( 'ipv4_address_already_assigned_to_another_owner', Issue.SEVERITY_WARNING, messages.IP_MAPPING_IP_ASSIGNED_TO_ANOTHER_OWNER_ISSUE % ( ip_type.title, ip_address ), messages.IP_MAPPING_IP_ASSIGNED_TO_ANOTHER_OWNER_SOLUTION % ip_type.title ) @staticmethod def _report_no_such_ip_address(ip_address, ip_type, subscription_report): """ :type ip_type: parallels.core.utils.ip_utils.IPAddressType :type subscription_report parallels.core.reports.model.report.Report :rtype: None """ subscription_report.add_issue( 'no_such_ip_address', Issue.SEVERITY_WARNING, messages.IP_MAPPING_NO_SUCH_IP_ISSUE % ( ip_type.title, ip_address ), messages.IP_MAPPING_NO_SUCH_IP_SOLUTION % ip_type.title ) @staticmethod def _report_no_free_new_exclusive_ip(ip_type, subscription_report): """ :type ip_type: parallels.core.utils.ip_utils.IPAddressType :type subscription_report parallels.core.reports.model.report.Report :rtype: None """ subscription_report.add_issue( 'no_free_exclusive_ip', Issue.SEVERITY_WARNING, messages.IP_MAPPING_NO_FREE_EXCLUSIVE_IP_ISSUE, messages.IP_MAPPING_NO_FREE_EXCLUSIVE_IP_SOLUTION % ip_type.title ) @staticmethod def _report_no_shared_ip_error(ip_type, subscription_report): """ :type ip_type: parallels.core.utils.ip_utils.IPAddressType :type subscription_report parallels.core.reports.model.report.Report :rtype: None """ subscription_report.add_issue( 'no_shared_ip_error', Issue.SEVERITY_ERROR, messages.IP_MAPPING_NO_SHARED_IP_ISSUE_ERROR % ip_type.title, messages.IP_MAPPING_NO_SHARED_IP_SOLUTION % ip_type.title ) @staticmethod def _report_no_shared_ip_warning(ip_type, subscription_report): """ :type ip_type: parallels.core.utils.ip_utils.IPAddressType :type subscription_report parallels.core.reports.model.report.Report :rtype: None """ subscription_report.add_issue( 'no_shared_ip_warning', Issue.SEVERITY_WARNING, messages.IP_MAPPING_NO_SHARED_IP_ISSUE_WARNING % ip_type.title, messages.IP_MAPPING_NO_SHARED_IP_SOLUTION % ip_type.title ) @staticmethod def _report_no_more_free_exclusive_ips(ip_type, subscription_report): """ :type ip_type: parallels.core.utils.ip_utils.IPAddressType :type subscription_report parallels.core.reports.model.report.Report :rtype: None """ subscription_report.add_issue( 'no_more_exclusive_ip_address', Issue.SEVERITY_WARNING, messages.IP_MAPPING_NO_MORE_EXCLUSIVE_IP_ISSUE % ip_type.title, messages.IP_MAPPING_NO_MORE_EXCLUSIVE_IP_SOLUTION )
Submit
FILE
FOLDER
INFO
Name
Size
Permission
Action
adapter
---
0755
__init__.py
0 bytes
0644
converter.py
23447 bytes
0644
hosting_plan.py
14814 bytes
0644
ip_mapping.py
19384 bytes
0644
reseller_plan.py
6880 bytes
0644
N4ST4R_ID | Naxtarrr