ramalama icon indicating copy to clipboard operation
ramalama copied to clipboard

Artifact Pulling

Open ieaves opened this issue 2 months ago • 5 comments

There are a number of open issues related to pulling and running generic model artifacts with a number of open technical questions related to each. Among which include

  • Using podman artifact https://github.com/containers/ramalama/issues/1152
  • How to implement equivalent docker functionality for artifact pulling
  • standards compliance https://github.com/containers/ramalama/issues/1674

This PR does not attempt to address all of these question. Given the scope of the problem though, I thought having some code to look at might form a useful jumping off point to begin picking off problems one at a time.

As pertains standards, one path is to implement a system capable of identifying discrete packaging strategies (like modelpack) but so far as I'm aware docker doesn't provide equivalent functionality to podman artifact. To that end, I've taken a rough shot at a pure python implementation for oci_artifacts.

I've attached some of this code to the rlcr transport option only because I have a variety of oras packaged model artifacts (e.g. rlcr://gemma3-270m:gguf) I could test against already.

I just want to reiterate this PR is only intended to facilitate the broader conversation around artifact pulling. Would it be better to only support podman for artifact running? Are there strong opinions about package structure?

Comments and thoughts would be welcome @rhatdan @engelmi.

Summary by Sourcery

Add pure Python OCI artifact pulling support and integrate it as a fallback in the RLCR transport when standard pulls fail.

New Features:

  • Implement a new oci_artifact module to fetch OCI manifests and download blobs over HTTP with checksum verification and token authentication
  • Enable RamalamaContainerRegistry to fall back to OCI artifact pulling when conventional container pulls fail

Enhancements:

  • Track and detect cached artifact snapshots in RLCR transport, overriding exists, pull, entry model path, and mount setup accordingly

Tests:

  • Add unit tests for RLCR fallback behavior, including successful and failed artifact download scenarios
  • Add unit tests for OCI artifact download to verify manifest parsing, blob retrieval, snapshot creation, and model path resolution

ieaves avatar Oct 17 '25 23:10 ieaves

Reviewer's Guide

This PR introduces Python-based OCI artifact pulling support and integrates it as a fallback in the RLCR transport when container pulls fail, along with unit tests validating both the fallback logic and the new OCI artifact download module.

Sequence diagram for RLCR transport artifact pulling fallback

sequenceDiagram
    participant User
    participant RLCRTransport
    participant OCI
    participant OCIArtifactModule
    User->>RLCRTransport: pull(args)
    RLCRTransport->>OCI: pull(args)
    alt OCI pull fails
        RLCRTransport->>OCIArtifactModule: attempt_artifact_pull(args)
        OCIArtifactModule->>OCIArtifactModule: download_oci_artifact(...)
        OCIArtifactModule-->>RLCRTransport: success/failure
        RLCRTransport-->>User: result
    else OCI pull succeeds
        OCI-->>RLCRTransport: success
        RLCRTransport-->>User: result
    end

Class diagram for new and updated RLCR and OCI artifact classes

classDiagram
    class RamalamaContainerRegistry {
        - _artifact_downloaded: bool
        + pull(args)
        + _attempt_artifact_pull(args) bool
        + _has_artifact_snapshot() bool
        + exists() bool
        + _get_entry_model_path(*args, **kwargs) str
        + setup_mounts(args)
    }
    RamalamaContainerRegistry --|> OCI

    class OCIRegistryClient {
        - registry: str
        - repository: str
        - reference: str
        - base_url: str
        - _bearer_token: str | None
        + get_manifest() (dict, str)
        + download_blob(digest, dest_path)
        + _prepare_headers(headers)
        + _open(url, headers)
        + _request_bearer_token(challenge)
    }

    class RegistryBlobSnapshotFile {
        + download(blob_file_path, snapshot_dir) str
        - client: OCIRegistryClient
        - digest: str
    }
    RegistryBlobSnapshotFile --|> SnapshotFile

    class SnapshotFile {
        <<external>>
    }

    class download_oci_artifact {
        <<function>>
    }
    OCIRegistryClient <.. RegistryBlobSnapshotFile : uses
    RegistryBlobSnapshotFile <.. download_oci_artifact : used by

File-Level Changes

Change Details Files
RLCR transport now falls back to OCI artifact download and tracks snapshot state
  • Initialize and track _artifact_downloaded based on existing snapshots
  • Override pull to catch CalledProcessError and call _attempt_artifact_pull
  • Implement _attempt_artifact_pull and _has_artifact_snapshot methods
  • Extend exists, _get_entry_model_path, and setup_mounts to respect artifact downloads
ramalama/transports/rlcr.py
Add pure-Python OCI artifact client and download integration
  • Create OCIRegistryClient for manifest fetching and blob downloads with token authentication
  • Define RegistryBlobSnapshotFile and snapshot file type inference
  • Implement download_oci_artifact to assemble snapshot files and drive model_store.new_snapshot
  • Add utility functions for reference splitting and file type mapping
ramalama/transports/oci_artifact.py
Enhance unit tests to cover RLCR fallback and OCI artifact download
  • Augment test args with new artifact-related flags
  • Add TestRLCRArtifactFallback for pull fallback success and failure
  • Add TestOCIArtifactDownload to simulate OCI client and verify snapshot creation
test/unit/test_rlcr.py

Possibly linked issues

  • #unknown: PR implements pure Python OCI artifact pulling, addressing the issue's question on pulling new OCI artifact types.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an issue from a review comment by replying to it. You can also reply to a review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull request title to generate a title at any time. You can also comment @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in the pull request body to generate a PR summary at any time exactly where you want it. You can also comment @sourcery-ai summary on the pull request to (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the pull request to resolve all Sourcery comments. Useful if you've already addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull request to dismiss all existing Sourcery reviews. Especially useful if you want to start fresh with a new review - don't forget to comment @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

  • Contact our support team for questions or feedback.
  • Visit our documentation for detailed guides and information.
  • Keep in touch with the Sourcery team by following us on X/Twitter, LinkedIn or GitHub.

sourcery-ai[bot] avatar Oct 17 '25 23:10 sourcery-ai[bot]

Summary of Changes

Hello @ieaves, I'm Gemini Code Assist[^1]! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request lays the groundwork for more flexible model artifact management by introducing direct OCI artifact pulling capabilities. It provides a pure Python implementation for interacting with OCI registries to fetch model artifacts, serving as an initial step towards addressing broader issues related to generic model artifact handling. The changes integrate this new functionality into the existing rlcr transport, enabling it to fall back to OCI artifact pulling when traditional container image pulls are unsuccessful, thereby enhancing the robustness of model retrieval.

Highlights

  • OCI Artifact Pulling Implementation: Introduces a new Python module (oci_artifact.py) to handle pulling Open Container Initiative (OCI) artifacts from registries, including manifest fetching, authentication, and blob downloading.
  • Fallback Mechanism for Model Pulling: Modifies the rlcr transport to attempt OCI artifact pulling as a fallback mechanism if the primary container image pulling (e.g., via Podman) fails.
  • Enhanced Model Lifecycle Management: Integrates OCI artifact handling into the RamalamaContainerRegistry class, allowing it to recognize and manage models downloaded as OCI artifacts, affecting exists, _get_entry_model_path, and setup_mounts methods.
  • Comprehensive Unit Tests: Adds new unit tests to validate the OCI artifact fallback logic and the core functionality of downloading OCI artifacts and creating model snapshots.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with :thumbsup: and :thumbsdown: on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

[^1]: Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

gemini-code-assist[bot] avatar Oct 17 '25 23:10 gemini-code-assist[bot]

@ieaves still working on this? I think this along with the podman PR which is waiting for podman 5.7 release should move us forward with artifact support.

rhatdan avatar Nov 03 '25 14:11 rhatdan

@rhatdan I'm taking a look at your podman changes now. I need to adapt this to use

  1. The podman annotation specs
  2. Add this is a fallback to the podman functionality you PRed.

ieaves avatar Nov 06 '25 16:11 ieaves

@rhatdan I rebased this to your branch and took a shot at integrating a hierarchy of decision strategies depending on the users configuration. The basic structure is supposed to be

  1. If there is a sufficiently advanced version of podman use podman pull
  2. If not, identify whether the artifact exists locally and check the manifest to distinguish artifacts from images
  3. If not, http probe the manifest to identify its type and use the appropriate strategy (docker / podman for images, http for artifacts)

Then, if the user is running docker we pipe the model file into the container since we can't use artifact/image mounting the same way we can with podman.

I haven't done extensive testing but I've got things working with both docker and podman testing against one of my models at rlcr.io/ramalama/gemma3-270m:gguf.

ieaves avatar Nov 21 '25 01:11 ieaves

A friendly reminder that this PR had no activity for 30 days.

github-actions[bot] avatar Dec 22 '25 00:12 github-actions[bot]

@ieaves still working on this? Can this be rebased after my Artifact PR was merged?

rhatdan avatar Dec 22 '25 14:12 rhatdan