6
6
- async commands executor member
7
7
"""
8
8
import logging
9
+ from typing import List
9
10
10
- from cloudshell .sandbox_rest .api import SandboxRestApiSession
11
+ from cloudshell .sandbox_rest .api import SandboxRestApiSession , CommandInputParam
12
+ from cloudshell .sandbox_rest import exceptions
13
+ from cloudshell .sandbox_rest import model
11
14
from cloudshell .sandbox_rest .async_commands import AsyncCommandExecutor
12
15
from cloudshell .sandbox_rest .components import SandboxComponents
16
+ from dataclasses import dataclass
17
+ from timeit import default_timer
13
18
14
19
20
+ @dataclass
15
21
class SandboxStartRequest :
16
- pass
22
+ blueprint_id : str
23
+ sandbox_name : str = ""
24
+ duration : str = "PT2H0M"
25
+ bp_params : List [CommandInputParam ] = None
26
+ permitted_users : List [str ] = None
27
+ max_polling_minutes : int = 20
28
+ polling_frequency_seconds : int = 30
29
+ polling_log_level : int = logging .DEBUG
30
+
31
+
32
+ @dataclass
33
+ class TeardownSettings :
34
+ max_polling_minutes : int = 20
35
+ polling_frequency_seconds : int = 30
36
+ polling_log_level : int = logging .DEBUG
17
37
18
38
19
39
class SandboxControllerContext :
20
- def __init__ (self , api : SandboxRestApiSession , sandbox_request : SandboxStartRequest = None , sandbox_id : str = None ,
21
- logger : logging .Logger = None ):
40
+ def __init__ (self , api : SandboxRestApiSession , sandbox_id : str = None ,sandbox_request : SandboxStartRequest = None ,
41
+ teardown_settings = TeardownSettings (), logger : logging .Logger = None ):
22
42
self .api = api
23
- self .sandbox_request = sandbox_request
24
43
self .sandbox_id = sandbox_id
44
+ self .sandbox_request = sandbox_request
45
+ self .teardown_settings = teardown_settings
25
46
self .logger = logger
26
47
self .components = SandboxComponents ()
27
48
self .async_executor = AsyncCommandExecutor ()
28
49
self .setup_duration_seconds : int = None
29
50
self .teardown_duration_seconds : int = None
30
- self .setup_errors = None
31
- self .teardown_errors = None
51
+ self .setup_errors : List [model .SandboxEvent ] = None
52
+ self .teardown_errors : List [model .SandboxEvent ] = None
53
+ self ._validate_init ()
54
+
55
+ def _validate_init (self ):
56
+ if not self .sandbox_request and not self .sandbox_id :
57
+ raise ValueError ("Must supply either an existing sandbox id or a SandboxStartRequest object" )
58
+
59
+ def _info_log (self , msg : str ):
60
+ if self .logger :
61
+ self .logger .info (msg )
62
+
63
+ def _debug_log (self , msg : str ):
64
+ if self .logger :
65
+ self .logger .debug (msg )
66
+
67
+ def _error_log (self , msg : str ):
68
+ if self .logger :
69
+ self .logger .error (msg )
70
+
71
+ def launch_sandbox (self ):
72
+ if self .sandbox_id :
73
+ self ._debug_log (f"launch sandbox called for existing sandbox '{ self .sandbox_id } '. Returning" )
74
+ return
75
+
76
+ if not self .sandbox_request :
77
+ raise ValueError ("No StartSandboxRequest object passed to init" )
78
+
79
+ start_response = self .api .start_sandbox (blueprint_id = self .sandbox_request .blueprint_id ,
80
+ sandbox_name = self .sandbox_request .sandbox_name ,
81
+ duration = self .sandbox_request .duration ,
82
+ bp_params = self .sandbox_request .bp_params ,
83
+ permitted_users = self .sandbox_request .permitted_users )
84
+ self .sandbox_id = start_response .id
85
+ self ._info_log (f"Sandbox '{ self .sandbox_id } ' started." )
86
+ self ._info_log ("Starting blocking sandbox and polling..." )
87
+ start = default_timer ()
88
+ try :
89
+ self .api .poll_sandbox_setup (reservation_id = self .sandbox_id ,
90
+ max_polling_minutes = self .sandbox_request .max_polling_minutes ,
91
+ polling_frequency_seconds = self .sandbox_request .polling_frequency_seconds ,
92
+ log_level = self .sandbox_request .polling_log_level )
93
+ except exceptions .SetupFailedException as e :
94
+ self .setup_errors = e .error_events
95
+ setup_duration_seconds = default_timer () - start
96
+ self ._error_log (f"Sandbox '{ self .sandbox_id } ' setup FAILED after { setup_duration_seconds } seconds" )
97
+ self ._error_log (str (e ))
98
+ raise
99
+
100
+ setup_duration_seconds = default_timer () - start
101
+ self ._info_log (f"Sandbox '{ self .sandbox_id } ' setup completed after { setup_duration_seconds } seconds" )
102
+ self .setup_duration_seconds = setup_duration_seconds
103
+ self .refresh_components ()
104
+
105
+ def teardown_sandbox (self ):
106
+ if not self .sandbox_id :
107
+ self ._debug_log ("Trying to start teardown, but no sandbox ID found. Returning" )
108
+ return
109
+
110
+ if self .teardown_duration_seconds :
111
+ self ._debug_log (f"Teardown has already ran for sandbox '{ self .sandbox_id } '. Returning" )
112
+
113
+ self ._info_log (f"starting blocking teardown of sandbox '{ self .sandbox_id } '" )
114
+ start = default_timer ()
115
+ try :
116
+ self .api .stop_sandbox (sandbox_id = self .sandbox_id ,
117
+ poll_teardown = True ,
118
+ max_polling_minutes = self .teardown_settings .max_polling_minutes ,
119
+ polling_frequency_seconds = self .teardown_settings .polling_frequency_seconds ,
120
+ polling_log_level = self .teardown_settings .polling_log_level )
121
+ except exceptions .TeardownFailedException as e :
122
+ self .teardown_errors = e .error_events
123
+ teardown_duration_seconds = default_timer () - start
124
+ self ._error_log (f"Sandbox '{ self .sandbox_id } ' setup FAILED after { teardown_duration_seconds } seconds" )
125
+ self ._error_log (str (e ))
126
+ raise
127
+
128
+ teardown_duration_seconds = default_timer () - start
129
+ self ._info_log (f"Sandbox '{ self .sandbox_id } ' teardown completed after { teardown_duration_seconds } seconds" )
130
+ self .teardown_duration_seconds = teardown_duration_seconds
131
+ self .refresh_components ()
32
132
33
133
def __enter__ (self ):
34
134
""" start sandbox """
135
+ self .launch_sandbox ()
35
136
return self
36
137
37
138
def __exit__ (self , exc_type , exc_val , exc_tb ):
38
139
""" end sandbox """
140
+ self .teardown_sandbox ()
39
141
return self
40
142
41
143
def refresh_components (self ):
42
144
self .components .refresh_components (self .api , self .sandbox_id )
43
145
44
146
45
147
if __name__ == "__main__" :
46
- controller = SandboxControllerContext ()
148
+ controller = SandboxControllerContext ()
149
+ controller .async_executor
0 commit comments