Skip to content

Conversation

@LinJin23
Copy link

@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
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
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
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
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
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).

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.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

except Exception as e:
self.log_error("Failed to load psuutil: %s" % (str(e)), True)
sys.exit(PSUUTIL_LOAD_ERROR)
self.log_warning("Failed to load psuutil: %s" % (str(e)), True)
Copy link

Copilot AI Oct 10, 2025

Choose a reason for hiding this comment

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

The log_warning method is being called with a second parameter True, but logger methods typically don't take a boolean parameter for console output. This could cause runtime errors if the logger doesn't support this parameter pattern.

Suggested change
self.log_warning("Failed to load psuutil: %s" % (str(e)), True)
self.log_warning("Failed to load psuutil: %s" % (str(e)))

Copilot uses AI. Check for mistakes.
Copy link
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).

@LinJin23 LinJin23 requested a review from Copilot October 10, 2025 15:21
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.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

def _wrapper_get_psu_presence(psu_index):
def _wrapper_get_psu(logger, psu_index):
"""
Get PSU object from platform chassis
Copy link

Copilot AI Oct 10, 2025

Choose a reason for hiding this comment

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

The docstring is missing the logger parameter description. Add ':param logger: Logger instance for error/warning messages' to document the logger parameter.

Suggested change
Get PSU object from platform chassis
Get PSU object from platform chassis
:param logger: Logger instance for error/warning messages

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

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

@LinJin23 Pls fix this.

Copy link
Author

Choose a reason for hiding this comment

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

done

self.log_error("Failed to load psuutil: %s" % (str(e)), True)
sys.exit(PSUUTIL_LOAD_ERROR)
self.log_warning("Failed to load psuutil: %s" % (str(e)))
# Don't expect the PSUD to exit just because psuutil is not available
Copy link

Copilot AI Oct 10, 2025

Choose a reason for hiding this comment

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

There's a grammatical error in the comment. It should be 'Don't expect PSUD to exit' instead of 'Don't expect the PSUD to exit'.

Suggested change
# Don't expect the PSUD to exit just because psuutil is not available
# Don't expect PSUD to exit just because psuutil is not available

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

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

This line has been removed.

@vvolam vvolam requested a review from Copilot October 14, 2025 18:19
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 3 comments.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

return platform_psuutil.get_num_psus()
if platform_psuutil is not None:
return platform_psuutil.get_num_psus()
return 0
Copy link

Copilot AI Oct 14, 2025

Choose a reason for hiding this comment

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

The function should maintain consistent fallback behavior. When platform_psuutil is None, returning 0 may not accurately represent the actual number of PSUs on the system. Consider returning a default value that makes sense for the platform or raising an appropriate exception.

Suggested change
return 0
raise RuntimeError("Unable to determine number of PSUs: neither platform_chassis nor platform_psuutil is available")

Copilot uses AI. Check for mistakes.
except NotImplementedError:
pass
if platform_psuutil is not None:
return platform_psuutil.get_psu_presence(psu_index)
Copy link

Copilot AI Oct 14, 2025

Choose a reason for hiding this comment

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

The fallback logic should handle potential exceptions from platform_psuutil.get_psu_presence(). Consider wrapping this call in a try-except block to prevent unhandled exceptions from propagating up.

Suggested change
return platform_psuutil.get_psu_presence(psu_index)
try:
return platform_psuutil.get_psu_presence(psu_index)
except Exception as e:
if logger:
logger.log_error("Exception in platform_psuutil.get_psu_presence({}): {}".format(psu_index, str(e)))
return False

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

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

Please wrap around this exception and log a warning message if it is not implemented.

Copy link
Author

Choose a reason for hiding this comment

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

done

except NotImplementedError:
pass
if platform_psuutil is not None:
return platform_psuutil.get_psu_status(psu_index)
Copy link

Copilot AI Oct 14, 2025

Choose a reason for hiding this comment

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

The fallback logic should handle potential exceptions from platform_psuutil.get_psu_status(). Consider wrapping this call in a try-except block to prevent unhandled exceptions from propagating up.

Suggested change
return platform_psuutil.get_psu_status(psu_index)
try:
return platform_psuutil.get_psu_status(psu_index)
except Exception as e:
if logger:
logger.log_error("Exception in platform_psuutil.get_psu_status({}): {}".format(psu_index, str(e)))
return False

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add this exception

Copy link
Author

Choose a reason for hiding this comment

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

done, and at the suggested line 152, I changed log_error to log_warning.

def _wrapper_get_psu_presence(psu_index):
def _wrapper_get_psu(logger, psu_index):
"""
Get PSU object from platform chassis
Copy link
Contributor

Choose a reason for hiding this comment

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

@LinJin23 Pls fix this.

except NotImplementedError as e:
if logger:
logger.log_warning("get_psu() not implemented by platform chassis: {}".format(str(e)))
return None
Copy link
Contributor

Choose a reason for hiding this comment

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

"return None" at line 121 is sufficient and line 116 and 120 is redundant

Copy link
Author

Choose a reason for hiding this comment

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

done

return platform_chassis.get_psu(psu_index - 1)
except NotImplementedError as e:
if logger:
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.

notice is not available, so you can leave this as warning for now.

except NotImplementedError:
pass
if platform_psuutil is not None:
return platform_psuutil.get_psu_presence(psu_index)
Copy link
Contributor

Choose a reason for hiding this comment

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

Please wrap around this exception and log a warning message if it is not implemented.

except NotImplementedError:
pass
if platform_psuutil is not None:
return platform_psuutil.get_psu_status(psu_index)
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add this exception

return platform_psuutil.get_num_psus()
if platform_psuutil is not None:
return platform_psuutil.get_num_psus()
return 0
Copy link
Contributor

Choose a reason for hiding this comment

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

Add a warning log something like, if we have to return 0

if logger:
    logger.log_warning("No PSU provider available; assuming 0 PSUs")

Copy link
Author

Choose a reason for hiding this comment

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

done

return None
except Exception as e:
if logger:
logger.log_warning("Failed to get PSU {} from platform chassis: {}".format(psu_index, 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.

This should be an error type log

Copy link
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).

@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 October 23, 2025 18:14
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.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

try:
return psu.get_name()
except NotImplementedError:
pass
Copy link

Copilot AI Oct 23, 2025

Choose a reason for hiding this comment

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

The comment explaining the IndexError exception handling was removed. This comment provided valuable context about why the exception is caught and should be preserved: 'some functionality is expectent on returning an expected key even if the psu object itself does not exist'.

Suggested change
pass
pass
# some functionality is expectent on returning an expected key even if the psu object itself does not exist

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

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

done

platform_psuutil = self.load_platform_util(PLATFORM_SPECIFIC_MODULE_NAME, PLATFORM_SPECIFIC_CLASS_NAME)
except Exception as e:
self.log_error("Failed to load psuutil: %s" % (str(e)), True)
self.log_warning("Failed to load psuutil: %s" % (str(e)))
Copy link

Copilot AI Oct 23, 2025

Choose a reason for hiding this comment

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

Logging a warning message before calling sys.exit() is contradictory. If the process is going to exit with an error code (PSUUTIL_LOAD_ERROR), this should remain as log_error(). Alternatively, if platform_psuutil being unavailable is truly non-fatal as the PR description suggests, the sys.exit() call should be removed.

Suggested change
self.log_warning("Failed to load psuutil: %s" % (str(e)))
self.log_error("Failed to load psuutil: %s" % (str(e)))

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

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

done, revert to original logic

@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 October 24, 2025 00:28
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.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines +108 to +111
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 Oct 24, 2025

Choose a reason for hiding this comment

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

The docstring should clarify that logger can be None and that when None is passed, errors/warnings won't be logged. This is an important behavior detail for callers of this function.

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.
:param logger: Logger instance for error/warning messages. Can be None; if None is passed, errors and warnings will not be logged.
:param psu_index: PSU index (1-based)
:return: PSU object if available, None otherwise
Note:
If logger is None, errors and warnings encountered during execution will not be logged.

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

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

done

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 October 24, 2025 00:37
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 no new comments.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

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