Merge lp:~blake-rouse/maas/fix-1629045 into lp:~maas-committers/maas/trunk

Proposed by Blake Rouse
Status: Merged
Approved by: Blake Rouse
Approved revision: no longer in the source branch.
Merged at revision: 5422
Proposed branch: lp:~blake-rouse/maas/fix-1629045
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 129 lines (+57/-8)
4 files modified
src/provisioningserver/import_images/boot_resources.py (+10/-2)
src/provisioningserver/import_images/cleanup.py (+12/-6)
src/provisioningserver/import_images/tests/test_boot_resources.py (+25/-0)
src/provisioningserver/import_images/tests/test_cleanup.py (+10/-0)
To merge this branch: bzr merge lp:~blake-rouse/maas/fix-1629045
Reviewer Review Type Date Requested Status
Andres Rodriguez (community) Approve
Review via email: mp+307337@code.launchpad.net

Commit message

Cleanup snapshots and cache directory when import fails.

To post a comment you must log in.
Revision history for this message
Andres Rodriguez (andreserl) wrote :

lgtm! Just one comment inline that needs to be addressed beforehand.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/provisioningserver/import_images/boot_resources.py'
--- src/provisioningserver/import_images/boot_resources.py 2016-09-11 21:35:53 +0000
+++ src/provisioningserver/import_images/boot_resources.py 2016-09-30 18:15:17 +0000
@@ -275,8 +275,16 @@
275275
276 product_mapping = map_products(image_descriptions)276 product_mapping = map_products(image_descriptions)
277277
278 snapshot_path = download_all_boot_resources(278 try:
279 sources, storage, product_mapping)279 snapshot_path = download_all_boot_resources(
280 sources, storage, product_mapping)
281 except:
282 # Cleanup snapshots and cache since download failed.
283 maaslog.warning(
284 "Unable to import boot images; cleaning up failed snapshot "
285 "and cache.")
286 cleanup_snapshots_and_cache(storage)
287 raise
280288
281 maaslog.info("Writing boot image metadata and iSCSI targets.")289 maaslog.info("Writing boot image metadata and iSCSI targets.")
282 write_snapshot_metadata(snapshot_path, meta_file_content)290 write_snapshot_metadata(snapshot_path, meta_file_content)
283291
=== modified file 'src/provisioningserver/import_images/cleanup.py'
--- src/provisioningserver/import_images/cleanup.py 2016-03-28 13:54:47 +0000
+++ src/provisioningserver/import_images/cleanup.py 2016-09-30 18:15:17 +0000
@@ -14,7 +14,10 @@
14def list_old_snapshots(storage):14def list_old_snapshots(storage):
15 """List of snapshot directories that are no longer in use."""15 """List of snapshot directories that are no longer in use."""
16 current_dir = os.path.join(storage, 'current')16 current_dir = os.path.join(storage, 'current')
17 current_snapshot = os.path.basename(os.readlink(current_dir))17 if os.path.exists(current_dir):
18 current_snapshot = os.path.basename(os.readlink(current_dir))
19 else:
20 current_snapshot = None
18 return [21 return [
19 os.path.join(storage, directory)22 os.path.join(storage, directory)
20 for directory in os.listdir(storage)23 for directory in os.listdir(storage)
@@ -32,11 +35,14 @@
32def list_unused_cache_files(storage):35def list_unused_cache_files(storage):
33 """List of cache files that are no longer being referenced by snapshots."""36 """List of cache files that are no longer being referenced by snapshots."""
34 cache_dir = os.path.join(storage, 'cache')37 cache_dir = os.path.join(storage, 'cache')
35 cache_files = [38 if os.path.exists(cache_dir):
36 os.path.join(cache_dir, filename)39 cache_files = [
37 for filename in os.listdir(cache_dir)40 os.path.join(cache_dir, filename)
38 if os.path.isfile(os.path.join(cache_dir, filename))41 for filename in os.listdir(cache_dir)
39 ]42 if os.path.isfile(os.path.join(cache_dir, filename))
43 ]
44 else:
45 cache_files = []
40 return [46 return [
41 cache_file47 cache_file
42 for cache_file in cache_files48 for cache_file in cache_files
4349
=== modified file 'src/provisioningserver/import_images/tests/test_boot_resources.py'
--- src/provisioningserver/import_images/tests/test_boot_resources.py 2016-08-30 18:45:05 +0000
+++ src/provisioningserver/import_images/tests/test_boot_resources.py 2016-09-30 18:15:17 +0000
@@ -56,6 +56,7 @@
56from testtools.matchers import (56from testtools.matchers import (
57 DirExists,57 DirExists,
58 FileExists,58 FileExists,
59 Not,
59)60)
60import yaml61import yaml
6162
@@ -484,6 +485,30 @@
484 ],485 ],
485 list(meta_data[osystem][arch][subarch][release][label]))486 list(meta_data[osystem][arch][subarch][release][label]))
486487
488 def test_failed_run_deletes_snapshot(self):
489 # Patch out things that we don't want running during the test. Patch
490 # at a low level, so that we exercise all the function calls that a
491 # unit test might not put to the test.
492 self.patch_maaslog()
493 self.patch(boot_resources, 'call_and_check')
494 self.patch(boot_resources, "service_monitor")
495
496 args = self.make_working_args()
497
498 # Cause the import to fail.
499 exception_type = factory.make_exception_type()
500 mock_download = self.patch(
501 boot_resources, "download_all_boot_resources")
502 mock_download.side_effect = exception_type()
503
504 # Run the import code.
505 self.assertRaises(exception_type, boot_resources.main, args)
506
507 # Verify the reuslts.
508 self.assertThat(os.path.join(self.storage, 'cache'), Not(DirExists()))
509 self.assertThat(
510 os.path.join(self.storage, 'current'), Not(DirExists()))
511
487 def test_warns_if_no_sources_selected(self):512 def test_warns_if_no_sources_selected(self):
488 self.patch_maaslog()513 self.patch_maaslog()
489 sources_fixture = self.useFixture(BootSourcesFixture([]))514 sources_fixture = self.useFixture(BootSourcesFixture([]))
490515
=== modified file 'src/provisioningserver/import_images/tests/test_cleanup.py'
--- src/provisioningserver/import_images/tests/test_cleanup.py 2016-03-28 13:54:47 +0000
+++ src/provisioningserver/import_images/tests/test_cleanup.py 2016-09-30 18:15:17 +0000
@@ -40,6 +40,11 @@
40 os.link(cache_path, link_path)40 os.link(cache_path, link_path)
41 return cache_path41 return cache_path
4242
43 def test_list_old_snapshots_returns_all(self):
44 storage = self.make_dir()
45 snapshots = [self.make_snapshot_dir(storage) for _ in range(3)]
46 self.assertItemsEqual(snapshots, cleanup.list_old_snapshots(storage))
47
43 def test_list_old_snapshots_returns_all_but_current_directory(self):48 def test_list_old_snapshots_returns_all_but_current_directory(self):
44 storage = self.make_dir()49 storage = self.make_dir()
45 snapshots = [self.make_snapshot_dir(storage) for _ in range(3)]50 snapshots = [self.make_snapshot_dir(storage) for _ in range(3)]
@@ -62,6 +67,11 @@
62 ]67 ]
63 self.assertEqual([], remaining_snapshots)68 self.assertEqual([], remaining_snapshots)
6469
70 def test_list_unused_cache_files_returns_empty(self):
71 storage = self.make_dir()
72 self.assertItemsEqual(
73 [], cleanup.list_unused_cache_files(storage))
74
65 def test_list_unused_cache_files_returns_all_files_nlink_equal_one(self):75 def test_list_unused_cache_files_returns_all_files_nlink_equal_one(self):
66 storage = self.make_dir()76 storage = self.make_dir()
67 cache_nlink_1 = [self.make_cache_file(storage) for _ in range(3)]77 cache_nlink_1 = [self.make_cache_file(storage) for _ in range(3)]