Storage Quotas & Limits
Relevant source files
The following files were used as context for generating this wiki page:
Storage Quotas and Limits in Harbor provide a mechanism to restrict and monitor resource consumption—primarily storage space and artifact counts—at the project level. This system ensures that no single project can exhaust the underlying registry storage or exceed predefined administrative boundaries, maintaining multi-tenant stability.
The system is implemented using a combination of specialized middleware that intercepts resource-intensive operations (like blob uploads and manifest pushes) and a central controller that manages the quota state in the database. It supports hard limits, real-time usage tracking, and warning notifications when usage reaches specific thresholds.
Sources: src/server/middleware/quota/quota.go:37-64, src/pkg/exporter/project_collector.go:33-45, api/v2.0/swagger.yaml:1396-1405
Architecture and Components
The quota system is distributed across the request handling pipeline, consisting of middleware, controllers, and background tasks.
Quota Middleware
Harbor utilizes RequestMiddleware and RefreshMiddleware to manage quotas during API calls. The RequestMiddleware validates that a project has sufficient remaining quota before allowing a resource-modifying operation to proceed. If a request is successful, the usage is typically updated.
Sources: src/server/middleware/quota/quota.go:50-136, src/server/middleware/quota/quota.go:173-219
Quota Controller
The quota.Ctl serves as the primary interface for managing quota records. It handles operations such as retrieving quotas by reference (e.g., project ID), requesting resource allocations, and refreshing usage data.
Sources: src/server/middleware/quota/controller.go:21-27, src/server/v2.0/handler/quota.go:32-35
Data Flow for Resource Requests
When an artifact is pushed or copied, the system calculates the impact on storage and checks against hard limits.
The diagram above illustrates the logic flow within the RequestMiddleware when a client attempts to upload a blob or manifest.
Sources: src/server/middleware/quota/quota.go:50-169
Resource Calculation Logic
Resource requirements are calculated differently depending on the specific OCI registry operation.
Blob Uploads
During a blob upload (PutBlobUploadMiddleware), the system determines size via the Content-Length header or by querying the session's accepted size. Quota is only deducted if the blob digest does not already exist within the project.
Sources: src/server/middleware/quota/put_blob_upload.go:31-62
Manifest Pushing
The PutManifestMiddleware calculates the total size of the manifest itself plus any new blobs it references. It uses blobController.FindMissingAssociationsForProject to identify which layers are not yet associated with the project to avoid double-counting existing shared layers.
Sources: src/server/middleware/quota/put_manifest.go:42-83
Artifact Copying
When copying an artifact between projects, the CopyArtifactMiddleware walks the artifact tree (including accessories) and identifies all blobs that are not yet present in the destination project. It sums their sizes to determine the storage impact.
Sources: src/server/middleware/quota/copy_artifact.go:61-125
API and Data Models
Quota Data Structure
Quotas are defined by "hard" limits and "used" usage metrics, both represented as resource lists.
| Field | Type | Description |
|---|---|---|
id | integer | Unique identifier for the quota record. |
ref | object | The reference object (e.g., project). |
hard | ResourceList | The hard limits (e.g., {"storage": 1073741824}). |
used | ResourceList | Current consumption (e.g., {"storage": 536870912}). |
update_time | string | The last time usage was refreshed. |
Sources: api/v2.0/swagger.yaml:2630-2651, src/server/v2.0/handler/quota_test.go:44-52
REST API Endpoints
Administrators can manage quotas through the following endpoints:
| Method | Path | Description |
|---|---|---|
GET | /quotas | List all quotas with filtering and sorting. |
GET | /quotas/{id} | Get details for a specific quota. |
PUT | /quotas/{id} | Update hard limits for a specific quota. |
Sources: api/v2.0/swagger.yaml:1396-1473, src/server/v2.0/handler/quota.go:37-97
Monitoring and Synchronization
Prometheus Exporter
The ProjectCollector gathers quota information for Prometheus monitoring. It executes SQL queries to join project metadata with the quota and quota_usage tables, exposing metrics like project_quota_usage_byte and project_quota_byte.
Sources: src/pkg/exporter/project_collector.go:40-100
Quota Synchronization
Over time, cached usage may drift from actual storage. The system provides an internal API (/internal/syncquota) to trigger a manual refresh. This operation:
- Sets the system to
ReadOnlymode. - Triggers an asynchronous refresh for all projects via
quota.RefreshForProjects. - Restores the system's original read-only state upon completion.
Sources: src/core/api/internal.go:78-109
Configuration Options
Global quota settings are managed through the system configuration API.
| Option | Type | Default | Description |
|---|---|---|---|
quota_per_project_enable | boolean | - | Enables the project-level quota feature. |
storage_per_project | integer | - | Default storage limit for new projects (bytes). |
ResourcesWarningPercent | integer | 85 | Threshold percentage to trigger warning events. |
Sources: api/v2.0/swagger.yaml:2150-2155, src/server/middleware/quota/quota.go:43-45
Conclusion
The storage quota system in Harbor is a robust framework that integrates deeply with the OCI distribution protocol handlers. By intercepting manifest and blob operations, it provides precise control over project growth. Its integration with Prometheus and administrative APIs allows for proactive resource management in large-scale container registry deployments.