From 6fecc06a6f7bc4fc427b6a96931e8a776df7e901 Mon Sep 17 00:00:00 2001 From: Benny Zlotnik Date: Wed, 24 Jun 2026 20:19:08 +0300 Subject: [PATCH] fix: serve fls binary from exporter instead of downloading from GitHub Serve the fls binary already installed in the exporter container via its HTTP server, Users can still override with --fls-version or --fls-binary-url. This would help to avoid scenarios in which github is not available for example Signed-off-by: Benny Zlotnik Assisted-by: claude-opus-4.6 --- python/Containerfile | 9 ++++++++- .../jumpstarter_driver_flashers/client.py | 13 +++++++++++-- .../jumpstarter_driver_flashers/driver.py | 10 ++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/python/Containerfile b/python/Containerfile index ea9bb606b..ad80b7edd 100644 --- a/python/Containerfile +++ b/python/Containerfile @@ -20,7 +20,14 @@ RUN ARCH=$(uname -m) && \ TEMP_FILE="/tmp/fls-${ARCH}-${SUFFIX}.tmp" && \ curl -fsSL "${URL}" -o "${TEMP_FILE}" && \ mv "${TEMP_FILE}" /usr/local/bin/fls && \ - chmod +x /usr/local/bin/fls + chmod +x /usr/local/bin/fls && \ + if [ "$ARCH" != "aarch64" ]; then \ + curl -fsSL "https://github.com/jumpstarter-dev/fls/releases/download/${FLS_VERSION}/fls-aarch64-linux-musl" \ + -o /usr/local/bin/fls-aarch64 && \ + chmod +x /usr/local/bin/fls-aarch64; \ + else \ + ln -s /usr/local/bin/fls /usr/local/bin/fls-aarch64; \ + fi FROM builder AS wheels ADD . /src diff --git a/python/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/client.py b/python/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/client.py index 49c6c0248..05b770c7e 100644 --- a/python/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/client.py +++ b/python/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/client.py @@ -39,7 +39,7 @@ from jumpstarter.client.core import DriverMethodNotImplemented from jumpstarter.client.decorators import driver_click_group -from jumpstarter.common.exceptions import ArgumentError, JumpstarterException +from jumpstarter.common.exceptions import ArgumentError, ConfigurationError, JumpstarterException from jumpstarter.common.fls import get_fls_github_url @@ -306,6 +306,11 @@ def _categorize_exception(self, exception: Exception) -> FlashRetryableError | F if isinstance(exception, CancelledError): return FlashNonRetryableError("Operation cancelled") + # ConfigurationError is deterministic and should not be retried + config_error = self._find_exception_in_chain(exception, ConfigurationError) + if config_error is not None: + return FlashNonRetryableError(str(config_error)) + # Unknown exception - log full stack trace and wrap as retryable self.logger.exception( f"Unknown exception encountered during flash operation, treating as retryable: " @@ -701,9 +706,13 @@ def _flash_with_fls( self._download_fls_binary(console, prompt, fls_binary_url, f"Failed to download FLS from {fls_binary_url}") elif fls_version != "": self.logger.info(f"Downloading FLS version {fls_version} from GitHub releases") - # Download fls binary to the target device (always aarch64 for target devices) fls_url = get_fls_github_url(fls_version, arch="aarch64") self._download_fls_binary(console, prompt, fls_url, f"Failed to download FLS from {fls_url}") + else: + self.logger.info("Serving FLS binary from exporter container") + self.call("setup_fls_binary") + fls_url = self.http.get_url() + "/fls" + self._download_fls_binary(console, prompt, fls_url, "Failed to download FLS from exporter") # Flash the image creds_file = None diff --git a/python/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/driver.py b/python/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/driver.py index a918cc4dd..30dacd927 100644 --- a/python/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/driver.py +++ b/python/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/driver.py @@ -78,6 +78,16 @@ async def get_cacert(self) -> str | None: with open(self.cacert) as f: return f.read() + @export + async def setup_fls_binary(self): + """Copy local fls binary to HTTP server root for DUT download""" + fls_path = Path("/usr/local/bin/fls-aarch64") + if not fls_path.exists(): + fls_path = Path("/usr/local/bin/fls") + if not fls_path.exists(): + raise ConfigurationError("fls binary not found at /usr/local/bin/fls-aarch64 or /usr/local/bin/fls") + await self.http.storage.copy_exporter_file(fls_path, "fls") + @export async def setup_flasher_bundle(self, force_flash_bundle: str | None = None): """Setup flasher bundle