diff options
| author | Pavel Zhukov <33721692+LeaveMyYard@users.noreply.github.com> | 2024-04-02 14:56:13 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-02 14:56:13 +0300 |
| commit | caa564ce2371f3bc478cc1916169d97291ffeac6 (patch) | |
| tree | 2e2316d715d8019a19094e0d6e5cdc7d224c7bd8 /robusta_krr | |
| parent | 242feeccaf18f8b8b2ff08d685937e5037749603 (diff) | |
Live introduction message (#239)
* Live introduction
* Add intro file into pyinstaller in CI/CD pipelines
* Do not exit if file fallback failed for some reason
* Make the intro message full colored
* Check for a newer version from github releases
* Rework intro to load the message from robusta API
* Change log of new version error to debug
* Add version query param to fetching intro message
* Fix request arg
* Remove stg from the intro link
Diffstat (limited to 'robusta_krr')
| -rw-r--r-- | robusta_krr/core/runner.py | 35 | ||||
| -rw-r--r-- | robusta_krr/utils/intro.py | 42 | ||||
| -rw-r--r-- | robusta_krr/utils/logo.py | 11 | ||||
| -rw-r--r-- | robusta_krr/utils/version.py | 23 |
4 files changed, 93 insertions, 18 deletions
diff --git a/robusta_krr/core/runner.py b/robusta_krr/core/runner.py index 25a85e8..3649b10 100644 --- a/robusta_krr/core/runner.py +++ b/robusta_krr/core/runner.py @@ -17,9 +17,9 @@ from robusta_krr.core.integrations.prometheus import ClusterNotSpecifiedExceptio from robusta_krr.core.models.config import settings from robusta_krr.core.models.objects import K8sObjectData from robusta_krr.core.models.result import ResourceAllocations, ResourceScan, ResourceType, Result, StrategyData -from robusta_krr.utils.logo import ASCII_LOGO +from robusta_krr.utils.intro import load_intro_message from robusta_krr.utils.progress_bar import ProgressBar -from robusta_krr.utils.version import get_version +from robusta_krr.utils.version import get_version, load_latest_version logger = logging.getLogger("krr") @@ -68,14 +68,35 @@ class Runner: return result - def _greet(self) -> None: + @staticmethod + def __parse_version_string(version: str) -> tuple[int, ...]: + version_trimmed = version.replace("-dev", "").replace("v", "") + return tuple(map(int, version_trimmed.split("."))) + + def __check_newer_version_available(self, current_version: str, latest_version: str) -> bool: + try: + current_version_parsed = self.__parse_version_string(current_version) + latest_version_parsed = self.__parse_version_string(latest_version) + + if current_version_parsed < latest_version_parsed: + return True + except Exception: + logger.debug("An error occurred while checking for a new version", exc_info=True) + return False + + async def _greet(self) -> None: if settings.quiet: return - custom_print(ASCII_LOGO) - custom_print(f"Running Robusta's KRR (Kubernetes Resource Recommender) {get_version()}") + current_version = get_version() + intro_message, latest_version = await asyncio.gather(load_intro_message(), load_latest_version()) + + custom_print(intro_message) + custom_print(f"\nRunning Robusta's KRR (Kubernetes Resource Recommender) {current_version}") custom_print(f"Using strategy: {self._strategy}") custom_print(f"Using formatter: {settings.format}") + if latest_version is not None and self.__check_newer_version_available(current_version, latest_version): + custom_print(f"[yellow bold]A newer version of KRR is available: {latest_version}[/yellow bold]") custom_print("") def _process_result(self, result: Result) -> None: @@ -281,9 +302,9 @@ class Runner: ), ) - async def run(self) -> int: + async def run(self) -> None: """Run the Runner. The return value is the exit code of the program.""" - self._greet() + await self._greet() try: settings.load_kubeconfig() diff --git a/robusta_krr/utils/intro.py b/robusta_krr/utils/intro.py new file mode 100644 index 0000000..c231773 --- /dev/null +++ b/robusta_krr/utils/intro.py @@ -0,0 +1,42 @@ +import requests +import asyncio +from concurrent.futures import ThreadPoolExecutor + +from .version import get_version + + +ONLINE_LINK = 'https://api.robusta.dev/krr/intro' +LOCAL_LINK = './intro.txt' +TIMEOUT = 0.5 + + +# Synchronous function to fetch intro message +def fetch_intro_message() -> str: + try: + # Attempt to get the message from the URL + response = requests.get(ONLINE_LINK, params={"version": get_version()}, timeout=TIMEOUT) + response.raise_for_status() # Raises an error for bad responses + result = response.json() + return result['message'] + except Exception as e1: + # If there's any error, fallback to local file + try: + with open(LOCAL_LINK, 'r') as file: + return file.read() + except Exception as e2: + return ( + "[red]Failed to load the intro message.\n" + f"Both from the URL: {e1.__class__.__name__} {e1}\n" + f"and the local file: {e2.__class__.__name__} {e2}\n" + "But as that is not critical, KRR will continue to run without the intro message.[/red]" + ) + + +async def load_intro_message() -> str: + loop = asyncio.get_running_loop() + # Use a ThreadPoolExecutor to run the synchronous function in a separate thread + with ThreadPoolExecutor() as pool: + return await loop.run_in_executor(pool, fetch_intro_message) + + +__all__ = ['load_intro_message'] diff --git a/robusta_krr/utils/logo.py b/robusta_krr/utils/logo.py deleted file mode 100644 index 6beb087..0000000 --- a/robusta_krr/utils/logo.py +++ /dev/null @@ -1,11 +0,0 @@ -ASCII_LOGO = r""" -[bold magenta] - _____ _ _ _ _______ _____ -| __ \ | | | | | |/ / __ \| __ \ -| |__) |___ | |__ _ _ ___| |_ __ _ | ' /| |__) | |__) | -| _ // _ \| '_ \| | | / __| __/ _` | | < | _ /| _ / -| | \ \ (_) | |_) | |_| \__ \ || (_| | | . \| | \ \| | \ \ -|_| \_\___/|_.__/ \__,_|___/\__\__,_| |_|\_\_| \_\_| \_\ -[/bold magenta] - -""" diff --git a/robusta_krr/utils/version.py b/robusta_krr/utils/version.py index 77772dd..d7b5df7 100644 --- a/robusta_krr/utils/version.py +++ b/robusta_krr/utils/version.py @@ -1,5 +1,28 @@ import robusta_krr +import requests +import asyncio +from typing import Optional +from concurrent.futures import ThreadPoolExecutor def get_version() -> str: return robusta_krr.__version__ + + +# Synchronous function to fetch the latest release version from GitHub API +def fetch_latest_version() -> Optional[str]: + url = "https://api.github.com/repos/robusta-dev/krr/releases/latest" + try: + response = requests.get(url, timeout=0.5) # 0.5 seconds timeout + response.raise_for_status() # Raises an error for bad responses + data = response.json() + return data.get("tag_name") # Returns the tag name of the latest release + except Exception: + return None + + +async def load_latest_version() -> Optional[str]: + loop = asyncio.get_running_loop() + # Run the synchronous function in a separate thread + with ThreadPoolExecutor() as pool: + return await loop.run_in_executor(pool, fetch_latest_version) |
