Skip to content
Closed
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
4 changes: 4 additions & 0 deletions .github/workflows/distro_image_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ jobs:
- name: Run fboss-image build
run: ./fboss-image/distro_cli/fboss-image build fboss-image/from_source.json

- name: Run distro_cli tests
run: |
docker exec ${USER}-fboss-image-builder ctest -R distro_cli -V

- name: Cleanup
if: always()
run: |
Expand Down
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1154,3 +1154,6 @@ if (GITHUB_ACTIONS_BUILD)
fsdb_all_services
)
endif()

# FBOSS Image Builder distro_cli tests
include(cmake/FbossImageDistroCliTests.cmake)
36 changes: 36 additions & 0 deletions cmake/FbossImageDistroCliTests.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# CMake to build and test fboss-image/distro_cli

# In general, libraries and binaries in fboss/foo/bar are built by
# cmake/FooBar.cmake

include(FBPythonBinary)

file(GLOB DISTRO_CLI_TEST_SOURCES
"fboss-image/distro_cli/tests/*_test.py"
)

file(GLOB DISTRO_CLI_TEST_HELPERS
"fboss-image/distro_cli/tests/test_helpers.py"
)

file(GLOB_RECURSE DISTRO_CLI_LIB_SOURCES
"fboss-image/distro_cli/builder/*.py"
"fboss-image/distro_cli/cmds/*.py"
"fboss-image/distro_cli/lib/*.py"
"fboss-image/distro_cli/tools/*.py"
)

file(COPY "fboss-image/distro_cli/tests/data" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/fboss-image/distro_cli/tests")

add_fb_python_unittest(
distro_cli_tests
BASE_DIR "fboss-image"
SOURCES
${DISTRO_CLI_TEST_SOURCES}
${DISTRO_CLI_TEST_HELPERS}
${DISTRO_CLI_LIB_SOURCES}
ENV
"PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}/fboss-image/distro_cli"
)

install_fb_python_executable(distro_cli_tests)
10 changes: 10 additions & 0 deletions fboss-image/distro_cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,16 @@ python3 -m unittest discover -s tests -p '*_test.py'
python3 -m unittest tests.cli_test
```

#### With CMake

```bash
# Build and run all tests
cmake --build . --target distro_cli_tests

# Run via CTest
ctest -R distro_cli -V
```

### Linting

```bash
Expand Down
11 changes: 11 additions & 0 deletions fboss-image/distro_cli/lib/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright (c) 2004-present, Facebook, Inc.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree. An additional grant
# of patent rights can be found in the PATENTS file in the same directory.

"""Constants for FBOSS image builder."""

# Docker image names
FBOSS_BUILDER_IMAGE = "fboss_builder"
57 changes: 57 additions & 0 deletions fboss-image/distro_cli/lib/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Copyright (c) 2004-present, Facebook, Inc.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree. An additional grant
# of patent rights can be found in the PATENTS file in the same directory.

"""Exception definitions for FBOSS image builder."""


class FbossImageError(Exception):
"""Base exception for all fboss-image errors.

All custom exceptions in the fboss-image tool should inherit from this.
This allows the top-level CLI handler to catch and format errors appropriately
before returning a non-zero exit code.
"""


class BuildError(FbossImageError):
"""Build command failed.

Raised when a component build fails, including:
- Build script/command not found
- Build process returned non-zero exit code
- Build output validation failed
"""


class ManifestError(FbossImageError):
"""Manifest parsing or validation failed.

Raised when:
- Manifest file not found or invalid JSON
- Required fields missing
- Invalid manifest structure
"""


class ArtifactError(FbossImageError):
"""Artifact operation failed.

Raised when:
- Expected artifact not found after build
- Artifact download failed
- Artifact cache operation failed
"""


class ComponentError(FbossImageError):
"""Component-specific error.

Raised when:
- Component not found in manifest
- Component configuration invalid
- Component builder not implemented
"""
6 changes: 6 additions & 0 deletions fboss-image/distro_cli/lib/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ def has_component(self, component: str) -> bool:
"""Check if component is present in manifest."""
return component in self.data

def get_component(self, component: str) -> dict | None:
"""Return component data in manifest."""
if component not in self.data:
return None
return self.data[component]

def resolve_path(self, path: str) -> Path:
"""Resolve a path relative to the manifest file."""
if path.startswith("http://") or path.startswith("https://"):
Expand Down
35 changes: 35 additions & 0 deletions fboss-image/distro_cli/lib/paths.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Copyright (c) 2004-present, Facebook, Inc.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree. An additional grant
# of patent rights can be found in the PATENTS file in the same directory.

"""Path resolution utilities for FBOSS image builder."""

from pathlib import Path


def get_root_dir() -> Path:
"""Find the root directory containing fboss-image

This works by walking up from the current file until we find
the fboss-image directory, then going up one more level.

Returns:
Path to root directory

Raises:
RuntimeError: If the root directory cannot be determined
"""
current = Path(__file__).resolve()

# Walk up the directory tree looking for fboss-image
for parent in current.parents:
if (parent / "fboss-image").is_dir():
return parent

raise RuntimeError(
f"Could not find root from {current}. "
"Expected to find 'fboss-image' directory in parent path."
)
29 changes: 29 additions & 0 deletions fboss-image/distro_cli/tests/data/dev_image.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"distribution_formats": {
"onie": "FBOSS-k6.4.3.bin",
"usb": "FBOSS-k6.4.3.iso"
},
"kernel": {
"download": "https://artifact.github.com/nexthop-ai/fboss/fboss-oss_kernel_v6.4.3.tar"
},
"other_dependencies": [
{"download": "https://artifact.github.com/nexthop-ai/fsdb/fsdb.rpm"},
{"download": "file:vendor_debug_tools/tools.rpm"}
],
"fboss-platform-stack": {
"execute": ["fboss/fboss/oss/scripts/build.py", "platformstack"]
},
"bsps": [
{"execute": ["vendor_bsp/build.make"]},
{"execute": ["fboss/oss/reference_bsp/build.py"]}
],
"sai": {
"execute": ["fboss_brcm_sai/build.sh"]
},
"fboss-forwarding-stack": {
"execute": ["fboss/fboss/oss/scripts/build.py", "forwardingstack"]
},
"image_build_hooks": {
"after_pkgs": "additional_os_pkgs.xml"
}
}
13 changes: 3 additions & 10 deletions fboss-image/distro_cli/tests/manifest_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,19 @@
"""

import json
import sys
import tempfile
import unittest
from pathlib import Path

# Add parent directory to path to import the modules
test_dir = Path(__file__).parent
cli_dir = test_dir.parent
sys.path.insert(0, str(cli_dir))

from lib.manifest import ImageManifest
from distro_cli.lib.manifest import ImageManifest


class TestImageManifest(unittest.TestCase):
"""Test ImageManifest class"""

def setUp(self):
"""Use the test manifest from the tests directory"""
self.test_dir = Path(__file__).parent
self.test_dir = Path(__file__).parent / "data"
self.manifest_path = self.test_dir / "dev_image.json"

# Load the manifest data for validation
Expand Down Expand Up @@ -86,8 +80,7 @@ def test_resolve_path_relative(self):
resolved = manifest.resolve_path("vendor_bsp/build.make")

# Check that the path ends with the expected relative path
# (works in both normal and Bazel sandbox environments)
self.assertTrue(str(resolved).endswith("tests/vendor_bsp/build.make"))
self.assertTrue(str(resolved).endswith("tests/data/vendor_bsp/build.make"))
self.assertTrue(resolved.is_absolute())

def test_resolve_path_url(self):
Expand Down
51 changes: 51 additions & 0 deletions fboss-image/kernel/configs/fboss-local-overrides.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# FBOSS Local Configuration Overrides
#
# Copyright (c) 2004-present, Facebook, Inc.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree. An additional grant
# of patent rights can be found in the PATENTS file in the same directory.
#
# This file contains local overrides to the Meta fboss-reference.config
# organized by common settings and kernel version-specific settings

# Common overrides that apply to all kernel versions
# Add config lines here
common_overrides: |
# These changes disable settings in Meta reference config that don't exist in standard linux source
CONFIG_BOOT_CONFIG_EMBED_FILE=""
CONFIG_SYSTEM_TRUSTED_KEYS=""

# Drivers for Golden Eagle platform
CONFIG_EEPROM_AT24=m
CONFIG_SENSORS_TMP464=m
CONFIG_SENSORS_LM90=m
CONFIG_SENSORS_PMBUS=m
CONFIG_SENSORS_ADM1266=m
CONFIG_SENSORS_ISL68137=m
CONFIG_AD525X_DPOT=m
CONFIG_AD525X_DPOT_I2C=m
CONFIG_NET_VENDOR_AMD=y
CONFIG_AMD_XGBE=m
CONFIG_AMD_XGBE_DCB=y
CONFIG_AMD_XGBE_HAVE_ECC=y
CONFIG_X86_AMD_PLATFORM_DEVICE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_I2C_DESIGNWARE_PCI=y
CONFIG_ACPI_SPCR_TABLE=y
CONFIG_SERIAL_8250_DW=m
CONFIG_SERIAL_8250_DWLIB=m
CONFIG_SERIAL_8250_PNP=y


# Kernel version overrides
# Add kernel version as key, then add config lines in the value
kernel_version_overrides:
"6.4.3": |
# Specific overrides for kernel 6.4.3
# Add any 6.4.3-specific config lines here

"6.11.1": |
# Specific overrides for kernel 6.11.1
# Add any 6.11.1-specific config lines here
Loading