diff --git a/charon/cache.py b/charon/cache.py index 86841ead..17ea22ac 100644 --- a/charon/cache.py +++ b/charon/cache.py @@ -4,6 +4,7 @@ import os import logging import uuid +import time logger = logging.getLogger(__name__) @@ -82,13 +83,33 @@ def invalidate_paths( The default value is 3000 which is the maximum number in official doc: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Invalidation.html#InvalidationLimits """ - logger.debug("[CloudFront] Creating invalidation for paths: %s", paths) real_paths = [paths] # Split paths into batches by batch_size if batch_size: real_paths = [paths[i:i + batch_size] for i in range(0, len(paths), batch_size)] results = [] + current_invalidation = {} for batch_paths in real_paths: + while (current_invalidation and + 'InProgress' == current_invalidation.get('Status', '')): + time.sleep(5) + try: + result = self.check_invalidation(distr_id, current_invalidation.get('Id')) + if result: + current_invalidation = { + 'Id': result.get('Id', None), + 'Status': result.get('Status', None) + } + logger.debug("Check invalidation: %s", current_invalidation) + except Exception as err: + logger.warning( + "[CloudFront] Error occurred while checking invalidation status during" + " creating invalidation, invalidation: %s, error: %s", + current_invalidation, err + ) + break + if current_invalidation: + results.append(current_invalidation) caller_ref = str(uuid.uuid4()) logger.debug( "Processing invalidation for batch with ref %s, size: %s", @@ -107,15 +128,17 @@ def invalidate_paths( ) if response: invalidation = response.get('Invalidation', {}) - results.append({ + current_invalidation = { 'Id': invalidation.get('Id', None), 'Status': invalidation.get('Status', None) - }) + } except Exception as err: logger.error( "[CloudFront] Error occurred while creating invalidation" " for paths %s, error: %s", batch_paths, err ) + if current_invalidation: + results.append(current_invalidation) return results def check_invalidation(self, distr_id: str, invalidation_id: str) -> dict: diff --git a/tests/test_cfclient.py b/tests/test_cfclient.py index 455af65c..8a38a68e 100644 --- a/tests/test_cfclient.py +++ b/tests/test_cfclient.py @@ -45,14 +45,23 @@ def test_get_distribution_id(self): dist_id = self.cf_client.get_dist_id_by_domain("notexists.redhat.com") self.assertIsNone(dist_id) - def test_invalidate_paths(self): + def test_invalidate_paths_single(self): dist_id = self.cf_client.get_dist_id_by_domain("maven.repository.redhat.com") result = self.cf_client.invalidate_paths(dist_id, ["/*"]) + self.assertEqual(len(result), 1) self.assertTrue(result[0]['Id']) self.assertEqual('completed', str.lower(result[0]['Status'])) status = self.cf_client.invalidate_paths("noexists_id", ["/*"]) self.assertFalse(status) + def test_invalidate_paths_multi(self): + dist_id = self.cf_client.get_dist_id_by_domain("maven.repository.redhat.com") + result = self.cf_client.invalidate_paths(dist_id, ["/1", "/2", "/3"], batch_size=1) + self.assertEqual(len(result), 3) + for r in result: + self.assertTrue(r['Id']) + self.assertEqual('completed', str.lower(r['Status'])) + @pytest.mark.skip(reason=""" Because current moto 5.0.3 has not implemented the get_invalidation(), this test will fail. Will enable it when the it is implemented in future moto