Skip to content

Commit fc5967d

Browse files
authored
Merge pull request redhat-performance#448 from grafuls/development
fix: better session handling
2 parents 9a82d01 + 43ae6f0 commit fc5967d

File tree

7 files changed

+770
-27
lines changed

7 files changed

+770
-27
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,6 @@ venv.bak/
113113
# SCP Exports folder (Testing purpose)
114114
tests/exports/
115115
exports/
116+
117+
# VSCode
118+
.vscode/

src/badfish/main.py

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,16 @@ def __init__(self, _host, _username, _password, _logger, _retries, _loop=None):
6969
self.token = None
7070
self.vendor = None
7171

72+
async def __aenter__(self):
73+
await self.init()
74+
return self
75+
76+
async def __aexit__(self, exc_type, exc_val, exc_tb):
77+
await self.delete_session()
78+
if exc_type is not None:
79+
self.logger.debug(f"Exiting context with exception: {exc_type.__name__}: {exc_val}")
80+
return False
81+
7282
async def init(self):
7383
self.session_uri = await self.find_session_uri()
7484
self.token = await self.validate_credentials()
@@ -2126,12 +2136,29 @@ async def take_screenshot(self):
21262136
return True
21272137

21282138
async def delete_session(self):
2129-
headers = {"content-type": "application/json"}
2130-
_uri = "%s%s" % (self.host_uri, self.session_id)
2131-
_response = await self.delete_request(_uri, headers=headers)
2132-
if _response.status not in [200, 201]:
2133-
raise BadfishException(f"Failed to delete X-Auth-Token for {self.host}")
2134-
return
2139+
try:
2140+
try:
2141+
if not self.session_id:
2142+
self.logger.debug("No session ID found, skipping session deletion")
2143+
return
2144+
headers = {"content-type": "application/json"}
2145+
_uri = "%s%s" % (self.host_uri, self.session_id)
2146+
try:
2147+
_response = await self.delete_request(_uri, headers=headers)
2148+
if _response.status in [200, 201]:
2149+
self.logger.debug(f"Session successfully deleted for {self.host}")
2150+
elif _response.status == 404:
2151+
self.logger.debug(f"Session not found (404) for {self.host}, may have been already deleted")
2152+
else:
2153+
self.logger.warning(f"Unexpected status {_response.status} when deleting session for {self.host}.")
2154+
except Exception as ex:
2155+
self.logger.warning(f"Failed to delete session for {self.host}: {ex}")
2156+
finally:
2157+
self.session_id = None
2158+
self.token = None
2159+
except Exception:
2160+
self.session_id = None
2161+
self.token = None
21352162

21362163
async def get_scp_targets(self, op):
21372164
uri = "%s%s" % (self.host_uri, self.manager_resource)
@@ -2564,6 +2591,7 @@ async def execute_badfish(_host, _args, logger, format_handler=None):
25642591
get_nic_attribute = _args["get_nic_attribute"]
25652592
set_nic_attribute = _args["set_nic_attribute"]
25662593
result = True
2594+
badfish = None
25672595

25682596
try:
25692597
badfish = await badfish_factory(
@@ -2684,10 +2712,16 @@ async def execute_badfish(_host, _args, logger, format_handler=None):
26842712
if pxe and not host_type:
26852713
await badfish.set_next_boot_pxe()
26862714

2687-
await badfish.delete_session()
26882715
except BadfishException as ex:
26892716
logger.error(ex)
26902717
result = False
2718+
finally:
2719+
if badfish and badfish.session_id:
2720+
try:
2721+
await badfish.delete_session()
2722+
logger.debug(f"Session closed for host: {_host}")
2723+
except BadfishException as ex:
2724+
logger.warning(f"Failed to close session for {_host}: {ex}")
26912725

26922726
if _args["host_list"]:
26932727
logger.info("*" * 48)

tests/config.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,12 +372,14 @@ def render_device_dict(index, device):
372372
"- INFO - Attempting to clear job list instead.\n"
373373
"- WARNING - Clearing job queue for job IDs: ['JID_498218641680'].\n"
374374
"- ERROR - Job queue not cleared, there was something wrong with your request.\n"
375+
"- WARNING - Unexpected status 400 when deleting session for f01-h01-000-r630.host.io.\n"
375376
)
376377
RESPONSE_DELETE_JOBS_UNSUPPORTED_EXCEPTION = (
377378
"- WARNING - iDRAC version installed does not support DellJobService\n"
378379
"- INFO - Attempting to clear job list instead.\n"
379380
"- WARNING - Clearing job queue for job IDs: ['JID_498218641680'].\n"
380381
"- ERROR - Failed to communicate with server.\n"
382+
"- WARNING - Failed to delete session for f01-h01-000-r630.host.io: Failed to communicate with server.\n"
381383
)
382384
RESPONSE_DELETE_JOBS_SUPPORTED_EXCEPTION = "- ERROR - Error reading response from host.\n"
383385

@@ -616,7 +618,7 @@ def render_device_dict(index, device):
616618
"- INFO - ProcessorType: Accelerator\n"
617619
)
618620

619-
RESPONSE_LS_GPU_SUMMARY_DATA_ERROR = "- ERROR - GPU endpoint not available on host.\n"
621+
RESPONSE_LS_GPU_SUMMARY_DATA_ERROR = "- ERROR - GPU endpoint not available on host.\n- WARNING - Failed to delete session for f01-h01-000-r630.host.io: Failed to communicate with server.\n"
620622
RESPONSE_LS_GPU_SUMMARY_VALUE_ERROR = "- ERROR - There was something wrong getting GPU summary values.\n"
621623
RESPONSE_LS_GPU_SUMMARY_BAD_JSON = "- ERROR - There was something wrong getting GPU data\n"
622624
RESPONSE_LS_GPU_DETAILS_NOT_FOUND = "- ERROR - There was something wrong getting host GPU details\n"

tests/test_base.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,16 @@ async def get_application(self):
1919
@staticmethod
2020
def set_mock_response(mock, status, responses, post=False, headers=None):
2121
mock.return_value.__aenter__.return_value.name = responses
22+
status_mock = MagicMock()
2223
if type(status) == list:
23-
status_mock = MagicMock()
2424
if post:
2525
dup_stats = [val for val in status for _ in range(2)]
2626
type(status_mock).status = PropertyMock(side_effect=dup_stats)
2727
else:
2828
type(status_mock).status = PropertyMock(side_effect=status)
29-
mock.return_value.__aenter__.return_value = status_mock
3029
else:
31-
mock.return_value.__aenter__.return_value.status = status
30+
type(status_mock).status = PropertyMock(return_value=status)
31+
mock.return_value.__aenter__.return_value = status_mock
3232
mock.return_value.__aenter__.return_value.read = AsyncMock()
3333
if type(responses) == list:
3434
mock.return_value.__aenter__.return_value.text = AsyncMock(

tests/test_bios_password.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ def test_set_bios_pass_cmd_failed(self, mock_get, mock_post, mock_delete):
107107
responses = INIT_RESP
108108
self.set_mock_response(mock_get, 200, responses)
109109
self.set_mock_response(mock_post, [200, 400], ["OK", "Bad Request"], True)
110+
self.set_mock_response(mock_delete, 200, "OK")
110111
self.args = [self.option_arg, "--new-password", "new_pass"]
111112
_, err = self.badfish_call()
112113
assert err == BIOS_PASS_CHANGE_CMD_FAILED

0 commit comments

Comments
 (0)