Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace redfish discover method #69

Merged
merged 4 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions src/hw_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@
from abc import ABCMeta, abstractmethod
from pathlib import Path

import redfish
from charms.operator_libs_linux.v0 import apt
from ops.model import ModelError, Resources
from redfish import redfish_client
from redfish.rest.v1 import InvalidCredentialsError, RetriesExhaustedError, SessionCreationError

from config import SNAP_COMMON, TOOLS_DIR, TPR_RESOURCES, HWTool, StorageVendor, SystemVendor
from hardware import SUPPORTED_STORAGES, lshw
from hardware import SUPPORTED_STORAGES, get_bmc_address, lshw
from keys import HP_KEYS

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -299,6 +300,26 @@ def raid_hw_verifier() -> t.List[HWTool]:
return list(tools)


def redfish_available() -> bool:
"""Check if redfish service is available."""
bmc_address = get_bmc_address()
host = f"https://{bmc_address}"
try:
# credentials can be empty because we're only checking if redfish service is accessible
redfish_obj = redfish_client(base_url=host, username="", password="")
redfish_obj.login(auth="session")
except RetriesExhaustedError: # redfish not available
result = False
except (SessionCreationError, InvalidCredentialsError):
# redfish available, wrong credentials or not able to create a session
result = True
else: # login succeeded with empty credentials
result = True
redfish_obj.logout()

return result


def bmc_hw_verifier() -> t.List[HWTool]:
"""Verify if the ipmi is available on the machine.

Expand All @@ -314,8 +335,7 @@ def bmc_hw_verifier() -> t.List[HWTool]:
logger.info("IPMI is not available")

# Check RedFish available
services = redfish.discover_ssdp()
if len(services):
if redfish_available():
tools.append(HWTool.REDFISH)
else:
logger.info("Redfish is not available")
Expand Down
5 changes: 5 additions & 0 deletions tests/functional/test_charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,11 @@ async def test_20_on_remove_event(self, app, sync_helper, ops_test):
)
principal_unit = ops_test.model.applications[PRINCIPAL_APP_NAME].units[0]

# Wait for cleanup activities to finish
await ops_test.model.block_until(
lambda: ops_test.model.applications[APP_NAME].status == "unknown"
)

cmd = "ls /etc/hardware-exporter-config.yaml"
results = await sync_helper.run_command_on_unit(ops_test, principal_unit.name, cmd)
assert results.get("return-code") > 0
Expand Down
58 changes: 53 additions & 5 deletions tests/unit/test_hw_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@
from hw_tools import (
APTStrategyABC,
HWToolHelper,
InvalidCredentialsError,
IPMIStrategy,
PercCLIStrategy,
RetriesExhaustedError,
SAS2IRCUStrategy,
SAS3IRCUStrategy,
SessionCreationError,
SSACLIStrategy,
StorCLIStrategy,
StrategyABC,
Expand All @@ -29,6 +32,7 @@
install_deb,
make_executable,
raid_hw_verifier,
redfish_available,
remove_deb,
symlink,
)
Expand Down Expand Up @@ -550,24 +554,68 @@ def test_raid_hw_verifier(mock_lshw, lshw_output, lshw_storage_output, expect):


class TestIPMIHWVerifier(unittest.TestCase):
@mock.patch("hw_tools.redfish.discover_ssdp", return_value=[1])
@mock.patch("hw_tools.redfish_client")
@mock.patch("hw_tools.get_bmc_address", return_value="1.2.3.4")
def test_redfish_not_available(self, mock_bmc_address, mock_redfish_client):
mock_redfish_obj = mock.Mock()
mock_redfish_client.return_value = mock_redfish_obj
mock_redfish_obj.login.side_effect = RetriesExhaustedError()

result = redfish_available()

self.assertEqual(result, False)
mock_bmc_address.assert_called_once()
mock_redfish_client.assert_called_once()
mock_redfish_obj.login.assert_called_once()

@mock.patch("hw_tools.redfish_client")
@mock.patch("hw_tools.get_bmc_address", return_value="1.2.3.4")
def test_redfish_available(self, mock_bmc_address, mock_redfish_client):
mock_redfish_obj = mock.Mock()
mock_redfish_client.return_value = mock_redfish_obj

for exc in [SessionCreationError, InvalidCredentialsError]:
mock_redfish_obj.login.side_effect = exc
result = redfish_available()
self.assertEqual(result, True)

mock_bmc_address.assert_called()
mock_redfish_client.assert_called()
mock_redfish_obj.login.assert_called()

@mock.patch("hw_tools.redfish_client")
@mock.patch("hw_tools.get_bmc_address", return_value="1.2.3.4")
def test_redfish_available_and_login_success(self, mock_bmc_address, mock_redfish_client):
mock_redfish_obj = mock.Mock()
mock_redfish_client.return_value = mock_redfish_obj

result = redfish_available()

self.assertEqual(result, True)

mock_bmc_address.assert_called_once()
mock_redfish_client.assert_called_once()
mock_redfish_obj.login.assert_called_once()
mock_redfish_obj.logout.assert_called_once()

@mock.patch("hw_tools.redfish_available", return_value=True)
@mock.patch("hw_tools.subprocess")
@mock.patch("hw_tools.apt")
def test_bmc_hw_verifier(self, mock_apt, mock_subprocess, mock_redfish_discover_ssdp):
def test_bmc_hw_verifier(self, mock_apt, mock_subprocess, mock_redfish_available):
output = bmc_hw_verifier()
mock_apt.add_package.assert_called_with("ipmitool", update_cache=False)
mock_subprocess.check_output.assert_called_with("ipmitool lan print".split())
self.assertCountEqual(output, [HWTool.IPMI, HWTool.REDFISH])
mock_redfish_discover_ssdp.assert_called()
mock_redfish_available.assert_called()

@mock.patch("hw_tools.redfish.discover_ssdp", return_value=[])
@mock.patch("hw_tools.redfish_available", return_value=False)
@mock.patch(
"hw_tools.subprocess.check_output",
side_effect=subprocess.CalledProcessError(-1, "cmd"),
)
@mock.patch("hw_tools.apt")
def test_bmc_hw_verifier_error_handling(
self, mock_apt, mock_check_output, mock_redfish_discover_ssdp
self, mock_apt, mock_check_output, mock_redfish_available
):
output = bmc_hw_verifier()
mock_apt.add_package.assert_called_with("ipmitool", update_cache=False)
Expand Down
Loading