-
Notifications
You must be signed in to change notification settings - Fork 16
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
Add Snap Strategy #306
Add Snap Strategy #306
Changes from all commits
7d9f44e
021a62e
1b4a250
b06e56e
7ce2ce1
855a963
a58b70c
5fe7a2c
a607856
88f7f09
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -18,6 +18,7 @@ | |||||||||||||||||
import requests | ||||||||||||||||||
import urllib3 | ||||||||||||||||||
from charms.operator_libs_linux.v0 import apt | ||||||||||||||||||
from charms.operator_libs_linux.v2 import snap | ||||||||||||||||||
from ops.model import ModelError, Resources | ||||||||||||||||||
|
||||||||||||||||||
import apt_helpers | ||||||||||||||||||
|
@@ -175,6 +176,41 @@ def remove(self) -> None: | |||||||||||||||||
# the remove option. | ||||||||||||||||||
|
||||||||||||||||||
|
||||||||||||||||||
class SnapStrategy(StrategyABC): | ||||||||||||||||||
"""Snap strategy class.""" | ||||||||||||||||||
|
||||||||||||||||||
def __init__(self, tool: HWTool, channel: str): | ||||||||||||||||||
"""Snap strategy constructor.""" | ||||||||||||||||||
self._name = tool | ||||||||||||||||||
self.snap_name = tool.value | ||||||||||||||||||
self.channel = channel | ||||||||||||||||||
self.snap_client = snap.SnapCache()[tool.value] | ||||||||||||||||||
|
||||||||||||||||||
def install(self) -> None: | ||||||||||||||||||
"""Install the snap from a channel.""" | ||||||||||||||||||
try: | ||||||||||||||||||
snap.add(self.snap_name, channel=self.channel) | ||||||||||||||||||
# using the snap.SnapError will result into: | ||||||||||||||||||
# TypeError: catching classes that do not inherit from BaseException is not allowed | ||||||||||||||||||
except Exception as err: # pylint: disable=broad-except | ||||||||||||||||||
logger.error( | ||||||||||||||||||
"Failed to install %s from channel: %s: %s", self.snap_name, self.channel, err | ||||||||||||||||||
) | ||||||||||||||||||
Comment on lines
+196
to
+198
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This logs an error to the charm log, but that's silent to the user - can we bubble this error up to the charm status? How do the other exporters handle installation failures? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good found Samuel! Please follow the current error handling design here. hardware-observer-operator/src/hw_tools.py Lines 701 to 708 in d420c63
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Forgot to re-raise the error. Thanks |
||||||||||||||||||
raise err | ||||||||||||||||||
|
||||||||||||||||||
logger.info("Installed %s from channel: %s", self.snap_name, self.channel) | ||||||||||||||||||
# enable services because some might be disabled by default | ||||||||||||||||||
self.snap_client.start(list(self.snap_client.services.keys()), enable=True) | ||||||||||||||||||
|
||||||||||||||||||
def remove(self) -> None: | ||||||||||||||||||
"""Remove the snap.""" | ||||||||||||||||||
snap.remove([self.snap_name]) | ||||||||||||||||||
|
||||||||||||||||||
def check(self) -> bool: | ||||||||||||||||||
"""Check if all services are active.""" | ||||||||||||||||||
return all(service.get("active", False) for service in self.snap_client.services.values()) | ||||||||||||||||||
|
||||||||||||||||||
|
||||||||||||||||||
class TPRStrategyABC(StrategyABC, metaclass=ABCMeta): | ||||||||||||||||||
"""Third party resource strategy class.""" | ||||||||||||||||||
|
||||||||||||||||||
|
@@ -689,20 +725,20 @@ def install(self, resources: Resources, hw_available: Set[HWTool]) -> Tuple[bool | |||||||||||||||||
if strategy.name not in hw_available: | ||||||||||||||||||
continue | ||||||||||||||||||
try: | ||||||||||||||||||
# TPRStrategy | ||||||||||||||||||
if isinstance(strategy, TPRStrategyABC): | ||||||||||||||||||
path = fetch_tools.get(strategy.name) # pylint: disable=W0212 | ||||||||||||||||||
if path: | ||||||||||||||||||
strategy.install(path) | ||||||||||||||||||
# APTStrategy | ||||||||||||||||||
elif isinstance(strategy, APTStrategyABC): | ||||||||||||||||||
|
||||||||||||||||||
elif isinstance(strategy, (APTStrategyABC, SnapStrategy)): | ||||||||||||||||||
chanchiwai-ray marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||
strategy.install() # pylint: disable=E1120 | ||||||||||||||||||
logger.info("Strategy %s install success", strategy) | ||||||||||||||||||
except ( | ||||||||||||||||||
ResourceFileSizeZeroError, | ||||||||||||||||||
OSError, | ||||||||||||||||||
apt.PackageError, | ||||||||||||||||||
ResourceChecksumError, | ||||||||||||||||||
snap.SnapError, | ||||||||||||||||||
) as e: | ||||||||||||||||||
logger.warning("Strategy %s install fail: %s", strategy, e) | ||||||||||||||||||
fail_strategies.append(strategy.name) | ||||||||||||||||||
|
@@ -717,7 +753,7 @@ def remove(self, resources: Resources, hw_available: Set[HWTool]) -> None: | |||||||||||||||||
for strategy in self.strategies: | ||||||||||||||||||
if strategy.name not in hw_available: | ||||||||||||||||||
continue | ||||||||||||||||||
if isinstance(strategy, (TPRStrategyABC, APTStrategyABC)): | ||||||||||||||||||
if isinstance(strategy, (TPRStrategyABC, APTStrategyABC, SnapStrategy)): | ||||||||||||||||||
strategy.remove() | ||||||||||||||||||
logger.info("Strategy %s remove success", strategy) | ||||||||||||||||||
|
||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion:
I kind of prefer code like this:
install
functionSo the (dis)advantage are:
Chance to use snap resource in the futureHWToolHelper.install
function. Other design won't be broken.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Different snaps will have different channels to install from. I don't see how passing a single channel on HWToolHelper can solve this. I think it would be very strange to have one charm config for channel to rule on all snaps channels.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
while I agree that we should remove the constructor for consistency with the other strategies, I don't quite get why it would be preferable to move complexity to the install function, as that requires the caller to have deeper knowledge about how each strategy works and adds extra conditionals to
HWToolHelper.install
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need a protocol to pass all the required material, resources, configuration, and hardware detect result, for the strategies.
So
install
function is the protocol right now. If we break this rule then the ISP(interface-segregation principles) will be broken then you have to find a tricky/hacky way to import those material into the strategies.(I am open to any way to refactor the protocol we have now, but it's a refactor so it shouldn't happen on this PR)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a pseudocode code, so pass the configuration you want.