Skip to content

Commit 10e533f

Browse files
committed
added enter / exit methods to start / stop sandbox
1 parent 4b4236c commit 10e533f

File tree

2 files changed

+112
-9
lines changed

2 files changed

+112
-9
lines changed

src/cloudshell/sandbox_rest/exceptions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def __init__(self, message: str, error_events: List[model.SandboxEvent] = None):
3737
super().__init__(message, error_events)
3838

3939

40-
class TeardownFailedException(SandboxRestException):
40+
class TeardownFailedException(FailedOrchestrationException):
4141
def __init__(self, message: str, error_events: List[model.SandboxEvent] = None):
4242
super().__init__(message, error_events)
4343

src/cloudshell/sandbox_rest/sandbox_context.py

Lines changed: 111 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,144 @@
66
- async commands executor member
77
"""
88
import logging
9+
from typing import List
910

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
1114
from cloudshell.sandbox_rest.async_commands import AsyncCommandExecutor
1215
from cloudshell.sandbox_rest.components import SandboxComponents
16+
from dataclasses import dataclass
17+
from timeit import default_timer
1318

1419

20+
@dataclass
1521
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
1737

1838

1939
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):
2242
self.api = api
23-
self.sandbox_request = sandbox_request
2443
self.sandbox_id = sandbox_id
44+
self.sandbox_request = sandbox_request
45+
self.teardown_settings = teardown_settings
2546
self.logger = logger
2647
self.components = SandboxComponents()
2748
self.async_executor = AsyncCommandExecutor()
2849
self.setup_duration_seconds: int = None
2950
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()
32132

33133
def __enter__(self):
34134
""" start sandbox """
135+
self.launch_sandbox()
35136
return self
36137

37138
def __exit__(self, exc_type, exc_val, exc_tb):
38139
""" end sandbox """
140+
self.teardown_sandbox()
39141
return self
40142

41143
def refresh_components(self):
42144
self.components.refresh_components(self.api, self.sandbox_id)
43145

44146

45147
if __name__ == "__main__":
46-
controller = SandboxControllerContext()
148+
controller = SandboxControllerContext()
149+
controller.async_executor

0 commit comments

Comments
 (0)