11# This file is part of pycloudlib. See LICENSE file for license information.
22"""Base class for all other clouds to provide consistent set of functions."""
33
4+ import dataclasses
45import enum
56import getpass
67import io
@@ -34,6 +35,14 @@ class ImageType(enum.Enum):
3435 PRO_FIPS = "Pro FIPS"
3536
3637
38+ @dataclasses .dataclass
39+ class ImageInfo :
40+ """Dataclass to hold image information."""
41+
42+ id : str
43+ name : str
44+
45+
3746class BaseCloud (ABC ):
3847 """Base Cloud Class."""
3948
@@ -54,7 +63,8 @@ def __init__(
5463 config_file: path to pycloudlib configuration file
5564 """
5665 self .created_instances : List [BaseInstance ] = []
57- self .created_images : List [str ] = []
66+ self .created_images : List [ImageInfo ] = []
67+ self .preserved_images : List [ImageInfo ] = [] # each dict will hold an id and name
5868
5969 self ._log = logging .getLogger ("{}.{}" .format (__name__ , self .__class__ .__name__ ))
6070 self ._check_and_set_config (config_file , required_values )
@@ -188,12 +198,13 @@ def launch(
188198 raise NotImplementedError
189199
190200 @abstractmethod
191- def snapshot (self , instance , clean = True , ** kwargs ):
201+ def snapshot (self , instance , * , clean = True , keep = False , ** kwargs ):
192202 """Snapshot an instance and generate an image from it.
193203
194204 Args:
195205 instance: Instance to snapshot
196206 clean: run instance clean method before taking snapshot
207+ keep: keep the snapshot after the cloud instance is cleaned up
197208
198209 Returns:
199210 An image id
@@ -215,11 +226,18 @@ def clean(self) -> List[Exception]:
215226 instance .delete ()
216227 except Exception as e :
217228 exceptions .append (e )
218- for image_id in self .created_images :
229+ for image_info in self .created_images :
219230 try :
220- self .delete_image (image_id )
231+ self .delete_image (image_id = image_info . id )
221232 except Exception as e :
222233 exceptions .append (e )
234+ for image_info in self .preserved_images :
235+ # noop - just log that we're not cleaning up these images
236+ self ._log .info (
237+ "Preserved image %s [id:%s] is NOT being cleaned up." ,
238+ image_info .name ,
239+ image_info .id ,
240+ )
223241 return exceptions
224242
225243 def list_keys (self ):
@@ -312,3 +330,38 @@ def _validate_tag(tag: str):
312330
313331 if rules_failed :
314332 raise InvalidTagNameError (tag = tag , rules_failed = rules_failed )
333+
334+ def _store_snapshot_info (
335+ self ,
336+ snapshot_id : str ,
337+ snapshot_name : str ,
338+ keep_snapshot : bool ,
339+ ) -> ImageInfo :
340+ """
341+ Store the snapshot information in the appropriate list.
342+
343+ :param snapshot_id: ID of the snapshot
344+ :param snapshot_name: Name of the snapshot
345+ :param keep_snapshot: Whether or not to keep the snapshot
346+
347+ :return: ImageInfo object with the snapshot information
348+ """
349+ image_info = ImageInfo (
350+ id = snapshot_id ,
351+ name = snapshot_name ,
352+ )
353+ if not keep_snapshot :
354+ self .created_images .append (image_info )
355+ self ._log .info (
356+ "Created temporary snapshot %s [id:%s]" ,
357+ image_info .name ,
358+ image_info .id ,
359+ )
360+ else :
361+ self .preserved_images .append (image_info )
362+ self ._log .info (
363+ "Created permanent snapshot %s [id:%s]" ,
364+ image_info .name ,
365+ image_info .id ,
366+ )
367+ return image_info
0 commit comments