Current section
Files
Jump to
Current section
Files
lib/oci/storage/adapter.ex
defmodule OCI.Storage.Adapter do
@moduledoc """
Behaviour for OCI registry storage backends.
This module defines the interface that storage adapters must implement to work with OCI (Open Container Initiative) registries.
A storage adapter is responsible for storing and retrieving container images and their components.
## Key Concepts
- **Repository**: A collection of related container images (e.g., "myapp/backend")
- **Blob**: Binary data that represents layers of a container image or configuration
- **Manifest**: A JSON document that describes a container image, including its layers and configuration
- **Digest**: A unique identifier for a blob, typically a SHA-256 hash
- **Reference**: A human-readable identifier for a manifest (e.g., "latest", "v1.0.0")
## Implementation Guide
When implementing this behaviour, you'll need to handle:
1. Repository initialization and management
2. Blob storage and retrieval
3. Manifest storage and retrieval
4. Tag management
5. Upload handling for large blobs
## Example Usage
```elixir
defmodule MyStorageAdapter do
@behaviour OCI.Storage.Adapter
defstruct [:path] # Define your struct fields here
# Implement all callbacks here
end
```
"""
@type t :: struct()
@type error_details_t :: any()
@doc """
Checks if a blob exists in the repository and returns its size if found.
"""
@callback blob_exists?(
storage :: t(),
repo :: String.t(),
digest :: String.t(),
ctx :: OCI.Context.t()
) ::
boolean()
@doc """
Cancels an ongoing blob upload session.
"""
@callback cancel_blob_upload(
storage :: t(),
repo :: String.t(),
uuid :: String.t(),
ctx :: OCI.Context.t()
) ::
:ok
| {:error, :BLOB_UPLOAD_UNKNOWN}
| {:error, :BLOB_UPLOAD_UNKNOWN, error_details_t}
@doc """
Finalizes a blob upload and verifies the digest.
"""
@callback complete_blob_upload(
storage :: t(),
repo :: String.t(),
upload_id :: String.t(),
digest :: String.t(),
ctx :: OCI.Context.t()
) ::
:ok | {:error, atom()} | {:error, atom(), error_details_t}
@doc """
Deletes a blob from the repository.
"""
@callback delete_blob(
storage :: t(),
repo :: String.t(),
digest :: String.t(),
ctx :: OCI.Context.t()
) ::
:ok | {:error, :BLOB_UNKNOWN} | {:error, :BLOB_UNKNOWN, error_details_t}
@doc """
Deletes a manifest from the repository.
"""
@callback delete_manifest(
storage :: t(),
repo :: String.t(),
reference :: String.t(),
ctx :: OCI.Context.t()
) ::
:ok | {:error, atom()}
@doc """
Retrieves a blob's content from the repository.
"""
@callback get_blob(
storage :: t(),
repo :: String.t(),
digest :: String.t(),
ctx :: OCI.Context.t()
) ::
{:ok, content :: binary()}
| {:error, :BLOB_UNKNOWN}
| {:error, :BLOB_UNKNOWN, error_details_t}
@doc """
Retrieves a manifest from the repository.
"""
@callback get_manifest(
storage :: t(),
repo :: String.t(),
reference :: String.t(),
ctx :: OCI.Context.t()
) ::
{:ok, manifest :: binary(), content_type :: String.t()}
| {:error, atom(), error_details_t}
@doc """
Gets the status of an ongoing blob upload.
"""
@callback get_blob_upload_status(
storage :: t(),
repo :: String.t(),
uuid :: String.t(),
ctx :: OCI.Context.t()
) ::
{:ok, range :: String.t()} | {:error, term()} | {:error, term(), error_details_t}
@doc """
Gets the total size of an ongoing blob upload.
"""
@callback get_blob_upload_offset(
storage :: t(),
repo :: String.t(),
uuid :: String.t(),
ctx :: OCI.Context.t()
) ::
{:ok, size :: non_neg_integer()}
| {:error, term()}
| {:error, term(), error_details_t}
@doc """
Gets metadata about a manifest without retrieving its content.
"""
@callback manifest_exists?(
storage :: t(),
repo :: String.t(),
reference :: String.t(),
ctx :: OCI.Context.t()
) ::
boolean()
@doc """
Initializes a new storage adapter instance with the given configuration.
"""
@callback init(config :: map()) ::
{:ok, storage :: t()} | {:error, term()} | {:error, term(), error_details_t}
@doc """
Initiates a blob upload session.
"""
@callback initiate_blob_upload(storage :: t(), repo :: String.t(), ctx :: OCI.Context.t()) ::
{:ok, upload_id :: String.t()}
| {:error, term()}
| {:error, term(), error_details_t}
@doc """
Lists tags in a repository with pagination support.
"""
@callback list_tags(
storage :: t(),
repo :: String.t(),
pagination :: OCI.Registry.Pagination.t(),
ctx :: OCI.Context.t()
) ::
{:ok, tags :: [String.t()]}
| {:error, :NAME_UNKNOWN}
| {:error, :NAME_UNKNOWN, error_details_t}
@doc """
Mounts a blob from one repository to another.
"""
@callback mount_blob(
storage :: t(),
repo :: String.t(),
digest :: String.t(),
from_repo :: String.t(),
ctx :: OCI.Context.t()
) ::
:ok | {:error, :BLOB_UNKNOWN} | {:error, :BLOB_UNKNOWN, error_details_t}
@doc """
Stores a manifest in the repository.
"""
@callback store_manifest(
storage :: t(),
repo :: String.t(),
reference :: String.t(),
manifest :: map(),
manifest_digest :: String.t(),
ctx :: OCI.Context.t()
) ::
:ok
| {:error, :MANIFEST_BLOB_UNKNOWN | :MANIFEST_INVALID | :NAME_UNKNOWN,
error_details_t}
@doc """
Checks if a repository exists.
"""
@callback repo_exists?(storage :: t(), repo :: String.t(), ctx :: OCI.Context.t()) :: boolean()
@doc """
Uploads a chunk of data to an ongoing blob upload.
"""
@callback upload_blob_chunk(
storage :: t(),
repo :: String.t(),
uuid :: String.t(),
chunk :: binary(),
content_range :: String.t(),
ctx :: OCI.Context.t()
) ::
{:ok, range :: String.t()}
| {:error, atom()}
| {:error, atom(), error_details_t}
@doc """
Checks if an upload exists.
"""
@callback upload_exists?(
storage :: t(),
repo :: String.t(),
uuid :: String.t(),
ctx :: OCI.Context.t()
) ::
boolean()
end