This document provides detailed information about the HyperFleet API resources, including endpoints, request/response formats, and usage patterns.
GET /api/hyperfleet/v1/clusters
POST /api/hyperfleet/v1/clusters
GET /api/hyperfleet/v1/clusters/{cluster_id}
GET /api/hyperfleet/v1/clusters/{cluster_id}/statuses
POST /api/hyperfleet/v1/clusters/{cluster_id}/statuses
POST /api/hyperfleet/v1/clusters
Request Body:
{
"kind": "Cluster",
"name": "my-cluster",
"spec": {},
"labels": {
"environment": "production"
}
}Response (201 Created):
{
"kind": "Cluster",
"id": "2abc123...",
"href": "/api/hyperfleet/v1/clusters/2abc123...",
"name": "my-cluster",
"generation": 1,
"spec": {},
"labels": {
"environment": "production"
},
"created_time": "2025-01-01T00:00:00Z",
"updated_time": "2025-01-01T00:00:00Z",
"created_by": "user@example.com",
"updated_by": "user@example.com",
"status": {
"conditions": [
{
"type": "Available",
"status": "False",
"reason": "AwaitingAdapters",
"message": "Waiting for adapters to report status",
"observed_generation": 1,
"created_time": "2025-01-01T00:00:00Z",
"last_updated_time": "2025-01-01T00:00:00Z",
"last_transition_time": "2025-01-01T00:00:00Z"
},
{
"type": "Ready",
"status": "False",
"reason": "AwaitingAdapters",
"message": "Waiting for adapters to report status",
"observed_generation": 1,
"created_time": "2025-01-01T00:00:00Z",
"last_updated_time": "2025-01-01T00:00:00Z",
"last_transition_time": "2025-01-01T00:00:00Z"
}
]
}
}Note: Status initially has Available=False and Ready=False conditions until adapters report status.
GET /api/hyperfleet/v1/clusters/{cluster_id}
Response (200 OK):
{
"kind": "Cluster",
"id": "2abc123...",
"href": "/api/hyperfleet/v1/clusters/2abc123...",
"name": "my-cluster",
"generation": 1,
"spec": {},
"labels": {
"environment": "production"
},
"created_time": "2025-01-01T00:00:00Z",
"updated_time": "2025-01-01T00:00:00Z",
"created_by": "user@example.com",
"updated_by": "user@example.com",
"status": {
"conditions": [
{
"type": "Available",
"status": "True",
"reason": "ResourceAvailable",
"message": "Cluster is accessible",
"observed_generation": 1,
"created_time": "2025-01-01T00:00:00Z",
"last_updated_time": "2025-01-01T00:00:00Z",
"last_transition_time": "2025-01-01T00:00:00Z"
},
{
"type": "Ready",
"status": "True",
"reason": "ResourceReady",
"message": "All adapters report ready at current generation",
"observed_generation": 1,
"created_time": "2025-01-01T00:00:00Z",
"last_updated_time": "2025-01-01T00:00:00Z",
"last_transition_time": "2025-01-01T00:00:00Z"
}
]
}
}GET /api/hyperfleet/v1/clusters?page=1&pageSize=10
Response (200 OK):
{
"kind": "ClusterList",
"page": 1,
"size": 10,
"total": 100,
"items": [
{
"kind": "Cluster",
"id": "2abc123...",
"name": "my-cluster",
...
}
]
}POST /api/hyperfleet/v1/clusters/{cluster_id}/statuses
Adapters use this endpoint to report their status.
Request Body:
{
"adapter": "validator",
"observed_generation": 1,
"observed_time": "2025-01-01T10:00:00Z",
"conditions": [
{
"type": "Available",
"status": "True",
"reason": "AllValidationsPassed",
"message": "All validations passed"
},
{
"type": "Applied",
"status": "True",
"reason": "ValidationJobApplied",
"message": "Validation job applied successfully"
},
{
"type": "Health",
"status": "True",
"reason": "OperationsCompleted",
"message": "All adapter operations completed successfully"
}
],
"data": {
"job_name": "validator-job-abc123",
"attempt": 1
}
}Response (201 Created):
{
"adapter": "validator",
"observed_generation": 1,
"conditions": [
{
"type": "Available",
"status": "True",
"reason": "AllValidationsPassed",
"message": "All validations passed",
"last_transition_time": "2025-01-01T10:00:00Z"
},
{
"type": "Applied",
"status": "True",
"reason": "ValidationJobApplied",
"message": "Validation job applied successfully",
"last_transition_time": "2025-01-01T10:00:00Z"
},
{
"type": "Health",
"status": "True",
"reason": "OperationsCompleted",
"message": "All adapter operations completed successfully",
"last_transition_time": "2025-01-01T10:00:00Z"
}
],
"data": {
"job_name": "validator-job-abc123",
"attempt": 1
},
"created_time": "2025-01-01T10:00:00Z",
"last_report_time": "2025-01-01T10:00:00Z"
}Note: The API automatically sets created_time, last_report_time, and last_transition_time fields.
The status uses Kubernetes-style conditions instead of a single phase field:
-
Ready - Whether all adapters report successfully at the current generation
True: All required adapters reportAvailable=Trueat current spec generationFalse: One or more adapters report Available=False at current generation- After every spec change,
ReadybecomesFalsesince adapters take some time to report at current spec generation - Default value when creating the cluster, when no adapters have reported yet any value
- After every spec change,
-
Available - Aggregated adapter result for a common
observed_generationTrue: All required adapters report Available=True for the same observed_generationFalse: At least one adapter reports Available=False when all adapters report the same observed_generation- Default value when creating the cluster, when no adapters have reported yet any value
Available keeps its value unchanged in case adapters report from a different observed_generation or there is already a mix of observed_generation statuses
- e.g.
Available=Trueforobserved_generation==1- One adapter reports
Available=Falseforobserved_generation=1Availabletransitions toFalse - One adapter reports
Available=Falseforobserved_generation=2Availablekeeps itsTruestatus
- One adapter reports
Description of the aggregation logic for the resource status conditions
- An API that stores resources entities (clusters, nodepools)
- A sentinel that polls the API for changes and triggers messages
- Instances of "adapters":
- Read the messages
- Reconcile the state with the world
- Report back to the API, using statuses "conditions"
Resources keep track of its status, which is affected by the reports from adapters
- Each resource keeps a
generationproperty that gets increased on every change - Adapters associated with a resource, report their state as an array of adapter conditions
- Three of these conditions are always mandatory :
Available,Applied,Health - If one of the mandatory conditions is missing, the report is discarded
- A
observed_generationfield indicating the generation associated with the report observed_timefor when the adapter work was done- If the reported
observed_generationis lower than the already storedobserved_generationfor that adapter, the report is discarded
- Three of these conditions are always mandatory :
- Each resource has a list of associated "adapters" used to compute the aggregated status.conditions
- Each resource "status.conditions" is array property composed of:
- The
Availablecondition of each adapter, named as<adapter-name>Successful - 2 aggregated conditions:
ReadyandAvailablecomputed from the array ofAvailableresource statuses conditions- Only
Availablecondition from adapters is used to compute aggregated conditions
- Only
- The
The whole API spec is at: https://raw.githubusercontent.com/openshift-hyperfleet/hyperfleet-api/refs/heads/main/openapi/openapi.yaml
The aggregation logic for a resource (cluster/nodepool) works as follows.
Notation:
X= report'sobserved_generationG= resource's currentgenerationstatuses[]= all stored adapter condition reportslut= adapter'slast_report_timeltt=last_transition_timeobs_gen=observed_generationobs_time= report'sobserved_time—= no change
Checked before any aggregation. A discarded or rejected report causes no state change.
| Rule | Condition | Outcome |
|---|---|---|
obs_gen too high |
report observed_generation > resource generation |
Discarded |
| Stale adapter report | report observed_generation < adapter's stored observed_generation |
Discarded |
| Missing mandatory conditions | Missing any of Available, Applied, Health, or value not in {True, False, Unknown} |
Discarded |
| Available=Unknown | Report is valid but Available=Unknown |
Discarded |
| Event | Condition | Target | → status | → obs_gen | → lut | → ltt |
|---|---|---|---|---|---|---|
| Creation | — | Ready |
False |
1 |
now |
now |
| Creation | — | Available |
False |
1 |
now |
now |
| Change (→G) | Was Ready=True |
Ready |
False |
G |
now |
now |
| Change (→G) | Was Ready=False |
Ready |
False |
G |
now |
— |
| Change (→G) | — | Available |
unchanged | unchanged | — |
— |
The Ready check and Available check are independent — both can apply to the same incoming report.
| Target | Current State | Required Condition | → status | → lut | → ltt | → obs_gen |
|---|---|---|---|---|---|---|
Ready |
Ready=True |
X==G AND all statuses[].obs_gen==G AND all statuses[].status==True |
unchanged | min(adapter last_report_time) |
— |
— |
Ready |
Ready=False |
X==G AND all statuses[].obs_gen==G AND all statuses[].status==True |
True |
min(adapter last_report_time) |
obs_time |
— |
Ready |
Ready=False |
Any required adapter has no stored status | — |
now |
— |
— |
Ready |
any | Conditions above not met | — |
— |
— |
— |
Available |
Available=False |
all statuses[].obs_gen==X |
True |
min(adapter last_report_time) |
obs_time |
X |
Available |
Available=True |
all statuses[].obs_gen==X |
unchanged | min(adapter last_report_time) |
— |
X |
Available |
any | Conditions above not met | — |
— |
— |
— |
| Target | Current State | Required Condition | → status | → lut | → ltt | → obs_gen |
|---|---|---|---|---|---|---|
Ready |
Ready=False |
X==G |
unchanged | min(adapter last_report_time) |
— |
— |
Ready |
Ready=True |
X==G |
False |
obs_time |
obs_time |
— |
Ready |
any | Conditions above not met | — |
— |
— |
— |
Available |
Available=False |
all statuses[].obs_gen==X |
unchanged | min(adapter last_report_time) |
— |
X |
Available |
Available=True |
all statuses[].obs_gen==X |
False |
obs_time |
obs_time |
X |
Available |
any | Conditions above not met | — |
— |
— |
— |
GET /api/hyperfleet/v1/nodepools
GET /api/hyperfleet/v1/clusters/{cluster_id}/nodepools
POST /api/hyperfleet/v1/clusters/{cluster_id}/nodepools
GET /api/hyperfleet/v1/clusters/{cluster_id}/nodepools/{nodepool_id}
GET /api/hyperfleet/v1/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses
POST /api/hyperfleet/v1/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses
POST /api/hyperfleet/v1/clusters/{cluster_id}/nodepools
Request Body:
{
"kind": "NodePool",
"name": "worker-pool",
"spec": {},
"labels": {
"role": "worker"
}
}Response (201 Created):
{
"kind": "NodePool",
"id": "2def456...",
"href": "/api/hyperfleet/v1/nodepools/2def456...",
"name": "worker-pool",
"owner_references": {
"kind": "Cluster",
"id": "2abc123..."
},
"generation": 1,
"spec": {},
"labels": {
"role": "worker"
},
"created_time": "2025-01-01T00:00:00Z",
"updated_time": "2025-01-01T00:00:00Z",
"created_by": "user@example.com",
"updated_by": "user@example.com",
"status": {
"conditions": [
{
"type": "Available",
"status": "False",
"reason": "AwaitingAdapters",
"message": "Waiting for adapters to report status",
"observed_generation": 1,
"created_time": "2025-01-01T00:00:00Z",
"last_updated_time": "2025-01-01T00:00:00Z",
"last_transition_time": "2025-01-01T00:00:00Z"
},
{
"type": "Ready",
"status": "False",
"reason": "AwaitingAdapters",
"message": "Waiting for adapters to report status",
"observed_generation": 1,
"created_time": "2025-01-01T00:00:00Z",
"last_updated_time": "2025-01-01T00:00:00Z",
"last_transition_time": "2025-01-01T00:00:00Z"
}
]
}
}GET /api/hyperfleet/v1/clusters/{cluster_id}/nodepools/{nodepool_id}
Response (200 OK):
{
"kind": "NodePool",
"id": "2def456...",
"href": "/api/hyperfleet/v1/nodepools/2def456...",
"name": "worker-pool",
"owner_references": {
"kind": "Cluster",
"id": "2abc123..."
},
"generation": 1,
"spec": {},
"labels": {
"role": "worker"
},
"created_time": "2025-01-01T00:00:00Z",
"updated_time": "2025-01-01T00:00:00Z",
"created_by": "user@example.com",
"updated_by": "user@example.com",
"status": {
"conditions": [
{
"type": "Available",
"status": "True",
"reason": "ResourceAvailable",
"message": "NodePool is accessible",
"observed_generation": 1
},
{
"type": "Ready",
"status": "True",
"reason": "ResourceReady",
"message": "All adapters report ready at current generation",
"observed_generation": 1
}
]
}
}POST /api/hyperfleet/v1/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses
Same format as cluster status reporting (see above).
All list endpoints support pagination:
GET /api/hyperfleet/v1/clusters?page=1&pageSize=10
Parameters:
page- Page number (default: 1)pageSize- Items per page (default: 100)
Response:
{
"kind": "ClusterList",
"page": 1,
"size": 10,
"total": 100,
"items": [...]
}All list endpoints support filtering using TSL (Tree Search Language) query syntax. Example:
curl -G http://localhost:8000/api/hyperfleet/v1/clusters \
--data-urlencode "search=status.conditions.Ready='True' and labels.environment='production'"See search.md for complete documentation.
kind- Resource type (Cluster, NodePool)id- Unique resource identifier (auto-generated, format:2<base62>)href- Resource URIname- Resource name (user-defined)generation- Spec version counter (incremented on spec updates)spec- Provider-specific configuration (JSONB, validated against OpenAPI schema)labels- Key-value pairs for categorization and searchcreated_time- When resource was created (API-managed)updated_time- When resource was last updated (API-managed)created_by- User who created the resource (email)updated_by- User who last updated the resource (email)
The status object contains synthesized conditions computed from adapter reports:
conditions- Array of resource conditions, including:- Available - Whether resource is running at any known good configuration
- Ready - Whether all adapters have processed current spec generation
- Additional conditions from adapters (with
observed_generation, timestamps)
In AdapterStatus POST request (ConditionRequest):
type- Condition type (Available, Applied, Health)status- Condition status (True, False)reason- Machine-readable reason codemessage- Human-readable message
In Cluster/NodePool status (ResourceCondition):
- All above fields plus:
observed_generation- Generation this condition reflectscreated_time- When condition was first created (API-managed)last_updated_time- When this condition was last refreshed (API-managed). For Available, always the evaluation time. For Ready: when Ready=True, the minimum oflast_report_timeacross all required adapters that report Available=True at the current generation; when Ready=False, the evaluation time (so consumers can detect staleness).last_transition_time- When status last changed (API-managed)
All list endpoints accept the following query parameters:
| Parameter | Type | Required | Default | Constraints |
|---|---|---|---|---|
search |
string | No | - | TSL query syntax |
page |
integer (int32) | No | 1 |
- |
pageSize |
integer (int32) | No | 20 |
- |
orderBy |
string | No | created_time |
- |
order |
string | No | - | Must be asc or desc |
| Parameter | Type | Required |
|---|---|---|
cluster_id |
string | Yes |
nodepool_id |
string | Yes |
| Constraint | Value |
|---|---|
| Required | Yes |
| Type | string |
| Min length | 3 |
| Max length | 53 |
| Pattern | ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ |
Must be lowercase alphanumeric, may contain hyphens, and must start and end with an alphanumeric character.
| Constraint | Value |
|---|---|
| Required | Yes |
| Type | string |
| Min length | 3 |
| Max length | 15 |
| Pattern | ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ |
Same naming rules as cluster, but with a shorter maximum length.
| Field | Type | Required |
|---|---|---|
adapter |
string | Yes |
observed_generation |
integer (int32) | Yes |
observed_time |
string (date-time) | Yes |
conditions |
array of ConditionRequest |
Yes |
metadata |
object | No |
data |
object | No |
| Field | Type | Required | Constraints |
|---|---|---|---|
type |
string | Yes | - |
status |
string | Yes | Must be True, False, or Unknown |
reason |
string | No | - |
message |
string | No | - |
- AdapterConditionStatus (used in adapter status reports):
True,False,Unknown - ResourceConditionStatus (used in cluster/nodepool conditions):
True,False - OrderDirection:
asc,desc
- Example Usage - Practical examples
- Authentication - API authentication
- Database - Database schema