Skip to content

Conversation

@LinJin23
Copy link
Contributor

@LinJin23 LinJin23 commented Aug 11, 2025

Description

This PR refactors the PSU object retrieval logic in psud by extracting the platform_chassis.get_psu() call into a dedicated wrapper function _wrapper_get_psu(). In addition, the process no longer exits when platform_psuutil is unavailable. The change improves exception handling consistency and code maintainability by centralizing PSU object retrieval logic.

Motivation and Context

The original code had duplicate platform_chassis.get_psu(psu_index - 1) calls scattered across multiple wrapper functions, making it difficult to maintain consistent exception handling and increasing code duplication.

How Has This Been Tested?

Unit tests were extended to test the PSU exception handling features and tested in physical platform.

Additional Information (Optional)

@mssonicbld
Copy link
Collaborator

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@LinJin23 LinJin23 changed the title add exception handling in add_exception_psu [psud] Refactor PSU object retrieval to improve exception handling Aug 11, 2025
@LinJin23 LinJin23 requested a review from vvolam August 13, 2025 01:08
if platform_chassis is not None:
try:
return platform_chassis.get_psu(psu_index - 1)
except NotImplementedError: # TODO: Is NotImplementedError sufficient?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log a warning for this exception and return None, Also add a general exception to make the code robust.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

def _wrapper_get_psu_presence(psu_index):
if platform_chassis is not None:
psu = _wrapper_get_psu(psu_index)
if not psu:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if psu returned is None here, add exception here to log error and returning false.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@mssonicbld
Copy link
Collaborator

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

try:
return platform_chassis.get_psu(psu_index - 1)
except NotImplementedError as e:
logger.log_warning("get_psu() not implemented by platform chassis: {}".format(str(e)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this something that needs to be logged? Also in its current form, you'll get two conflicting logs. Say you run the wrapper to get presence, this get_psu wrapper will log "get_psu() not implemented by platform chassis: {}" and return none, but now that its none the get_presence will print "Failed to get PSU {} object from platform chassis".

This also seems to deviate from the prior behavior where if the platform_chassis doesn't have the get_psu, it will fallback to the platform_psuutil case. Is it possible that some vendors have not implemented this get_psu on the platform_chassis and still rely on this fallback?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your pointing out.

psu = _wrapper_get_psu(psu_index)
if not psu:
logger.log_error("Failed to get PSU {} object from platform chassis".format(psu_index))
return ''
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo this should be a case where it returns the PSU_INFO_KEY_TEMPLATE, not an empty string.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@LinJin23
Copy link
Contributor Author

/azpw run

@mssonicbld
Copy link
Collaborator

/AzurePipelines run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@mssonicbld
Copy link
Collaborator

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Signed-off-by: Lin Jin <[email protected]>
@mssonicbld
Copy link
Collaborator

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Signed-off-by: Lin Jin <[email protected]>
@mssonicbld
Copy link
Collaborator

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Signed-off-by: Lin Jin <[email protected]>
@mssonicbld
Copy link
Collaborator

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Signed-off-by: Lin Jin <[email protected]>
@mssonicbld
Copy link
Collaborator

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@LinJin23 LinJin23 requested a review from Copilot November 4, 2025 22:51
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 11 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

except NotImplementedError:
pass
except Exception as e:
logger.log_warning("Exception in psu.get_presence() for PSU {}: {}".format(psu_index, str(e)))
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing null check for logger before calling log_warning. This will cause an AttributeError if logger is None. The same pattern is correctly handled on line 143-144 with an if logger: check.

Suggested change
logger.log_warning("Exception in psu.get_presence() for PSU {}: {}".format(psu_index, str(e)))
if logger:
logger.log_warning("Exception in psu.get_presence() for PSU {}: {}".format(psu_index, str(e)))

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

# some functionality is expectent on returning an expected key even if the psu object itself does not exist
pass
except Exception as e:
return False
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning False in get_psu_key() is inconsistent with the function's purpose. The function should return a string key identifying the PSU. In all other exception paths (NotImplementedError, IndexError), it falls through to return PSU_INFO_KEY_TEMPLATE.format(psu_index) on line 191. This general Exception handler should either return the same default template or be removed to allow the fall-through behavior.

Suggested change
return False
pass

Copilot uses AI. Check for mistakes.
judyjoseph
judyjoseph previously approved these changes Nov 5, 2025
Copy link
Contributor

@judyjoseph judyjoseph left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@judyjoseph
Copy link
Contributor

/azp run

@judyjoseph judyjoseph requested a review from vvolam November 5, 2025 21:22
@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Signed-off-by: Lin Jin <[email protected]>
@mssonicbld
Copy link
Collaborator

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@LinJin23 LinJin23 requested a review from Copilot November 6, 2025 07:27
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@mssonicbld
Copy link
Collaborator

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@LinJin23 LinJin23 requested a review from Copilot November 6, 2025 08:53
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

#

def get_psu_key(psu_index):
if platform_chassis is not None:
Copy link

Copilot AI Nov 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The get_psu_key function passes None as the logger parameter to _wrapper_get_psu. While this is intentional to avoid logging in this context, the function should include a comment explaining why logging is suppressed here, as this is a deviation from other usages where self (the logger) is passed.

Suggested change
if platform_chassis is not None:
if platform_chassis is not None:
# Intentionally pass None as the logger to suppress logging in this context,
# as get_psu_key is only used for key generation and not for error reporting.
# This deviates from other usages where a logger is passed.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t think it’s necessary.

Comment on lines +108 to +112
Get PSU object from platform chassis
:param logger: Logger instance for error/warning messages
:param psu_index: PSU index (1-based)
:return: PSU object if available, None otherwise
Copy link

Copilot AI Nov 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring should explicitly mention that this function only attempts to retrieve PSU from platform_chassis and does not fall back to platform_psuutil, as this is a key behavioral difference from other wrapper functions like _wrapper_get_psu_presence and _wrapper_get_psu_status.

Suggested change
Get PSU object from platform chassis
:param logger: Logger instance for error/warning messages
:param psu_index: PSU index (1-based)
:return: PSU object if available, None otherwise
Get PSU object from platform chassis.
This function only attempts to retrieve the PSU from `platform_chassis` and does not fall back to
`platform_psuutil`, unlike other wrapper functions such as `_wrapper_get_psu_presence` and
`_wrapper_get_psu_status`.
:param logger: Logger instance for error/warning messages
:param psu_index: PSU index (1-based)
:return: PSU object if available, None otherwise

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t think it’s necessary.

@LinJin23 LinJin23 requested a review from judyjoseph November 10, 2025 00:13
@judyjoseph judyjoseph requested a review from Copilot November 10, 2025 15:50
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

psud.platform_psuutil = mock.MagicMock()
psud._wrapper_get_num_psus(None)
assert psud.platform_chassis.get_num_psus.call_count >= 1

Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace should be removed for code cleanliness.

Suggested change

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

mock_logger = mock.MagicMock()
mock_psu = mock.MagicMock()
mock_psu.get_presence.return_value = True

Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace should be removed for code cleanliness.

Suggested change

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

def test_wrapper_get_psu():
mock_logger = mock.MagicMock()
mock_psu = mock.MagicMock()

Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace should be removed for code cleanliness.

Suggested change

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

mock_logger = mock.MagicMock()
mock_psu = mock.MagicMock()
mock_psu.get_powergood_status.return_value = True

Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace should be removed for code cleanliness.

Suggested change

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

def test_get_psu_key():
mock_psu = mock.MagicMock()
mock_psu.get_name.return_value = "PSU-1"

Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace should be removed for code cleanliness.

Suggested change

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment on lines +113 to +114
Note:
If logger is None, errors and warnings encountered during execution will not be logged.
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The docstring mentions that 'logger is None' will suppress logging, but this behavior should be more prominently documented in the parameter description itself, not just in a Note section. Consider updating line 109 to: :param logger: Logger instance for error/warning messages (can be None to suppress logging)

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t think it’s necessary.

Comment on lines +186 to +187
except Exception:
pass
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Catching a bare Exception without logging or handling specific exception types makes debugging harder. The old code caught NotImplementedError and IndexError separately. Consider at minimum adding a comment explaining why all exceptions are silently ignored here, or restore the specific exception handling for clarity.

Suggested change
except Exception:
pass
except NotImplementedError:
pass
except IndexError:
pass
except Exception as e:
# Unexpected exception; log if logger is available, else silently ignore
# (logger is None here, so we cannot log)
pass

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t think it’s necessary.

judyjoseph
judyjoseph previously approved these changes Nov 11, 2025
Copy link
Contributor

@judyjoseph judyjoseph left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, please take care of general comments above

Signed-off-by: Lin Jin <[email protected]>
@mssonicbld
Copy link
Collaborator

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@LinJin23 LinJin23 requested review from liamkearney-msft and removed request for gregoryboudreau November 13, 2025 23:59
@LinJin23
Copy link
Contributor Author

Hi @liamkearney-msft, could you please help review?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants