Skip to content

Commit b6e52b5

Browse files
committed
Try a context manager API to start systems. refs: #29
1 parent 1750c26 commit b6e52b5

File tree

3 files changed

+44
-9
lines changed

3 files changed

+44
-9
lines changed

moncic/imagestorage.py

+29-3
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
import subprocess
99
import tempfile
1010
from collections import defaultdict
11-
from typing import TYPE_CHECKING, Generator, List
11+
from typing import TYPE_CHECKING, ContextManager, Generator, List
1212

1313
from .btrfs import do_dedupe, is_btrfs
14-
from .system import System, SystemConfig
14+
from .system import MaintenanceSystem, System, SystemConfig
1515
from .utils import is_on_rotational, pause_automounting
1616

1717
if TYPE_CHECKING:
@@ -47,10 +47,36 @@ def list_images(self) -> List[str]:
4747

4848
def create_system(self, name: str) -> System:
4949
"""
50-
Instantiate a System from its name or path
50+
Instantiate a System by its name
5151
"""
5252
raise NotImplementedError(f"{self.__class__.__name__}.create_system is not implemented")
5353

54+
def system(self, name: str) -> ContextManager[System]:
55+
"""
56+
Instantiate a System that can only be used for the duration
57+
of this context manager.
58+
"""
59+
# raise NotImplementedError(f"{self.__class__.__name__}.maintenance_system is not implemented")
60+
@contextlib.contextmanager
61+
def res():
62+
yield self.create_system(name)
63+
return res()
64+
65+
def maintenance_system(self, name: str) -> ContextManager[MaintenanceSystem]:
66+
"""
67+
Instantiate a MaintenanceSystem that can only be used for the duration
68+
of this context manager.
69+
70+
This allows maintenance to be transactional, limited to backends that
71+
support it, so that errors in the maintenance roll back to the previous
72+
state and do not leave an inconsistent OS image
73+
"""
74+
# raise NotImplementedError(f"{self.__class__.__name__}.maintenance_system is not implemented")
75+
@contextlib.contextmanager
76+
def res():
77+
yield self.create_system(name)
78+
return res()
79+
5480
def add_dependencies(self, images: List[str]) -> List[str]:
5581
"""
5682
Add dependencies to the given list of images, returning the extended

moncic/system.py

+6
Original file line numberDiff line numberDiff line change
@@ -298,3 +298,9 @@ def create_container(
298298
# Import here to avoid an import loop
299299
from .container import NspawnContainer
300300
return NspawnContainer(self, config, instance_name)
301+
302+
303+
class MaintenanceSystem(System):
304+
"""
305+
System used to do maintenance on an OS image
306+
"""

tests/test_machine.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -21,32 +21,35 @@ class RunTestCase:
2121
@classmethod
2222
def setUpClass(cls):
2323
super().setUpClass()
24-
cls.exit_stack = contextlib.ExitStack()
25-
# cls.workdir = cls.exit_stack.enter_context(tempfile.TemporaryDirectory())
24+
cls.cls_exit_stack = contextlib.ExitStack()
25+
# cls.workdir = cls.cls_exit_stack.enter_context(tempfile.TemporaryDirectory())
2626
# cls.moncic = make_moncic(imagedir=cls.workdir)
2727
cls.moncic = make_moncic()
28-
cls.images = cls.exit_stack.enter_context(cls.moncic.images())
28+
cls.images = cls.cls_exit_stack.enter_context(cls.moncic.images())
2929

3030
@classmethod
3131
def tearDownClass(cls):
32-
cls.exit_stack.close()
32+
cls.cls_exit_stack.close()
3333
cls.images = None
3434
cls.moncic = None
3535
# cls.workdir = None
36-
cls.exit_stack = None
36+
cls.cls_exit_stack = None
3737
super().tearDownClass()
3838

3939
def setUp(self):
4040
super().setUp()
41+
self.exit_stack = contextlib.ExitStack()
4142
with privs.root():
4243
if self.distro_name not in self.images.list_images():
4344
raise unittest.SkipTest(f"Image {self.distro_name} not available")
44-
self.system = self.images.create_system(self.distro_name)
45+
self.system = self.exit_stack.enter_context(self.images.system(self.distro_name))
4546
if not os.path.exists(self.system.path):
4647
raise unittest.SkipTest(f"Image {self.distro_name} has not been bootstrapped")
4748

4849
def tearDown(self):
4950
self.system = None
51+
self.exit_stack.close()
52+
self.exit_stack = None
5053
super().tearDown()
5154

5255
def test_true(self):

0 commit comments

Comments
 (0)