diff --git a/poppy/provider/akamai/background_jobs/check_cert_status_and_update/check_cert_status_and_update_flow.py b/poppy/provider/akamai/background_jobs/check_cert_status_and_update/check_cert_status_and_update_flow.py index 414c8395..422dd584 100644 --- a/poppy/provider/akamai/background_jobs/check_cert_status_and_update/check_cert_status_and_update_flow.py +++ b/poppy/provider/akamai/background_jobs/check_cert_status_and_update/check_cert_status_and_update_flow.py @@ -13,6 +13,14 @@ # See the License for the specific language governing permissions and # limitations under the License. +"""Taskflow's Flow to update a certificate status. + +The flow has below tasks: + - Check the certificate status + - Update the certificate status + +The flow is LinearFlow and all the tasks are run in a single thread. +""" from oslo_config import cfg from taskflow import engines from taskflow.patterns import linear_flow @@ -30,6 +38,11 @@ def check_cert_status_and_update_flow(): + """Create flow to check and update certificate status. + + :return: Linear Flow with check and update tasks + :rtype: taskflow.patterns.linear_flow.Flow + """ flow = linear_flow.Flow('Update Akamai Property').add( check_cert_status_and_update_tasks.CheckCertStatusTask(), check_cert_status_and_update_tasks.UpdateCertStatusTask() @@ -39,6 +52,18 @@ def check_cert_status_and_update_flow(): def run_check_cert_status_and_update_flow(domain_name, cert_type, flavor_id, project_id): + """Load and Run the ``check_cert_status_and_update_flow`` using Taskflow engine. + + For details about the flow that gets run + by the engine, refer to :meth:`check_cert_status_and_update_flow()`. + + All the tasks chained in this flow, will run in single thread. + + :param unicode domain_name: The domain name + :param unicode cert_type: Type of the certificate + :param unicode flavor_id: Id of the flavor + :param unicode project_id: The project Id + """ e = engines.load( check_cert_status_and_update_flow(), store={ diff --git a/poppy/provider/akamai/background_jobs/check_cert_status_and_update/check_cert_status_and_update_tasks.py b/poppy/provider/akamai/background_jobs/check_cert_status_and_update/check_cert_status_and_update_tasks.py index b89a416d..65dcbb82 100644 --- a/poppy/provider/akamai/background_jobs/check_cert_status_and_update/check_cert_status_and_update_tasks.py +++ b/poppy/provider/akamai/background_jobs/check_cert_status_and_update/check_cert_status_and_update_tasks.py @@ -13,6 +13,16 @@ # See the License for the specific language governing permissions and # limitations under the License. +"""Checks and updates the status of certificates. + +The module has below tasks defined in it and will be +called when the parent flow is loaded into Taskflow +engine: + - Get the certificate for a given details + - Determine the needed status for the certificate + - Update the certificate with that status +""" + import json from oslo_config import cfg @@ -29,9 +39,34 @@ class GetCertInfoTask(task.Task): + """Get the certificate object. + + Fetch the certificate details from cassandra storage + for the below given values: + - domain name + - certificate type + - flavor id + - project id + + Serialize the certificate details and return. + + The returned value will be assigned to the variable + ``cert_obj_json`` and consumed by the next Task + in the flow :class:`CheckCertStatusTask` to check the status. + """ default_provides = "cert_obj_json" def execute(self, domain_name, cert_type, flavor_id, project_id): + """Return certificate details. + + :param unicode domain_name: The domain name + :param unicode cert_type: Type of the certificate + :param unicode flavor_id: Flavor id + :param unicode project_id: Project id + + :return: Serialized dict of certificate details + :rtype: str + """ service_controller, self.ssl_certificate_manager = \ memoized_controllers.task_controllers('poppy', 'ssl_certificate') self.storage = self.ssl_certificate_manager.storage @@ -45,6 +80,7 @@ def execute(self, domain_name, cert_type, flavor_id, project_id): class CheckCertStatusTask(task.Task): + """Determine the correct status for the certificate.""" default_provides = "status_change_to" def __init__(self): @@ -54,6 +90,42 @@ def __init__(self): self.akamai_driver = self.providers['akamai'].obj def execute(self, cert_obj_json): + """Get the status for the certificate based on its type. + + The ``cert_obj_json`` will be an output from the + previous task in the flow :class:`GetCertInfoTask`. + + For SAN types, Makes call to Akamai SPS API and inspects the status + returned from Akamai. + + Below are expected status from Akamai for SAN: + - 'SPS Request Complete' + - 'edge host already created or pending' + - 'CPS cancelled' + + Return a new status for the certificate based on the + SPS response status. If the status is other than the + above mentioned list, then send the certificate to + ``san mapping queue``. + + For SNI types, Makes call to CPS API and gets list of + pending changes. If the ``change url`` is still present + under pending changes, put the certificate details into + ``san mapping queue`` for future check. Else, return a + status the certificate should have. + + In either of the cert types, the returned value will be + assigned to a variable ``status_change_to`` which will + be consumed by the next task :class:`UpdateCertStatusTask` + in the flow pipeline. + + :param str cert_obj_json: Serialized certificate details + + :return: Status needs to be set for the certificate + :rtype: str + + :raises RuntimeError: If Akamai SPS request failed + """ if cert_obj_json != "": cert_obj = ssl_certificate.load_from_json( json.loads(cert_obj_json)) @@ -167,6 +239,7 @@ def execute(self, cert_obj_json): class UpdateCertStatusTask(task.Task): + """Update the certificate status""" def __init__(self): super(UpdateCertStatusTask, self).__init__() @@ -178,6 +251,15 @@ def __init__(self): self.service_storage = service_controller.storage_controller def execute(self, project_id, cert_obj_json, status_change_to): + """Update certificate and provider details. + + The ``status_change_to`` will be an output from the + previous task in the flow :class:`CheckCertStatusTask`. + + :param unicode project_id: The project id + :param str cert_obj_json: Certificate details + :param str status_change_to: New status for the certificate + """ if not cert_obj_json: return cert_obj = ssl_certificate.load_from_json( diff --git a/poppy/provider/akamai/background_jobs/delete_policy/delete_obsolete_http_policy_flow.py b/poppy/provider/akamai/background_jobs/delete_policy/delete_obsolete_http_policy_flow.py index 86cd5c7e..3f3ff26f 100644 --- a/poppy/provider/akamai/background_jobs/delete_policy/delete_obsolete_http_policy_flow.py +++ b/poppy/provider/akamai/background_jobs/delete_policy/delete_obsolete_http_policy_flow.py @@ -13,6 +13,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +"""Taskflow's Flow to delete old http policies. + +Create and return a flow that consists of +Taskflow's Task to delete the old http policies. +""" from oslo_config import cfg from oslo_log import log from taskflow.patterns import linear_flow @@ -28,6 +33,11 @@ def delete_obsolete_http_policy(): + """Create flow to delete old http policy. + + :return: Linear Flow with ``delete old http policy`` task + :rtype: taskflow.patterns.linear_flow.Flow + """ flow = linear_flow.Flow('Deleting obsolete HTTP policy').add( delete_obsolete_http_policy_tasks.DeleteObsoleteHTTPPolicy(), ) diff --git a/poppy/provider/akamai/background_jobs/delete_policy/delete_obsolete_http_policy_tasks.py b/poppy/provider/akamai/background_jobs/delete_policy/delete_obsolete_http_policy_tasks.py index 9a81bf74..8c0138ae 100644 --- a/poppy/provider/akamai/background_jobs/delete_policy/delete_obsolete_http_policy_tasks.py +++ b/poppy/provider/akamai/background_jobs/delete_policy/delete_obsolete_http_policy_tasks.py @@ -37,8 +37,10 @@ def __init__(self): def execute(self, configuration_number, policy_name): """Deletes old HTTP policy once a domain is upgraded to HTTPS+san. - :param configuration_number: akamai configuration number - :param policy_name: name of policy on akamai policy api + :param unicode configuration_number: akamai configuration number + :param unicode policy_name: name of policy on akamai policy api + + :raises RuntimeError: If Akamai Policy API failed """ resp = self.akamai_driver.policy_api_client.delete( diff --git a/poppy/provider/akamai/background_jobs/update_property/update_property_flow.py b/poppy/provider/akamai/background_jobs/update_property/update_property_flow.py index a660f1bb..0840164a 100644 --- a/poppy/provider/akamai/background_jobs/update_property/update_property_flow.py +++ b/poppy/provider/akamai/background_jobs/update_property/update_property_flow.py @@ -13,6 +13,16 @@ # See the License for the specific language governing permissions and # limitations under the License. +"""Taskflow's Flow to update and activate property. + +The flow has below tasks: + - Get latest property version + - Update the latest property + - Activate the latest property + - Update ``san mapping`` queue with activated properties + +The flow is LinearFlow and all the tasks are run in a single thread. +""" from oslo_config import cfg from taskflow import engines from taskflow.patterns import linear_flow @@ -30,6 +40,11 @@ def update_property_flow(): + """Constructs the LinearFlow of independent tasks. + + :return: A Linear Flow of property tasks + :rtype: taskflow.patterns.linear_flow.Flow + """ flow = linear_flow.Flow('Update Akamai Property').add( update_property_tasks.PropertyGetLatestVersionTask(), update_property_tasks.PropertyUpdateTask(), @@ -40,6 +55,18 @@ def update_property_flow(): def run_update_property_flow(property_spec, update_type, update_info_list): + """Load and Run the ``update_property_flow`` using Taskflow engine. + + For details about the flow that gets run + by the engine, refer to :meth:`update_property_flow()`. + + All the tasks chained in this flow, will run in single thread. + + :param unicode property_spec: The property name + :param str update_type: Type of the update + :param list update_info_list: List of tuples with action and + cname host mapping info + """ e = engines.load( update_property_flow(), store={ diff --git a/poppy/provider/akamai/background_jobs/update_property/update_property_tasks.py b/poppy/provider/akamai/background_jobs/update_property/update_property_tasks.py index 800a2c0d..c798df51 100644 --- a/poppy/provider/akamai/background_jobs/update_property/update_property_tasks.py +++ b/poppy/provider/akamai/background_jobs/update_property/update_property_tasks.py @@ -29,6 +29,15 @@ class PropertyGetLatestVersionTask(task.Task): + """Get or create latest property version. + + This is the very first Task that gets run from + the ``update_property_flow``. + + The return value from :meth:`execute()` will be + passed as parameter ``new_version_number`` to the + next task in the flow :class:`PropertyUpdateTask`. + """ default_provides = "new_version_number" def __init__(self): @@ -40,7 +49,19 @@ def __init__(self): self.akamai_conf = self.akamai_driver.akamai_conf def execute(self, property_spec): - """Get/Create a new Akamai property update version if necessary""" + """Get/Create a new Akamai property update version if necessary + + Makes calls to Akamai's PAPI to get the the property details + and to create a new property version. + + :param unicode property_spec: The property name + :return: The latest version of the property + :rtype: int + + :raises RuntimeError: If Akamai PAPI request failed + :raises ValueError: If ``production status`` of the + latest version is in ``PENDING``. + """ self.property_id = self.akamai_driver.papi_property_id(property_spec) LOG.info('Starting to get next version for property: %s' @@ -117,6 +138,15 @@ def execute(self, property_spec): class PropertyUpdateTask(task.Task): + """Update property hostnames. + + This task runs after the :class:`PropertyGetLatestVersionTask` as + part of the parent Taskflow Flow ``update_property_flow``. + + The return value from the :meth:`execute()`` will be + passed as an input to the :class:`PropertyActivateTask`` + with the name ``update_detail``. + """ default_provides = 'update_detail' def __init__(self): @@ -132,7 +162,25 @@ def __init__(self): def execute(self, property_spec, new_version_number, update_type, update_info_list): - """Update an Akamai property""" + """Update an Akamai property. + + Makes call to Akamai's PAPI to get the list of + ``hostnames`` and ``edge host name``. + + Based on add or delete actions, prepares hosts list + accordingly to update the property. + + :param unicode property_spec: The property name + :param int new_version_number: The latest property version + :param str update_type: Type of the update + :param list update_info_list: List of tuples with action and + cname host mapping info + + :return: serialized List of added and removed cnameFrom and cnameTo records + :rtype: str + + :raises RuntimeError: If PAPI request failed + """ self.property_id = self.akamai_driver.papi_property_id(property_spec) update_info_list = json.loads(update_info_list) @@ -242,7 +290,11 @@ def execute(self, property_spec, new_version_number, update_type, class PropertyActivateTask(task.Task): + """Activate the updated property into production. + This task runs after the :class:`PropertyUpdateTask` + as part of the ``update_property_flow()``. + """ def __init__(self): super(PropertyActivateTask, self).__init__() service_controller, self.providers = \ @@ -253,7 +305,26 @@ def __init__(self): def execute(self, property_spec, new_version_number, update_detail, notify_email_list=[]): - """Update an Akamai property""" + """Activate the updated property. + + Makes call to PAPI with the updated property details. + A first time Activation API call returns with 400 status + code with warning messages before activating. Make an + acknowledgement for these warning messages by making + a followup PAPI request to proceed to activation. + + :param unicode property_spec: The property id + :param int new_version_number: The latest property version + :param str update_detail: serialized List of added and + removed cnameFrom and cnameTo records + :param list notify_email_list: (Default []) List of emails + to notify about the activation + + :return: The activation link + :rtype: dict + + :raises RuntimeError: If PAPI request failed + """ self.property_id = self.akamai_driver.papi_property_id(property_spec) # This request needs json @@ -312,6 +383,10 @@ def revert(self, property_spec, new_version_number, **kwargs): class MarkQueueItemsWithActivatedProperty(task.Task): + """Update the san mapping queue with activated property. + + This task will be the final one in ``update_property_flow()``. + """ def __init__(self): super(MarkQueueItemsWithActivatedProperty, self).__init__() @@ -320,6 +395,16 @@ def __init__(self): self.akamai_driver = self.providers['akamai'].obj def execute(self, update_info_list): + """Mark certs in san mapping queue with property activated. + + Traverse the ``san mapping queue``; update and keep + those certificates whose properties are activated by + marking the field ``property_activated`` of each such + certificate. + + :param update_info_list: List of tuples with action and + cname host mapping info + """ update_info_list = json.loads(update_info_list) queue_data = self.akamai_driver.san_mapping_queue.traverse_queue()