summaryrefslogtreecommitdiff
path: root/robusta_krr
diff options
context:
space:
mode:
authorPavel Zhukov <33721692+LeaveMyYard@users.noreply.github.com>2024-04-02 14:56:13 +0300
committerGitHub <noreply@github.com>2024-04-02 14:56:13 +0300
commitcaa564ce2371f3bc478cc1916169d97291ffeac6 (patch)
tree2e2316d715d8019a19094e0d6e5cdc7d224c7bd8 /robusta_krr
parent242feeccaf18f8b8b2ff08d685937e5037749603 (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.py35
-rw-r--r--robusta_krr/utils/intro.py42
-rw-r--r--robusta_krr/utils/logo.py11
-rw-r--r--robusta_krr/utils/version.py23
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)