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

feat: third party resource checksum #80

Merged
merged 8 commits into from
Nov 2, 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
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
cosl
distro
ops >= 2.2.0
jinja2
redfish
Expand Down
235 changes: 235 additions & 0 deletions src/checksum.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
# Copyright 2023 Canonical Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# For further info, check https://github.com/canonical/charmcraft
"""Checksum definition, check functions and related utils."""
import hashlib
import logging
import typing as t
from dataclasses import dataclass, field
from pathlib import Path

from os_platform import Architecture, UbuntuSeries, get_os_platform

logger = logging.getLogger(__name__)


class ResourceChecksumError(Exception):
"""Raise if checksum does not match."""


@dataclass
class ToolVersionInfo:
"""Tool version information for checksum comparison."""

version: str
supported_architectures: t.List[Architecture]
sha256_checksum: str
link: t.Optional[str] = None
desc: str = ""
support_all_series: bool = False
supported_series: t.List[UbuntuSeries] = field(default_factory=lambda: [])


STORCLI_VERSION_INFOS: t.List[ToolVersionInfo] = [
Pjack marked this conversation as resolved.
Show resolved Hide resolved
ToolVersionInfo(
version="007.2705.0000.0000",
support_all_series=True,
supported_architectures=[Architecture.X86_64],
link="https://docs.broadcom.com/docs/1232743397",
desc="MR 7.27",
sha256_checksum="45ff0d3c7fc8b77f64de7de7b3698307971546a6be00982934a19ee44f5d91bb",
),
ToolVersionInfo(
version="007.2612.0000.0000",
support_all_series=True,
supported_architectures=[Architecture.X86_64],
link="https://docs.broadcom.com/docs/1232743291",
desc="MR 7.26",
sha256_checksum="5ab2c1b608934626817828ced85e4aeaee7dc97fbd6e3f4fed00b13a95a06e14",
),
ToolVersionInfo(
version="007.2508.0000.0000",
support_all_series=True,
supported_architectures=[Architecture.X86_64],
link="https://docs.broadcom.com/docs/1232743203",
desc="MR 7.25",
sha256_checksum="17c3f5292de6491f1388c9305ba65836730614b6defe17039b427fced2f75e0b",
),
ToolVersionInfo(
version="007.2408.0000.0000",
support_all_series=True,
supported_architectures=[Architecture.X86_64],
link="https://docs.broadcom.com/docs/1232743081",
desc="MR 7.24",
sha256_checksum="8ecf2d46e253e243c5d169adcd84f2701e52e3815913694f074e80af5a98cbab",
),
ToolVersionInfo(
version="007.2310.0000.0000",
support_all_series=True,
supported_architectures=[Architecture.X86_64],
link="https://docs.broadcom.com/docs/Unified_storcli_all_os_7.2309.0000.0000.zip",
desc="MR 7.23",
sha256_checksum="94cbef2ec2ca58700a49e646a7bded3a49ddab4646a9d5d178bc4ccb2996cb73",
),
]

PERCCLI_VERSION_INFOS: t.List[ToolVersionInfo] = [
ToolVersionInfo(
version="007.2313.0000.0000",
supported_series=[UbuntuSeries.JAMMY, UbuntuSeries.FOCAL],
supported_architectures=[Architecture.X86_64],
link="https://www.dell.com/support/home/zh-tw/drivers/driversdetails?driverid=tdghn",
desc="A14",
sha256_checksum="043f7d6235cf125072e95d748cb98f5db42965f218de30f6f72f5503a626e4e3",
),
ToolVersionInfo(
version="007.1623.0000.0000",
supported_series=[UbuntuSeries.FOCAL, UbuntuSeries.BIONIC, UbuntuSeries.XENIAL],
supported_architectures=[Architecture.X86_64],
link="https://www.dell.com/support/home/zh-tw/drivers/driversdetails?driverid=j91yg",
desc="A11",
sha256_checksum="e46d955241c932023caf63862cd9dacb2b723b7f944340efb0e5afb6a2681e9d",
),
ToolVersionInfo(
version="007.1420.0000.0000",
supported_series=[
UbuntuSeries.FOCAL,
UbuntuSeries.BIONIC,
UbuntuSeries.XENIAL,
],
supported_architectures=[Architecture.X86_64],
link="https://www.dell.com/support/home/zh-tw/drivers/driversdetails?driverid=n65f1",
desc="A10",
sha256_checksum="8a405000ea592e1d2999313ade07609a7abcfa24d1b9b35bb242bb6aff75a6be",
),
ToolVersionInfo(
version="007.1327.0000.0000",
supported_series=[UbuntuSeries.FOCAL, UbuntuSeries.BIONIC, UbuntuSeries.XENIAL],
supported_architectures=[Architecture.X86_64],
link="https://www.dell.com/support/home/zh-tw/drivers/driversdetails?driverid=d6ywp",
desc="A09",
sha256_checksum="53c8ee43808779f8263c25b3cb975d816d207659684f3c7de1df4bbd2447ead4",
),
]

SAS2IRCU_VERSION_INFOS: t.List[ToolVersionInfo] = [
Pjack marked this conversation as resolved.
Show resolved Hide resolved
ToolVersionInfo(
version="20.00.00.00",
support_all_series=True,
supported_architectures=[Architecture.X86_64],
link="https://docs.broadcom.com/docs/12351735",
desc="P20, linux_x86",
sha256_checksum="37467826d0b22aad47287efe70bb34e47f475d70e9b1b64cbd63f57607701e73",
),
ToolVersionInfo(
version="19.00.00.00",
support_all_series=True,
supported_architectures=[Architecture.X86_64],
link="https://docs.broadcom.com/docs/12351734",
desc="P19, linux_x86",
sha256_checksum="4baaec21865973c0a6da617e37850cc27512715e6ab22df18b1f67d068e5095c",
),
ToolVersionInfo(
version="18.00.00.00",
support_all_series=True,
supported_architectures=[Architecture.X86_64],
link="https://docs.broadcom.com/docs/12351733",
desc="P18, linux_x86",
sha256_checksum="b6ed72275066e80ebe9813cd15f1d019eba9daddbd9dfd8ad426da78801f15d8",
),
ToolVersionInfo(
version="17.00.00.00",
support_all_series=True,
supported_architectures=[Architecture.X86_64],
link="https://docs.broadcom.com/docs/12351732",
desc="P17, linux_x86",
sha256_checksum="07e9236b99bbe4a3ae6148f8668e1ce0331d83c2fcb0c4841d000454c6200c1f",
),
ToolVersionInfo(
version="16.00.00.00",
support_all_series=True,
supported_architectures=[Architecture.X86_64],
link="https://docs.broadcom.com/docs/12351731",
desc="P16, linux_x86",
sha256_checksum="a8653117067847042bb83e7b51f02d8f2db94e91ce95842efea0dffcb655c966",
),
]

SAS3IRCU_VERSION_INFOS: t.List[ToolVersionInfo] = [
Pjack marked this conversation as resolved.
Show resolved Hide resolved
ToolVersionInfo(
version="16.00.00.00",
support_all_series=True,
supported_architectures=[Architecture.X86_64],
link="https://docs.broadcom.com/docs/SAS3IRCU_P15.zip",
desc="P15, linux_x86",
sha256_checksum="f150eb37bb332668949a3eccf9636e0e03f874aecd17a39d586082c6be1386bd",
),
ToolVersionInfo(
version="15.00.00.00",
support_all_series=True,
supported_architectures=[Architecture.X86_64],
link="https://docs.broadcom.com/docs/SAS3IRCU_P14.zip",
desc="P14, linux_x86",
sha256_checksum="5825b90964d1950551e5ed5100ddf1141360b0acf8dd3c6ddb4fe5874d6bbabb",
),
ToolVersionInfo(
version="14.00.00.00",
support_all_series=True,
supported_architectures=[Architecture.X86_64],
link="https://docs.broadcom.com/docs/SAS3IRCU_P13.zip",
desc="P13, linux_x86",
sha256_checksum="1ce45e57efa0a2d8c5c3d61a0950ab7e950a317aff3155fc1831099e19274c32",
),
ToolVersionInfo(
version="13.00.00.00",
support_all_series=True,
supported_architectures=[Architecture.X86_64],
link="https://docs.broadcom.com/docs/SAS3IRCU_P12.zip",
desc="P12, linux_x86",
sha256_checksum="cb4010a3d2bc4f9b75859a0c599d889f9fb847e4dfc88abf74082a13b9490a59",
),
ToolVersionInfo(
version="12.00.00.00",
support_all_series=True,
supported_architectures=[Architecture.X86_64],
link="https://docs.broadcom.com/docs/SAS3IRCU_P11.zip",
desc="P11, linux_x86",
sha256_checksum="458d51b030468901fc8a207088070e6ce82db34b181d9190c8f849605f1b9b6d",
),
]


def validate_checksum(support_version_infos: t.List[ToolVersionInfo], path: Path) -> bool:
"""Validate checksum of resource file by checking with supported versions.

Returns True if resource is supported by the charm, architecture, and
checksum validation is successful.
"""
os_platform = get_os_platform()

supported_checksums = []
for info in support_version_infos:
if os_platform.machine in info.supported_architectures and (
info.support_all_series or os_platform.series in info.supported_series
):
supported_checksums.append(info.sha256_checksum)

with open(path, "rb") as f:
sha256_hash = hashlib.sha256(f.read()).hexdigest()

if sha256_hash in supported_checksums:
return True
logger.warning("Checksum validation fail, path: %s hash: %s", path, sha256_hash)
return False
2 changes: 1 addition & 1 deletion src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,5 @@ class HWTool(str, Enum):

TOOLS_DIR = Path("/usr/sbin")

# SNAP envionment
# SNAP environment
SNAP_COMMON = Path(f"/var/snap/{EXPORTER_NAME}/common")
24 changes: 24 additions & 0 deletions src/hw_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@
from redfish import redfish_client
from redfish.rest.v1 import InvalidCredentialsError, RetriesExhaustedError, SessionCreationError

from checksum import (
PERCCLI_VERSION_INFOS,
SAS2IRCU_VERSION_INFOS,
SAS3IRCU_VERSION_INFOS,
STORCLI_VERSION_INFOS,
ResourceChecksumError,
validate_checksum,
)
from config import SNAP_COMMON, TOOLS_DIR, TPR_RESOURCES, HWTool, StorageVendor, SystemVendor
from hardware import SUPPORTED_STORAGES, get_bmc_address, lshw
from keys import HP_KEYS
Expand Down Expand Up @@ -144,6 +152,8 @@ def install(self, path: Path) -> None:
"""Install storcli."""
if not check_file_size(path):
raise ResourceFileSizeZeroError(tool=self._name, path=path)
if not validate_checksum(STORCLI_VERSION_INFOS, path):
raise ResourceChecksumError
install_deb(self.name, path)
symlink(src=self.origin_path, dst=self.symlink_bin)

Expand All @@ -165,6 +175,8 @@ def install(self, path: Path) -> None:
"""Install perccli."""
if not check_file_size(path):
raise ResourceFileSizeZeroError(tool=self._name, path=path)
if not validate_checksum(PERCCLI_VERSION_INFOS, path):
raise ResourceChecksumError
install_deb(self.name, path)
symlink(src=self.origin_path, dst=self.symlink_bin)

Expand All @@ -185,6 +197,8 @@ def install(self, path: Path) -> None:
"""Install sas2ircu."""
if not check_file_size(path):
raise ResourceFileSizeZeroError(tool=self._name, path=path)
if not validate_checksum(SAS2IRCU_VERSION_INFOS, path):
raise ResourceChecksumError
make_executable(path)
symlink(src=path, dst=self.symlink_bin)

Expand All @@ -200,6 +214,15 @@ class SAS3IRCUStrategy(SAS2IRCUStrategy):
_name = HWTool.SAS3IRCU
symlink_bin = TOOLS_DIR / HWTool.SAS3IRCU.value

def install(self, path: Path) -> None:
"""Install sas3ircu."""
if not check_file_size(path):
raise ResourceFileSizeZeroError(tool=self._name, path=path)
if not validate_checksum(SAS3IRCU_VERSION_INFOS, path):
raise ResourceChecksumError
make_executable(path)
symlink(src=path, dst=self.symlink_bin)


class SSACLIStrategy(APTStrategyABC):
"""Strategy for install ssacli."""
Expand Down Expand Up @@ -444,6 +467,7 @@ def install(self, resources: Resources) -> t.Tuple[bool, str]:
ResourceFileSizeZeroError,
OSError,
apt.PackageError,
ResourceChecksumError,
) as e:
logger.warning("Strategy %s install fail: %s", strategy, e)
fail_strategies.append(strategy.name)
Expand Down
63 changes: 63 additions & 0 deletions src/os_platform.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Copyright 2023 Canonical Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# For further info, check https://github.com/canonical/charmcraft
"""Platform-related Charmcraft utilities."""
import dataclasses
import platform
import typing as t
from enum import Enum

import distro


class UbuntuSeries(str, Enum):
"""Ubuntu Series."""

NOBLE = "24.04"
JAMMY = "22.04"
Pjack marked this conversation as resolved.
Show resolved Hide resolved
FOCAL = "20.04"
BIONIC = "18.04"
XENIAL = "16.04"


class Architecture(str, Enum):
"""Host architecture."""

X86_64 = "x86_64"


@dataclasses.dataclass
class OSPlatform:
"""Description of an operating system platform."""

release: str
machine: str

@property
def series(self) -> t.Optional[UbuntuSeries]:
"""Return series base on system and release."""
for series in UbuntuSeries:
if series == self.release:
return series
return None


def get_os_platform() -> OSPlatform:
"""Determine a system/release combo for an OS using /etc/os-release if available."""
machine = platform.machine()
info = distro.info()
release = info.get("version", "")

return OSPlatform(release=release, machine=machine)
2 changes: 1 addition & 1 deletion tests/unit/test_charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def test_10_config_changed(self, mock_exporter):

@mock.patch("charm.Exporter", return_value=mock.MagicMock())
def test_11_config_changed_before_install_complete(self, mock_exporter):
"""Test: config change event is defered if charm not installed."""
"""Test: config change event is deferred if charm not installed."""
self.harness.begin()
self.harness.charm._stored.installed = False

Expand Down
Loading