From debc9038a167bd67e46b0b0f73d009672db2b70c Mon Sep 17 00:00:00 2001 From: Dmitrii Andreev Date: Tue, 19 May 2026 16:02:56 -0500 Subject: [PATCH] HYPERFLEET-1083 feat: add generic Resource type and Channel/Version spec schemas --- CHANGELOG.md | 21 +- aliases-core.tsp | 1 + aliases-gcp.tsp | 10 + main.tsp | 4 +- models-gcp/channel/example_channel.tsp | 22 + models-gcp/channel/example_patch.tsp | 9 + models-gcp/channel/example_post.tsp | 11 + models-gcp/channel/model.tsp | 55 + models-gcp/version/example_patch.tsp | 11 + models-gcp/version/example_post.tsp | 13 + models-gcp/version/example_version.tsp | 29 + models-gcp/version/model.tsp | 67 + models/resource/example_patch.tsp | 6 + models/resource/example_post.tsp | 8 + models/resource/example_resource.tsp | 19 + models/resource/model.tsp | 90 ++ schemas/core/openapi.yaml | 541 ++++++- schemas/core/swagger.yaml | 558 ++++++- schemas/gcp/openapi.yaml | 1780 +++++++++++++++------ schemas/gcp/swagger.yaml | 1990 +++++++++++++++++------- services/channels.tsp | 89 ++ services/resources.tsp | 93 ++ services/statuses-internal.tsp | 59 + services/statuses.tsp | 1 + services/versions.tsp | 96 ++ 25 files changed, 4527 insertions(+), 1056 deletions(-) create mode 100644 models-gcp/channel/example_channel.tsp create mode 100644 models-gcp/channel/example_patch.tsp create mode 100644 models-gcp/channel/example_post.tsp create mode 100644 models-gcp/channel/model.tsp create mode 100644 models-gcp/version/example_patch.tsp create mode 100644 models-gcp/version/example_post.tsp create mode 100644 models-gcp/version/example_version.tsp create mode 100644 models-gcp/version/model.tsp create mode 100644 models/resource/example_patch.tsp create mode 100644 models/resource/example_post.tsp create mode 100644 models/resource/example_resource.tsp create mode 100644 models/resource/model.tsp create mode 100644 services/channels.tsp create mode 100644 services/resources.tsp create mode 100644 services/versions.tsp diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c5ab4d..4c1e273 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.0.17] - 2026-05-21 + +### Added + +- Generic `Resource` type with `kind` discriminator and JSONB `spec` field, replacing per-entity model hierarchies for new resource types (HYPERFLEET-1083) +- `ResourceCreateRequest`, `ResourcePatchRequest`, `ResourceList`, `ResourceStatus` types in core contract +- Generic `/resources` CRUD routes in core contract (GET list, GET by ID, POST, PATCH, DELETE) per design doc Section 3.2 +- `/channels` and `/channels/{channel_id}/versions` CRUD routes in GCP contract +- `references` field on Resource for non-ownership associations between entities (Section 9) +- `ChannelSpec` validation schema in GCP contract (`is_default`, `enabled_regex`) +- `VersionSpec` validation schema in GCP contract (`raw_version`, `enabled`, `is_default`, `release_image`, `end_of_life_time`) +- `KindChannel` and `KindVersion` kind aliases in GCP contract + +### Changed + +- `GET /resources/{id}/statuses` and `POST /resources/{id}/force-delete` moved to core contract +- `GET /clusters/{id}/statuses` and `GET /nodepools/{id}/statuses` moved to core contract + ## [1.0.16] - 2026-05-20 ### Added @@ -152,7 +170,8 @@ First official stable release of the HyperFleet API specification. - Interactive API documentation -[Unreleased]: https://github.com/openshift-hyperfleet/hyperfleet-api-spec/compare/v1.0.16...HEAD +[Unreleased]: https://github.com/openshift-hyperfleet/hyperfleet-api-spec/compare/v1.0.17...HEAD +[1.0.17]: https://github.com/openshift-hyperfleet/hyperfleet-api-spec/compare/v1.0.16...v1.0.17 [1.0.16]: https://github.com/openshift-hyperfleet/hyperfleet-api-spec/compare/v1.0.15...v1.0.16 [1.0.15]: https://github.com/openshift-hyperfleet/hyperfleet-api-spec/compare/v1.0.14...v1.0.15 [1.0.14]: https://github.com/openshift-hyperfleet/hyperfleet-api-spec/compare/v1.0.13...v1.0.14 diff --git a/aliases-core.tsp b/aliases-core.tsp index b972f47..406e7d5 100644 --- a/aliases-core.tsp +++ b/aliases-core.tsp @@ -6,5 +6,6 @@ import "./models-core/nodepool/model.tsp"; import "./models-core/nodepool/example_nodepool.tsp"; import "./models-core/nodepool/example_post.tsp"; import "./models-core/nodepool/example_patch.tsp"; +import "./services/statuses.tsp"; import "./services/statuses-internal.tsp"; import "./services/force-delete-internal.tsp"; diff --git a/aliases-gcp.tsp b/aliases-gcp.tsp index 4965061..740b67f 100644 --- a/aliases-gcp.tsp +++ b/aliases-gcp.tsp @@ -6,3 +6,13 @@ import "./models-gcp/nodepool/model.tsp"; import "./models-gcp/nodepool/example_nodepool.tsp"; import "./models-gcp/nodepool/example_post.tsp"; import "./models-gcp/nodepool/example_patch.tsp"; +import "./models-gcp/channel/model.tsp"; +import "./models-gcp/channel/example_channel.tsp"; +import "./models-gcp/channel/example_post.tsp"; +import "./models-gcp/channel/example_patch.tsp"; +import "./models-gcp/version/model.tsp"; +import "./models-gcp/version/example_version.tsp"; +import "./models-gcp/version/example_post.tsp"; +import "./models-gcp/version/example_patch.tsp"; +import "./services/channels.tsp"; +import "./services/versions.tsp"; diff --git a/main.tsp b/main.tsp index 4124471..fd44f51 100644 --- a/main.tsp +++ b/main.tsp @@ -3,8 +3,8 @@ import "@typespec/openapi"; import "@typespec/openapi3"; import "./services/clusters.tsp"; -import "./services/statuses.tsp"; import "./services/nodepools.tsp"; +import "./services/resources.tsp"; // Provider-specific security is imported via aliases.tsp import "./aliases.tsp"; @@ -21,7 +21,7 @@ using OpenAPI; */ @service(#{ title: "HyperFleet API" }) @info(#{ - version: "1.0.16", + version: "1.0.17", contact: #{ name: "HyperFleet Team", url: "https://github.com/openshift-hyperfleet", diff --git a/models-gcp/channel/example_channel.tsp b/models-gcp/channel/example_channel.tsp new file mode 100644 index 0000000..1f681ec --- /dev/null +++ b/models-gcp/channel/example_channel.tsp @@ -0,0 +1,22 @@ +import "./model.tsp"; +import "../../models/common/model.tsp"; + +const exampleChannel: Channel = #{ + kind: "Channel", + id: "019466a2-1234-7abc-9def-0123456789ab", + href: "/api/hyperfleet/v1/channels/019466a2-1234-7abc-9def-0123456789ab", + name: "stable", + labels: #{ tier: "production" }, + spec: #{ + is_default: true, + enabled_regex: "^4\\.\\d+\\.\\d+$", + }, + generation: 1, + status: #{ + conditions: #[], + }, + created_time: "2025-06-01T00:00:00Z", + updated_time: "2025-06-01T10:02:00Z", + created_by: "user-123@example.com", + updated_by: "user-123@example.com", +}; diff --git a/models-gcp/channel/example_patch.tsp b/models-gcp/channel/example_patch.tsp new file mode 100644 index 0000000..481bfb3 --- /dev/null +++ b/models-gcp/channel/example_patch.tsp @@ -0,0 +1,9 @@ +import "./model.tsp"; + +const exampleChannelPatchRequest: ChannelPatchRequest = #{ + spec: #{ + is_default: false, + enabled_regex: "^4\\.17\\.\\d+$", + }, + labels: #{ tier: "staging" }, +}; diff --git a/models-gcp/channel/example_post.tsp b/models-gcp/channel/example_post.tsp new file mode 100644 index 0000000..da36a93 --- /dev/null +++ b/models-gcp/channel/example_post.tsp @@ -0,0 +1,11 @@ +import "./model.tsp"; + +const exampleChannelCreateRequest: ChannelCreateRequest = #{ + kind: "Channel", + name: "stable", + labels: #{ tier: "production" }, + spec: #{ + is_default: true, + enabled_regex: "^4\\.\\d+\\.\\d+$", + }, +}; diff --git a/models-gcp/channel/model.tsp b/models-gcp/channel/model.tsp new file mode 100644 index 0000000..84130f3 --- /dev/null +++ b/models-gcp/channel/model.tsp @@ -0,0 +1,55 @@ +import "@typespec/openapi"; +import "../../models/common/model.tsp"; +import "../../models/statuses/model.tsp"; +import "../../models/resource/model.tsp"; + +using OpenAPI; + +alias KindChannel = "Channel"; + +model ChannelSpec { + /** Whether this is the default channel for new clusters */ + is_default: boolean; + + /** Regex pattern for matching enabled version strings */ + enabled_regex: string; +} + +model ChannelBase { + ...APIResource; + + @minLength(1) + @maxLength(63) + @pattern("^[a-z0-9]([-a-z0-9]*[a-z0-9])?$") + name: string; + + spec: ChannelSpec; +} + +@example(exampleChannel) +model Channel { + ...ChannelBase; + ...APIMetadata; + + @minValue(1) + generation: int32; + + status: ResourceStatus; +} + +@example(exampleChannelCreateRequest) +model ChannelCreateRequest { + ...ChannelBase; +} + +@extension("minProperties", 1) +@extension("additionalProperties", false) +@example(exampleChannelPatchRequest) +model ChannelPatchRequest { + spec?: ChannelSpec; + labels?: Record; +} + +model ChannelList { + ...List; +} diff --git a/models-gcp/version/example_patch.tsp b/models-gcp/version/example_patch.tsp new file mode 100644 index 0000000..a242719 --- /dev/null +++ b/models-gcp/version/example_patch.tsp @@ -0,0 +1,11 @@ +import "./model.tsp"; + +const exampleVersionPatchRequest: VersionPatchRequest = #{ + spec: #{ + raw_version: "4.17.12", + enabled: false, + is_default: false, + release_image: "quay.io/openshift-release-dev/ocp-release:4.17.12-multi", + }, + labels: #{ deprecated: "true" }, +}; diff --git a/models-gcp/version/example_post.tsp b/models-gcp/version/example_post.tsp new file mode 100644 index 0000000..7e1c2c5 --- /dev/null +++ b/models-gcp/version/example_post.tsp @@ -0,0 +1,13 @@ +import "./model.tsp"; + +const exampleVersionCreateRequest: VersionCreateRequest = #{ + kind: "Version", + name: "4.17.12", + labels: #{}, + spec: #{ + raw_version: "4.17.12", + enabled: true, + is_default: true, + release_image: "quay.io/openshift-release-dev/ocp-release:4.17.12-multi", + }, +}; diff --git a/models-gcp/version/example_version.tsp b/models-gcp/version/example_version.tsp new file mode 100644 index 0000000..671a980 --- /dev/null +++ b/models-gcp/version/example_version.tsp @@ -0,0 +1,29 @@ +import "./model.tsp"; +import "../../models/common/model.tsp"; + +const exampleVersion: Version = #{ + kind: "Version", + id: "019466a3-5678-7abc-9def-0123456789ab", + href: "/api/hyperfleet/v1/channels/019466a2-1234-7abc-9def-0123456789ab/versions/019466a3-5678-7abc-9def-0123456789ab", + name: "4.17.12", + labels: #{}, + spec: #{ + raw_version: "4.17.12", + enabled: true, + is_default: true, + release_image: "quay.io/openshift-release-dev/ocp-release:4.17.12-multi", + }, + generation: 1, + owner_references: #{ + id: "019466a2-1234-7abc-9def-0123456789ab", + kind: "Channel", + href: "/api/hyperfleet/v1/channels/019466a2-1234-7abc-9def-0123456789ab", + }, + status: #{ + conditions: #[], + }, + created_time: "2025-06-01T00:00:00Z", + updated_time: "2025-06-01T10:02:00Z", + created_by: "user-123@example.com", + updated_by: "user-123@example.com", +}; diff --git a/models-gcp/version/model.tsp b/models-gcp/version/model.tsp new file mode 100644 index 0000000..a2602ae --- /dev/null +++ b/models-gcp/version/model.tsp @@ -0,0 +1,67 @@ +import "@typespec/openapi"; +import "@typespec/http"; +import "../../models/common/model.tsp"; +import "../../models/statuses/model.tsp"; +import "../../models/resource/model.tsp"; + +using OpenAPI; +using Http; + +alias KindVersion = "Version"; + +model VersionSpec { + /** Raw version string (e.g., "4.17.12") */ + raw_version: string; + + /** Whether this version is enabled for provisioning */ + enabled: boolean; + + /** Whether this is the default version for its channel */ + is_default: boolean; + + /** Container image reference for the release */ + release_image: string; + + /** When this version reaches end of life */ + @format("date-time") end_of_life_time?: string; +} + +model VersionBase { + ...APIResource; + + @minLength(1) + @maxLength(63) + name: string; + + spec: VersionSpec; +} + +@example(exampleVersion) +model Version { + ...VersionBase; + ...APIMetadata; + + @minValue(1) + generation: int32; + + owner_references: ObjectReference; + + status: ResourceStatus; +} + +@example(exampleVersionCreateRequest) +model VersionCreateRequest { + ...VersionBase; +} + +@extension("minProperties", 1) +@extension("additionalProperties", false) +@example(exampleVersionPatchRequest) +model VersionPatchRequest { + spec?: VersionSpec; + labels?: Record; +} + +model VersionList { + ...List; +} diff --git a/models/resource/example_patch.tsp b/models/resource/example_patch.tsp new file mode 100644 index 0000000..1905fa1 --- /dev/null +++ b/models/resource/example_patch.tsp @@ -0,0 +1,6 @@ +import "./model.tsp"; + +const exampleResourcePatchRequest: ResourcePatchRequest = #{ + spec: #{}, + labels: #{ env: "staging" }, +}; diff --git a/models/resource/example_post.tsp b/models/resource/example_post.tsp new file mode 100644 index 0000000..4cfec50 --- /dev/null +++ b/models/resource/example_post.tsp @@ -0,0 +1,8 @@ +import "./model.tsp"; + +const exampleResourceCreateRequest: ResourceCreateRequest = #{ + kind: "MyResource", + name: "my-resource-1", + spec: #{}, + labels: #{ environment: "production", team: "platform" }, +}; diff --git a/models/resource/example_resource.tsp b/models/resource/example_resource.tsp new file mode 100644 index 0000000..cf59102 --- /dev/null +++ b/models/resource/example_resource.tsp @@ -0,0 +1,19 @@ +import "./model.tsp"; +import "../common/model.tsp"; + +const exampleResource: Resource = #{ + kind: "MyResource", + id: "019466a0-8f8e-7abc-9def-0123456789ab", + href: "/api/hyperfleet/v1/resources/019466a0-8f8e-7abc-9def-0123456789ab", + name: "my-resource-1", + labels: #{ environment: "production", team: "platform" }, + spec: #{}, + generation: 1, + status: #{ + conditions: #[], + }, + created_time: "2025-06-01T00:00:00Z", + updated_time: "2025-06-01T10:02:00Z", + created_by: "user-123@example.com", + updated_by: "user-123@example.com", +}; diff --git a/models/resource/model.tsp b/models/resource/model.tsp new file mode 100644 index 0000000..1aa2f1d --- /dev/null +++ b/models/resource/model.tsp @@ -0,0 +1,90 @@ +import "@typespec/openapi"; +import "../common/model.tsp"; +import "../statuses/model.tsp"; +import "./example_resource.tsp"; +import "./example_post.tsp"; +import "./example_patch.tsp"; + +using OpenAPI; + +/** + * Aggregated status of the resource, populated by the status aggregation + * pipeline from adapter condition reports. + */ +model ResourceStatus { + conditions: ResourceCondition[]; +} + +@example(exampleResource) +model Resource { + /** Resource identifier (UUID v7) */ + id: Identifier; + + /** Entity type discriminator */ + kind: string; + + /** Resource name (unique per kind, or per kind+owner for child entities) */ + @minLength(1) + @maxLength(253) + name: string; + + /** Resource URI (computed at creation time) */ + href?: string; + + /** Entity-specific payload, validated at runtime against the entity's spec schema */ + spec: Record; + + /** Key-value pairs for filtering and grouping */ + labels?: Record; + + status: ResourceStatus; + + /** Incremented on spec or label changes */ + @minValue(1) + generation: int32; + + /** Parent resource reference (present only on child entities) */ + owner_references?: ObjectReference; + + /** Non-ownership associations to other resources, keyed by reference type */ + references?: Record; + + ...APIMetadata; +} + +@example(exampleResourceCreateRequest) +model ResourceCreateRequest { + /** Entity type discriminator */ + kind: string; + + /** Resource name */ + @minLength(1) + @maxLength(253) + name: string; + + /** Entity-specific payload */ + spec: Record; + + /** Key-value pairs for filtering and grouping */ + labels?: Record; + + /** Non-ownership associations to other resources */ + references?: Record; +} + +@extension("minProperties", 1) +@extension("additionalProperties", false) +@example(exampleResourcePatchRequest) +model ResourcePatchRequest { + spec?: Record; + labels?: Record; + references?: Record; +} + +model ResourceList { + kind: string; + page: int32; + size: int32; + total: int64; + items: Resource[]; +} diff --git a/schemas/core/openapi.yaml b/schemas/core/openapi.yaml index b2f415d..d36e851 100644 --- a/schemas/core/openapi.yaml +++ b/schemas/core/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: HyperFleet API - version: 1.0.16 + version: 1.0.17 contact: name: HyperFleet Team url: https://github.com/openshift-hyperfleet @@ -18,6 +18,8 @@ tags: - name: Clusters - name: Cluster statuses - name: NodePool statuses + - name: Resource statuses + - name: Resources - name: NodePools paths: /api/hyperfleet/v1/clusters: @@ -576,6 +578,46 @@ paths: security: - BearerAuth: [] /api/hyperfleet/v1/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses: + get: + operationId: getNodePoolsStatuses + summary: List all adapter statuses for nodepools + description: Returns adapter status reports for this nodepool + parameters: + - name: cluster_id + in: path + required: true + description: Cluster ID + schema: + type: string + - name: nodepool_id + in: path + required: true + schema: + type: string + - $ref: '#/components/parameters/SearchParams' + - $ref: '#/components/parameters/QueryParams.page' + - $ref: '#/components/parameters/QueryParams.pageSize' + - $ref: '#/components/parameters/QueryParams.orderBy' + - $ref: '#/components/parameters/QueryParams.order' + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/AdapterStatusList' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - NodePool statuses + security: + - BearerAuth: [] put: operationId: putNodePoolStatuses summary: Adapter creates or updates nodepool status @@ -616,10 +658,11 @@ paths: $ref: '#/components/schemas/AdapterStatusCreateRequest' security: - BearerAuth: [] + /api/hyperfleet/v1/clusters/{cluster_id}/statuses: get: - operationId: getNodePoolsStatuses - summary: List all adapter statuses for nodepools - description: Returns adapter status reports for this nodepool + operationId: getClusterStatuses + summary: List all adapter statuses for cluster + description: Returns adapter status reports for this cluster parameters: - name: cluster_id in: path @@ -627,11 +670,6 @@ paths: description: Cluster ID schema: type: string - - name: nodepool_id - in: path - required: true - schema: - type: string - $ref: '#/components/parameters/SearchParams' - $ref: '#/components/parameters/QueryParams.page' - $ref: '#/components/parameters/QueryParams.pageSize' @@ -646,15 +684,12 @@ paths: $ref: '#/components/schemas/AdapterStatusList' '400': description: The server could not understand the request due to invalid syntax. - default: - description: An unexpected error response. - content: - application/problem+json: - schema: - $ref: '#/components/schemas/Error' + '404': + description: The server cannot find the requested resource. tags: - - NodePool statuses - /api/hyperfleet/v1/clusters/{cluster_id}/statuses: + - Cluster statuses + security: + - BearerAuth: [] put: operationId: putClusterStatuses summary: Adapter creates or updates cluster status @@ -689,17 +724,12 @@ paths: $ref: '#/components/schemas/AdapterStatusCreateRequest' security: - BearerAuth: [] + /api/hyperfleet/v1/nodepools: get: - operationId: getClusterStatuses - summary: List all adapter statuses for cluster - description: Returns adapter status reports for this cluster + operationId: getNodePools + summary: List all nodepools for cluster + description: Returns the list of all nodepools parameters: - - name: cluster_id - in: path - required: true - description: Cluster ID - schema: - type: string - $ref: '#/components/parameters/SearchParams' - $ref: '#/components/parameters/QueryParams.page' - $ref: '#/components/parameters/QueryParams.pageSize' @@ -711,21 +741,238 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/AdapterStatusList' + $ref: '#/components/schemas/NodePoolList' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - NodePools + security: + - BearerAuth: [] + /api/hyperfleet/v1/resources: + get: + operationId: getResources + summary: List resources + description: Returns a paginated list of all resources, optionally filtered by kind, labels, or TSL query. + parameters: + - $ref: '#/components/parameters/SearchParams' + - $ref: '#/components/parameters/QueryParams.page' + - $ref: '#/components/parameters/QueryParams.pageSize' + - $ref: '#/components/parameters/QueryParams.orderBy' + - $ref: '#/components/parameters/QueryParams.order' + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceList' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - Resources + security: + - BearerAuth: [] + post: + operationId: postResource + summary: Create resource + description: |- + Create a new resource. Only top-level entity types (no parent) can be created + via this endpoint. Child entities must use the nested route under their parent. + parameters: [] + responses: + '201': + description: The request has succeeded and a new resource has been created as a result. + content: + application/json: + schema: + $ref: '#/components/schemas/Resource' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - Resources + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceCreateRequest' + security: + - BearerAuth: [] + /api/hyperfleet/v1/resources/{resource_id}: + get: + operationId: getResourceById + summary: Get resource by ID + description: Returns a single resource by its ID. + parameters: + - $ref: '#/components/parameters/SearchParams' + - name: resource_id + in: path + required: true + schema: + type: string + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/Resource' '400': description: The server could not understand the request due to invalid syntax. '404': description: The server cannot find the requested resource. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' tags: - - Cluster statuses + - Resources security: - BearerAuth: [] - /api/hyperfleet/v1/nodepools: + patch: + operationId: patchResourceById + summary: Patch resource by ID + description: Patch a resource by ID. Supports partial updates to spec, labels, and references. + parameters: + - name: resource_id + in: path + required: true + schema: + type: string + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/Resource' + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - Resources + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ResourcePatchRequest' + security: + - BearerAuth: [] + delete: + operationId: deleteResourceById + summary: Request resource deletion + description: |- + Marks the resource for deletion. Child resources are handled per their + OnParentDelete policy (cascade or restrict). Returns 409 if a restrict-policy + child exists or if another resource holds a reference to this one. + parameters: + - name: resource_id + in: path + required: true + schema: + type: string + responses: + '202': + description: The request has been accepted for processing, but processing has not yet completed. + content: + application/json: + schema: + $ref: '#/components/schemas/Resource' + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - Resources + security: + - BearerAuth: [] + /api/hyperfleet/v1/resources/{resource_id}/force-delete: + post: + operationId: forceDeleteResource + summary: Force-delete a resource + description: |- + Permanently removes the resource record from the database for a resource stuck in Finalizing state. + This is a database-only operation. Requires a reason for audit purposes. + parameters: + - name: resource_id + in: path + required: true + schema: + type: string + responses: + '204': + description: 'There is no content to send for this request, but the headers may be useful. ' + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - Resources + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ForceDeleteRequest' + security: + - BearerAuth: [] + /api/hyperfleet/v1/resources/{resource_id}/statuses: get: - operationId: getNodePools - summary: List all nodepools for cluster - description: Returns the list of all nodepools + operationId: getResourceStatuses + summary: List resource statuses + description: Returns adapter statuses for a resource. parameters: + - name: resource_id + in: path + required: true + schema: + type: string - $ref: '#/components/parameters/SearchParams' - $ref: '#/components/parameters/QueryParams.page' - $ref: '#/components/parameters/QueryParams.pageSize' @@ -737,9 +984,11 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/NodePoolList' + $ref: '#/components/schemas/AdapterStatusList' '400': description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. default: description: An unexpected error response. content: @@ -747,7 +996,40 @@ paths: schema: $ref: '#/components/schemas/Error' tags: - - NodePools + - Resource statuses + security: + - BearerAuth: [] + put: + operationId: putResourceStatuses + summary: Adapter creates or updates resource status + description: Adapters call this endpoint to report status for a resource after each evaluation. The adapter's status entry is created if it doesn't exist, or updated if it does (upserted by adapter name). + parameters: + - name: resource_id + in: path + required: true + schema: + type: string + responses: + '201': + description: The request has succeeded and a new resource has been created as a result. + content: + application/json: + schema: + $ref: '#/components/schemas/AdapterStatus' + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. + tags: + - Resource statuses + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AdapterStatusCreateRequest' security: - BearerAuth: [] components: @@ -1680,6 +1962,101 @@ components: enum: - asc - desc + Resource: + type: object + required: + - id + - kind + - name + - spec + - status + - generation + - created_time + - updated_time + - created_by + - updated_by + properties: + id: + type: string + description: Resource identifier (UUID v7) + kind: + type: string + description: Entity type discriminator + name: + type: string + minLength: 1 + maxLength: 253 + description: Resource name (unique per kind, or per kind+owner for child entities) + href: + type: string + description: Resource URI (computed at creation time) + spec: + type: object + additionalProperties: {} + description: Entity-specific payload, validated at runtime against the entity's spec schema + labels: + type: object + additionalProperties: + type: string + description: Key-value pairs for filtering and grouping + status: + $ref: '#/components/schemas/ResourceStatus' + generation: + type: integer + format: int32 + minimum: 1 + description: Incremented on spec or label changes + owner_references: + allOf: + - $ref: '#/components/schemas/ObjectReference' + description: Parent resource reference (present only on child entities) + references: + type: object + additionalProperties: + type: array + items: + $ref: '#/components/schemas/ObjectReference' + description: Non-ownership associations to other resources, keyed by reference type + created_time: + type: string + format: date-time + description: Timestamp when the resource was created + updated_time: + type: string + format: date-time + description: Timestamp when the resource was last updated + created_by: + type: string + format: email + description: Identity that created the resource + updated_by: + type: string + format: email + description: Identity that last updated the resource + deleted_time: + type: string + format: date-time + description: Timestamp when deletion was requested; omitted if not marked for deletion + deleted_by: + type: string + format: email + description: Identity that requested deletion; omitted if not marked for deletion + example: + kind: MyResource + id: 019466a0-8f8e-7abc-9def-0123456789ab + href: /api/hyperfleet/v1/resources/019466a0-8f8e-7abc-9def-0123456789ab + name: my-resource-1 + labels: + environment: production + team: platform + spec: {} + generation: 1 + status: + conditions: [] + created_time: '2025-06-01T00:00:00Z' + updated_time: '2025-06-01T10:02:00Z' + created_by: user-123@example.com + updated_by: user-123@example.com ResourceCondition: type: object required: @@ -1732,6 +2109,102 @@ components: - 'True' - 'False' description: Status value for resource conditions + ResourceCreateRequest: + type: object + required: + - kind + - name + - spec + properties: + kind: + type: string + description: Entity type discriminator + name: + type: string + minLength: 1 + maxLength: 253 + description: Resource name + spec: + type: object + additionalProperties: {} + description: Entity-specific payload + labels: + type: object + additionalProperties: + type: string + description: Key-value pairs for filtering and grouping + references: + type: object + additionalProperties: + type: array + items: + $ref: '#/components/schemas/ObjectReference' + description: Non-ownership associations to other resources + example: + kind: MyResource + name: my-resource-1 + spec: {} + labels: + environment: production + team: platform + ResourceList: + type: object + required: + - kind + - page + - size + - total + - items + properties: + kind: + type: string + page: + type: integer + format: int32 + size: + type: integer + format: int32 + total: + type: integer + format: int64 + items: + type: array + items: + $ref: '#/components/schemas/Resource' + ResourcePatchRequest: + type: object + properties: + spec: + type: object + additionalProperties: {} + labels: + type: object + additionalProperties: + type: string + references: + type: object + additionalProperties: + type: array + items: + $ref: '#/components/schemas/ObjectReference' + example: + spec: {} + labels: + env: staging + additionalProperties: false + minProperties: 1 + ResourceStatus: + type: object + required: + - conditions + properties: + conditions: + type: array + items: + $ref: '#/components/schemas/ResourceCondition' + description: |- + Aggregated status of the resource, populated by the status aggregation + pipeline from adapter condition reports. ValidationError: type: object required: diff --git a/schemas/core/swagger.yaml b/schemas/core/swagger.yaml index 7f9af8c..ff67847 100644 --- a/schemas/core/swagger.yaml +++ b/schemas/core/swagger.yaml @@ -17,7 +17,7 @@ info: name: Apache 2.0 url: 'https://www.apache.org/licenses/LICENSE-2.0' title: HyperFleet API - version: 1.0.16 + version: 1.0.17 host: hyperfleet.redhat.com basePath: / schemes: @@ -722,6 +722,8 @@ paths: description: An unexpected error response. schema: $ref: '#/definitions/Error' + security: + - BearerAuth: [] tags: - NodePool statuses description: Returns adapter status reports for this nodepool @@ -930,6 +932,363 @@ paths: description: Returns the list of all nodepools operationId: getNodePools summary: List all nodepools for cluster + /api/hyperfleet/v1/resources: + get: + produces: + - application/json + - application/problem+json + parameters: + - description: >- + Filter results using TSL (Tree Search Language) query syntax. + + Examples: `status.conditions.Reconciled='True'`, `name in + ('c1','c2')`, `labels.region='us-east'` + in: query + name: search + required: false + type: string + - default: 1 + format: int32 + in: query + name: page + required: false + type: integer + - default: 20 + format: int32 + in: query + name: pageSize + required: false + type: integer + - default: created_time + in: query + name: orderBy + required: false + type: string + - enum: + - asc + - desc + in: query + name: order + required: false + type: string + responses: + '200': + description: The request has succeeded. + schema: + $ref: '#/definitions/ResourceList' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - Resources + description: >- + Returns a paginated list of all resources, optionally filtered by kind, + labels, or TSL query. + operationId: getResources + summary: List resources + post: + consumes: + - application/json + produces: + - application/json + - application/problem+json + parameters: + - in: body + name: body + required: true + schema: + $ref: '#/definitions/ResourceCreateRequest' + responses: + '201': + description: >- + The request has succeeded and a new resource has been created as a + result. + schema: + $ref: '#/definitions/Resource' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - Resources + description: >- + Create a new resource. Only top-level entity types (no parent) can be + created + + via this endpoint. Child entities must use the nested route under their + parent. + operationId: postResource + summary: Create resource + '/api/hyperfleet/v1/resources/{resource_id}': + delete: + produces: + - application/json + - application/problem+json + parameters: + - in: path + name: resource_id + required: true + type: string + responses: + '202': + description: >- + The request has been accepted for processing, but processing has not + yet completed. + schema: + $ref: '#/definitions/Resource' + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - Resources + description: >- + Marks the resource for deletion. Child resources are handled per their + + OnParentDelete policy (cascade or restrict). Returns 409 if a + restrict-policy + + child exists or if another resource holds a reference to this one. + operationId: deleteResourceById + summary: Request resource deletion + get: + produces: + - application/json + - application/problem+json + parameters: + - description: >- + Filter results using TSL (Tree Search Language) query syntax. + + Examples: `status.conditions.Reconciled='True'`, `name in + ('c1','c2')`, `labels.region='us-east'` + in: query + name: search + required: false + type: string + - in: path + name: resource_id + required: true + type: string + responses: + '200': + description: The request has succeeded. + schema: + $ref: '#/definitions/Resource' + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - Resources + description: Returns a single resource by its ID. + operationId: getResourceById + summary: Get resource by ID + patch: + consumes: + - application/json + produces: + - application/json + - application/problem+json + parameters: + - in: path + name: resource_id + required: true + type: string + - in: body + name: body + required: true + schema: + $ref: '#/definitions/ResourcePatchRequest' + responses: + '200': + description: The request has succeeded. + schema: + $ref: '#/definitions/Resource' + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - Resources + description: >- + Patch a resource by ID. Supports partial updates to spec, labels, and + references. + operationId: patchResourceById + summary: Patch resource by ID + '/api/hyperfleet/v1/resources/{resource_id}/force-delete': + post: + consumes: + - application/json + produces: + - application/problem+json + parameters: + - in: path + name: resource_id + required: true + type: string + - in: body + name: body + required: true + schema: + $ref: '#/definitions/ForceDeleteRequest' + responses: + '204': + description: >- + There is no content to send for this request, but the headers may be + useful. + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - Resources + description: >- + Permanently removes the resource record from the database for a resource + stuck in Finalizing state. + + This is a database-only operation. Requires a reason for audit purposes. + operationId: forceDeleteResource + summary: Force-delete a resource + '/api/hyperfleet/v1/resources/{resource_id}/statuses': + get: + produces: + - application/json + - application/problem+json + parameters: + - in: path + name: resource_id + required: true + type: string + - description: >- + Filter results using TSL (Tree Search Language) query syntax. + + Examples: `status.conditions.Reconciled='True'`, `name in + ('c1','c2')`, `labels.region='us-east'` + in: query + name: search + required: false + type: string + - default: 1 + format: int32 + in: query + name: page + required: false + type: integer + - default: 20 + format: int32 + in: query + name: pageSize + required: false + type: integer + - default: created_time + in: query + name: orderBy + required: false + type: string + - enum: + - asc + - desc + in: query + name: order + required: false + type: string + responses: + '200': + description: The request has succeeded. + schema: + $ref: '#/definitions/AdapterStatusList' + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - Resource statuses + description: Returns adapter statuses for a resource. + operationId: getResourceStatuses + summary: List resource statuses + put: + consumes: + - application/json + produces: + - application/json + parameters: + - in: path + name: resource_id + required: true + type: string + - in: body + name: body + required: true + schema: + $ref: '#/definitions/AdapterStatusCreateRequest' + responses: + '201': + description: >- + The request has succeeded and a new resource has been created as a + result. + schema: + $ref: '#/definitions/AdapterStatus' + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. + security: + - BearerAuth: [] + tags: + - Resource statuses + description: >- + Adapters call this endpoint to report status for a resource after each + evaluation. The adapter's status entry is created if it doesn't exist, + or updated if it does (upserted by adapter name). + operationId: putResourceStatuses + summary: Adapter creates or updates resource status definitions: AdapterCondition: description: >- @@ -1870,6 +2229,105 @@ definitions: - asc - desc type: string + Resource: + example: + created_by: user-123@example.com + created_time: '2025-06-01T00:00:00Z' + generation: 1 + href: /api/hyperfleet/v1/resources/019466a0-8f8e-7abc-9def-0123456789ab + id: 019466a0-8f8e-7abc-9def-0123456789ab + kind: MyResource + labels: + environment: production + team: platform + name: my-resource-1 + spec: {} + status: + conditions: [] + updated_by: user-123@example.com + updated_time: '2025-06-01T10:02:00Z' + properties: + created_by: + description: Identity that created the resource + format: email + type: string + created_time: + description: Timestamp when the resource was created + format: date-time + type: string + deleted_by: + description: Identity that requested deletion; omitted if not marked for deletion + format: email + type: string + deleted_time: + description: >- + Timestamp when deletion was requested; omitted if not marked for + deletion + format: date-time + type: string + generation: + description: Incremented on spec or label changes + format: int32 + minimum: 1 + type: integer + href: + description: Resource URI (computed at creation time) + type: string + id: + description: Resource identifier (UUID v7) + type: string + kind: + description: Entity type discriminator + type: string + labels: + additionalProperties: + type: string + description: Key-value pairs for filtering and grouping + type: object + name: + description: 'Resource name (unique per kind, or per kind+owner for child entities)' + maxLength: 253 + minLength: 1 + type: string + owner_references: + allOf: + - $ref: '#/definitions/ObjectReference' + description: Parent resource reference (present only on child entities) + references: + additionalProperties: + items: + $ref: '#/definitions/ObjectReference' + type: array + description: 'Non-ownership associations to other resources, keyed by reference type' + type: object + spec: + additionalProperties: {} + description: >- + Entity-specific payload, validated at runtime against the entity's + spec schema + type: object + status: + $ref: '#/definitions/ResourceStatus' + updated_by: + description: Identity that last updated the resource + format: email + type: string + updated_time: + description: Timestamp when the resource was last updated + format: date-time + type: string + required: + - id + - kind + - name + - spec + - status + - generation + - created_time + - updated_time + - created_by + - updated_by + type: object ResourceCondition: description: >- Condition in Cluster/NodePool status @@ -1931,6 +2389,102 @@ definitions: - 'True' - 'False' type: string + ResourceCreateRequest: + example: + kind: MyResource + labels: + environment: production + team: platform + name: my-resource-1 + spec: {} + properties: + kind: + description: Entity type discriminator + type: string + labels: + additionalProperties: + type: string + description: Key-value pairs for filtering and grouping + type: object + name: + description: Resource name + maxLength: 253 + minLength: 1 + type: string + references: + additionalProperties: + items: + $ref: '#/definitions/ObjectReference' + type: array + description: Non-ownership associations to other resources + type: object + spec: + additionalProperties: {} + description: Entity-specific payload + type: object + required: + - kind + - name + - spec + type: object + ResourceList: + properties: + items: + items: + $ref: '#/definitions/Resource' + type: array + kind: + type: string + page: + format: int32 + type: integer + size: + format: int32 + type: integer + total: + format: int64 + type: integer + required: + - kind + - page + - size + - total + - items + type: object + ResourcePatchRequest: + additionalProperties: false + example: + labels: + env: staging + spec: {} + minProperties: 1 + properties: + labels: + additionalProperties: + type: string + type: object + references: + additionalProperties: + items: + $ref: '#/definitions/ObjectReference' + type: array + type: object + spec: + additionalProperties: {} + type: object + type: object + ResourceStatus: + description: |- + Aggregated status of the resource, populated by the status aggregation + pipeline from adapter condition reports. + properties: + conditions: + items: + $ref: '#/definitions/ResourceCondition' + type: array + required: + - conditions + type: object ValidationError: description: Field-level validation error detail properties: @@ -1971,6 +2525,8 @@ tags: - name: Clusters - name: Cluster statuses - name: NodePool statuses + - name: Resource statuses + - name: Resources - name: NodePools x-components: parameters: diff --git a/schemas/gcp/openapi.yaml b/schemas/gcp/openapi.yaml index 0f1fde3..7e98065 100644 --- a/schemas/gcp/openapi.yaml +++ b/schemas/gcp/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: HyperFleet API - version: 1.0.16 + version: 1.0.17 contact: name: HyperFleet Team url: https://github.com/openshift-hyperfleet @@ -16,15 +16,16 @@ info: Adapters handle the specifics of managing spec tags: - name: Clusters - - name: Cluster statuses - - name: NodePool statuses + - name: Channels + - name: Versions - name: NodePools + - name: Resources paths: - /api/hyperfleet/v1/clusters: + /api/hyperfleet/v1/channels: get: - operationId: getClusters - summary: List clusters - description: Returns a list of all clusters. + operationId: getChannels + summary: List channels + description: Returns a paginated list of channels, optionally filtered by labels or TSL query. parameters: - $ref: '#/components/parameters/SearchParams' - $ref: '#/components/parameters/QueryParams.page' @@ -37,7 +38,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ClusterList' + $ref: '#/components/schemas/ChannelList' '400': description: The server could not understand the request due to invalid syntax. default: @@ -47,18 +48,13 @@ paths: schema: $ref: '#/components/schemas/Error' tags: - - Clusters + - Channels security: - BearerAuth: [] post: - operationId: postCluster - summary: Create cluster - description: |- - Create a new cluster resource. - - **Note**: The `status` object in the response is read-only and computed by the service. - It is NOT part of the request body. Initially, - status.conditions will include mandatory "LastKnownReconciled" and "Reconciled" conditions. + operationId: postChannel + summary: Create channel + description: Creates a new channel. parameters: [] responses: '201': @@ -66,7 +62,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Cluster' + $ref: '#/components/schemas/Channel' '400': description: The server could not understand the request due to invalid syntax. default: @@ -76,23 +72,23 @@ paths: schema: $ref: '#/components/schemas/Error' tags: - - Clusters + - Channels requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/ClusterCreateRequest' + $ref: '#/components/schemas/ChannelCreateRequest' security: - BearerAuth: [] - /api/hyperfleet/v1/clusters/{cluster_id}: + /api/hyperfleet/v1/channels/{channel_id}: get: - operationId: getClusterById - summary: Get cluster by ID - description: Returns a single cluster by its ID. + operationId: getChannelById + summary: Get channel by ID + description: Returns a single channel by its ID. parameters: - $ref: '#/components/parameters/SearchParams' - - name: cluster_id + - name: channel_id in: path required: true schema: @@ -103,9 +99,11 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Cluster' + $ref: '#/components/schemas/Channel' '400': description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. default: description: An unexpected error response. content: @@ -113,18 +111,17 @@ paths: schema: $ref: '#/components/schemas/Error' tags: - - Clusters + - Channels security: - BearerAuth: [] patch: - operationId: patchClusterById - summary: Patch cluster by ID - description: Patch a specific cluster by ID + operationId: patchChannelById + summary: Patch channel by ID + description: Patches a channel by ID. Supports partial updates to spec and labels. parameters: - - name: cluster_id + - name: channel_id in: path required: true - description: Cluster ID schema: type: string responses: @@ -133,7 +130,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Cluster' + $ref: '#/components/schemas/Channel' '400': description: The server could not understand the request due to invalid syntax. '404': @@ -147,24 +144,21 @@ paths: schema: $ref: '#/components/schemas/Error' tags: - - Clusters + - Channels requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/ClusterPatchRequest' + $ref: '#/components/schemas/ChannelPatchRequest' security: - BearerAuth: [] delete: - operationId: deleteClusterById - summary: Request cluster deletion - description: |- - Marks the cluster for deletion by setting deleted_time to the current time, cascades to its nodepools. - The cluster remains in the database until it is fully deleted. - Returns the updated cluster with generation incremented. + operationId: deleteChannelById + summary: Request channel deletion + description: Marks the channel for deletion. Returns 409 if versions still exist (RESTRICT policy). parameters: - - name: cluster_id + - name: channel_id in: path required: true schema: @@ -175,81 +169,13 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Cluster' - example: - kind: Cluster - id: 019466a0-8f8e-7abc-9def-0123456789ab - href: https://api.hyperfleet.com/v1/clusters/019466a0-8f8e-7abc-9def-0123456789ab - name: cluster-123 - labels: - environment: production - team: platform - spec: - platform: - type: gcp - gcp: - projectID: project-123 - region: us-central1 - zone: us-central1-a - network: network-123 - subnet: subnet-123 - release: - image: registry.redhat.io/openshift4/ose-cluster-version-operator:v4.22.0-ec.4 - version: 4.22.0-ec.4 - channelGroup: candidate - networking: - clusterNetwork: - - cidr: 10.10.0.0/16 - hostPrefix: 24 - serviceNetwork: - - 10.96.0.0/12 - dns: - baseDomain: example.com - generation: 2 - status: - conditions: - - type: Reconciled - status: 'True' - reason: ReconciledAll - message: All required adapters reported Available=True or Finalized=True at the current generation - observed_generation: 2 - created_time: '2021-01-01T10:00:00Z' - last_updated_time: '2021-01-01T10:00:00Z' - last_transition_time: '2021-01-01T10:00:00Z' - - type: LastKnownReconciled - status: 'True' - reason: AllAdaptersReconciled - message: All required adapters report Available=True for the tracked generation - observed_generation: 2 - created_time: '2021-01-01T10:00:00Z' - last_updated_time: '2021-01-01T10:00:00Z' - last_transition_time: '2021-01-01T10:00:00Z' - - type: Adapter1Successful - status: 'True' - reason: This adapter1 is available - message: This adapter1 is available - observed_generation: 2 - created_time: '2021-01-01T10:00:00Z' - last_updated_time: '2021-01-01T10:00:00Z' - last_transition_time: '2021-01-01T10:00:00Z' - - type: Adapter2Successful - status: 'True' - reason: This adapter2 is available - message: This adapter2 is available - observed_generation: 2 - created_time: '2021-01-01T10:01:00Z' - last_updated_time: '2021-01-01T10:01:00Z' - last_transition_time: '2021-01-01T10:01:00Z' - created_time: '2021-01-01T00:00:00Z' - updated_time: '2021-01-01T10:02:00Z' - deleted_time: '2021-01-01T10:05:00Z' - created_by: user-123@example.com - updated_by: user-123@example.com - deleted_by: user-123@example.com + $ref: '#/components/schemas/Channel' '400': description: The server could not understand the request due to invalid syntax. '404': description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. default: description: An unexpected error response. content: @@ -257,19 +183,18 @@ paths: schema: $ref: '#/components/schemas/Error' tags: - - Clusters + - Channels security: - BearerAuth: [] - /api/hyperfleet/v1/clusters/{cluster_id}/nodepools: + /api/hyperfleet/v1/channels/{channel_id}/versions: get: - operationId: getNodePoolsByClusterId - summary: List all nodepools for cluster - description: Returns the list of all nodepools for a cluster + operationId: getVersionsByChannelId + summary: List versions for channel + description: Returns a paginated list of versions for a channel. parameters: - - name: cluster_id + - name: channel_id in: path required: true - description: Cluster ID schema: type: string - $ref: '#/components/parameters/SearchParams' @@ -283,7 +208,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/NodePoolList' + $ref: '#/components/schemas/VersionList' '400': description: The server could not understand the request due to invalid syntax. default: @@ -293,18 +218,17 @@ paths: schema: $ref: '#/components/schemas/Error' tags: - - NodePools + - Versions security: - BearerAuth: [] post: - operationId: createNodePool - summary: Create nodepool - description: Create a NodePool for a cluster + operationId: postVersion + summary: Create version + description: Creates a new version under a channel. parameters: - - name: cluster_id + - name: channel_id in: path required: true - description: Cluster ID schema: type: string responses: @@ -313,11 +237,9 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/NodePoolCreateResponse' + $ref: '#/components/schemas/Version' '400': description: The server could not understand the request due to invalid syntax. - '409': - description: The request conflicts with the current state of the server. default: description: An unexpected error response. content: @@ -325,31 +247,29 @@ paths: schema: $ref: '#/components/schemas/Error' tags: - - NodePools + - Versions requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/NodePoolCreateRequest' + $ref: '#/components/schemas/VersionCreateRequest' security: - BearerAuth: [] - /api/hyperfleet/v1/clusters/{cluster_id}/nodepools/{nodepool_id}: + /api/hyperfleet/v1/channels/{channel_id}/versions/{version_id}: get: - operationId: getNodePoolById - summary: Get nodepool by ID - description: Returns specific nodepool + operationId: getVersionById + summary: Get version by ID + description: Returns a single version by its ID within a channel. parameters: - - name: cluster_id + - name: channel_id in: path required: true - description: Cluster ID schema: type: string - - name: nodepool_id + - name: version_id in: path required: true - description: NodePool ID schema: type: string responses: @@ -358,9 +278,11 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/NodePool' + $ref: '#/components/schemas/Version' '400': description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. default: description: An unexpected error response. content: @@ -368,112 +290,37 @@ paths: schema: $ref: '#/components/schemas/Error' tags: - - NodePools + - Versions security: - BearerAuth: [] - delete: - operationId: deleteNodePoolById - summary: Request nodepool deletion - description: |- - Marks the nodepool for deletion by setting deleted_time and deleted_by. Does not affect the parent cluster. - Returns the updated nodepool with generation incremented. + patch: + operationId: patchVersionById + summary: Patch version by ID + description: Patch a version by ID. Supports partial updates to spec and labels. parameters: - - name: cluster_id + - name: channel_id in: path required: true - description: Cluster ID schema: type: string - - name: nodepool_id + - name: version_id in: path required: true - description: NodePool ID schema: type: string responses: - '202': - description: The request has been accepted for processing, but processing has not yet completed. + '200': + description: The request has succeeded. content: application/json: schema: - $ref: '#/components/schemas/NodePool' - example: - kind: NodePool - id: 019466a1-2b3c-7def-8abc-456789abcdef - href: https://api.hyperfleet.com/v1/nodepools/019466a1-2b3c-7def-8abc-456789abcdef - name: worker-pool-1 - labels: - environment: production - pooltype: worker - generation: 2 - spec: - platform: - type: gcp - gcp: - machineType: n1-standard-4 - diskSize: 100 - diskType: pd-standard - zones: - - us-central1-a - - us-central1-b - preemptible: false - labels: - team: platform - managedby: hyperfleet - nodeCount: 3 - autoscaling: - enabled: true - minNodes: 1 - maxNodes: 10 - targetCPUUtilization: 80 - owner_references: - id: 019466a0-8f8e-7abc-9def-0123456789ab - kind: Cluster - href: https://api.hyperfleet.com/v1/clusters/019466a0-8f8e-7abc-9def-0123456789ab - status: - conditions: - - type: Reconciled - status: 'True' - reason: ReconciledAll - message: All required adapters reported Available=True or Finalized=True at the current generation - observed_generation: 2 - created_time: '2021-01-01T10:00:00Z' - last_updated_time: '2021-01-01T10:00:00Z' - last_transition_time: '2021-01-01T10:00:00Z' - - type: LastKnownReconciled - status: 'True' - reason: AllAdaptersReconciled - message: All required adapters report Available=True for the tracked generation - observed_generation: 2 - created_time: '2021-01-01T10:00:00Z' - last_updated_time: '2021-01-01T10:00:00Z' - last_transition_time: '2021-01-01T10:00:00Z' - - type: ValidationSuccessful - status: 'True' - reason: All validations passed - message: NodePool validation passed - observed_generation: 2 - created_time: '2021-01-01T10:00:00Z' - last_updated_time: '2021-01-01T10:00:00Z' - last_transition_time: '2021-01-01T10:00:00Z' - - type: NodePoolSuccessful - status: 'True' - reason: NodePool provisioned successfully - message: NodePool has 3 nodes running - observed_generation: 2 - created_time: '2021-01-01T10:01:00Z' - last_updated_time: '2021-01-01T10:01:00Z' - last_transition_time: '2021-01-01T10:01:00Z' - created_time: '2021-01-01T00:00:00Z' - updated_time: '2021-01-01T10:02:00Z' - deleted_time: '2021-01-01T10:05:00Z' - created_by: user-123@example.com - updated_by: user-123@example.com - deleted_by: user-123@example.com + $ref: '#/components/schemas/Version' '400': description: The server could not understand the request due to invalid syntax. '404': description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. default: description: An unexpected error response. content: @@ -481,33 +328,37 @@ paths: schema: $ref: '#/components/schemas/Error' tags: - - NodePools + - Versions + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/VersionPatchRequest' security: - BearerAuth: [] - patch: - operationId: patchNodePoolById - summary: Patch nodepool by ID - description: Patch a specific nodepool within a cluster + delete: + operationId: deleteVersionById + summary: Request version deletion + description: Marks a version for deletion. parameters: - - name: cluster_id + - name: channel_id in: path required: true - description: Cluster ID schema: type: string - - name: nodepool_id + - name: version_id in: path required: true - description: NodePool ID schema: type: string responses: - '200': - description: The request has succeeded. + '202': + description: The request has been accepted for processing, but processing has not yet completed. content: application/json: schema: - $ref: '#/components/schemas/NodePool' + $ref: '#/components/schemas/Version' '400': description: The server could not understand the request due to invalid syntax. '404': @@ -521,46 +372,129 @@ paths: schema: $ref: '#/components/schemas/Error' tags: - - NodePools + - Versions + security: + - BearerAuth: [] + /api/hyperfleet/v1/clusters: + get: + operationId: getClusters + summary: List clusters + description: Returns a list of all clusters. + parameters: + - $ref: '#/components/parameters/SearchParams' + - $ref: '#/components/parameters/QueryParams.page' + - $ref: '#/components/parameters/QueryParams.pageSize' + - $ref: '#/components/parameters/QueryParams.orderBy' + - $ref: '#/components/parameters/QueryParams.order' + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/ClusterList' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - Clusters + security: + - BearerAuth: [] + post: + operationId: postCluster + summary: Create cluster + description: |- + Create a new cluster resource. + + **Note**: The `status` object in the response is read-only and computed by the service. + It is NOT part of the request body. Initially, + status.conditions will include mandatory "LastKnownReconciled" and "Reconciled" conditions. + parameters: [] + responses: + '201': + description: The request has succeeded and a new resource has been created as a result. + content: + application/json: + schema: + $ref: '#/components/schemas/Cluster' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - Clusters requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/NodePoolPatchRequest' + $ref: '#/components/schemas/ClusterCreateRequest' security: - BearerAuth: [] - /api/hyperfleet/v1/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses: + /api/hyperfleet/v1/clusters/{cluster_id}: get: - operationId: getNodePoolsStatuses - summary: List all adapter statuses for nodepools - description: Returns adapter status reports for this nodepool + operationId: getClusterById + summary: Get cluster by ID + description: Returns a single cluster by its ID. parameters: + - $ref: '#/components/parameters/SearchParams' - name: cluster_id in: path required: true - description: Cluster ID schema: type: string - - name: nodepool_id + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/Cluster' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - Clusters + security: + - BearerAuth: [] + patch: + operationId: patchClusterById + summary: Patch cluster by ID + description: Patch a specific cluster by ID + parameters: + - name: cluster_id in: path required: true + description: Cluster ID schema: type: string - - $ref: '#/components/parameters/SearchParams' - - $ref: '#/components/parameters/QueryParams.page' - - $ref: '#/components/parameters/QueryParams.pageSize' - - $ref: '#/components/parameters/QueryParams.orderBy' - - $ref: '#/components/parameters/QueryParams.order' responses: '200': description: The request has succeeded. content: application/json: schema: - $ref: '#/components/schemas/AdapterStatusList' + $ref: '#/components/schemas/Cluster' '400': description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. default: description: An unexpected error response. content: @@ -568,59 +502,579 @@ paths: schema: $ref: '#/components/schemas/Error' tags: - - NodePool statuses - /api/hyperfleet/v1/clusters/{cluster_id}/statuses: - get: - operationId: getClusterStatuses - summary: List all adapter statuses for cluster - description: Returns adapter status reports for this cluster + - Clusters + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ClusterPatchRequest' + security: + - BearerAuth: [] + delete: + operationId: deleteClusterById + summary: Request cluster deletion + description: |- + Marks the cluster for deletion by setting deleted_time to the current time, cascades to its nodepools. + The cluster remains in the database until it is fully deleted. + Returns the updated cluster with generation incremented. parameters: - name: cluster_id in: path required: true - description: Cluster ID schema: type: string - - $ref: '#/components/parameters/SearchParams' - - $ref: '#/components/parameters/QueryParams.page' - - $ref: '#/components/parameters/QueryParams.pageSize' - - $ref: '#/components/parameters/QueryParams.orderBy' - - $ref: '#/components/parameters/QueryParams.order' responses: - '200': - description: The request has succeeded. + '202': + description: The request has been accepted for processing, but processing has not yet completed. content: application/json: schema: - $ref: '#/components/schemas/AdapterStatusList' + $ref: '#/components/schemas/Cluster' + example: + kind: Cluster + id: 019466a0-8f8e-7abc-9def-0123456789ab + href: https://api.hyperfleet.com/v1/clusters/019466a0-8f8e-7abc-9def-0123456789ab + name: cluster-123 + labels: + environment: production + team: platform + spec: + platform: + type: gcp + gcp: + projectID: project-123 + region: us-central1 + zone: us-central1-a + network: network-123 + subnet: subnet-123 + release: + image: registry.redhat.io/openshift4/ose-cluster-version-operator:v4.22.0-ec.4 + version: 4.22.0-ec.4 + channelGroup: candidate + networking: + clusterNetwork: + - cidr: 10.10.0.0/16 + hostPrefix: 24 + serviceNetwork: + - 10.96.0.0/12 + dns: + baseDomain: example.com + generation: 2 + status: + conditions: + - type: Reconciled + status: 'True' + reason: ReconciledAll + message: All required adapters reported Available=True or Finalized=True at the current generation + observed_generation: 2 + created_time: '2021-01-01T10:00:00Z' + last_updated_time: '2021-01-01T10:00:00Z' + last_transition_time: '2021-01-01T10:00:00Z' + - type: LastKnownReconciled + status: 'True' + reason: AllAdaptersReconciled + message: All required adapters report Available=True for the tracked generation + observed_generation: 2 + created_time: '2021-01-01T10:00:00Z' + last_updated_time: '2021-01-01T10:00:00Z' + last_transition_time: '2021-01-01T10:00:00Z' + - type: Adapter1Successful + status: 'True' + reason: This adapter1 is available + message: This adapter1 is available + observed_generation: 2 + created_time: '2021-01-01T10:00:00Z' + last_updated_time: '2021-01-01T10:00:00Z' + last_transition_time: '2021-01-01T10:00:00Z' + - type: Adapter2Successful + status: 'True' + reason: This adapter2 is available + message: This adapter2 is available + observed_generation: 2 + created_time: '2021-01-01T10:01:00Z' + last_updated_time: '2021-01-01T10:01:00Z' + last_transition_time: '2021-01-01T10:01:00Z' + created_time: '2021-01-01T00:00:00Z' + updated_time: '2021-01-01T10:02:00Z' + deleted_time: '2021-01-01T10:05:00Z' + created_by: user-123@example.com + updated_by: user-123@example.com + deleted_by: user-123@example.com '400': description: The server could not understand the request due to invalid syntax. '404': description: The server cannot find the requested resource. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' tags: - - Cluster statuses + - Clusters security: - BearerAuth: [] - /api/hyperfleet/v1/nodepools: + /api/hyperfleet/v1/clusters/{cluster_id}/nodepools: get: - operationId: getNodePools + operationId: getNodePoolsByClusterId summary: List all nodepools for cluster - description: Returns the list of all nodepools + description: Returns the list of all nodepools for a cluster parameters: + - name: cluster_id + in: path + required: true + description: Cluster ID + schema: + type: string - $ref: '#/components/parameters/SearchParams' - $ref: '#/components/parameters/QueryParams.page' - $ref: '#/components/parameters/QueryParams.pageSize' - $ref: '#/components/parameters/QueryParams.orderBy' - $ref: '#/components/parameters/QueryParams.order' responses: - '200': - description: The request has succeeded. + '200': + description: The request has succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/NodePoolList' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - NodePools + security: + - BearerAuth: [] + post: + operationId: createNodePool + summary: Create nodepool + description: Create a NodePool for a cluster + parameters: + - name: cluster_id + in: path + required: true + description: Cluster ID + schema: + type: string + responses: + '201': + description: The request has succeeded and a new resource has been created as a result. + content: + application/json: + schema: + $ref: '#/components/schemas/NodePoolCreateResponse' + '400': + description: The server could not understand the request due to invalid syntax. + '409': + description: The request conflicts with the current state of the server. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - NodePools + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NodePoolCreateRequest' + security: + - BearerAuth: [] + /api/hyperfleet/v1/clusters/{cluster_id}/nodepools/{nodepool_id}: + get: + operationId: getNodePoolById + summary: Get nodepool by ID + description: Returns specific nodepool + parameters: + - name: cluster_id + in: path + required: true + description: Cluster ID + schema: + type: string + - name: nodepool_id + in: path + required: true + description: NodePool ID + schema: + type: string + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/NodePool' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - NodePools + security: + - BearerAuth: [] + delete: + operationId: deleteNodePoolById + summary: Request nodepool deletion + description: |- + Marks the nodepool for deletion by setting deleted_time and deleted_by. Does not affect the parent cluster. + Returns the updated nodepool with generation incremented. + parameters: + - name: cluster_id + in: path + required: true + description: Cluster ID + schema: + type: string + - name: nodepool_id + in: path + required: true + description: NodePool ID + schema: + type: string + responses: + '202': + description: The request has been accepted for processing, but processing has not yet completed. + content: + application/json: + schema: + $ref: '#/components/schemas/NodePool' + example: + kind: NodePool + id: 019466a1-2b3c-7def-8abc-456789abcdef + href: https://api.hyperfleet.com/v1/nodepools/019466a1-2b3c-7def-8abc-456789abcdef + name: worker-pool-1 + labels: + environment: production + pooltype: worker + generation: 2 + spec: + platform: + type: gcp + gcp: + machineType: n1-standard-4 + diskSize: 100 + diskType: pd-standard + zones: + - us-central1-a + - us-central1-b + preemptible: false + labels: + team: platform + managedby: hyperfleet + nodeCount: 3 + autoscaling: + enabled: true + minNodes: 1 + maxNodes: 10 + targetCPUUtilization: 80 + owner_references: + id: 019466a0-8f8e-7abc-9def-0123456789ab + kind: Cluster + href: https://api.hyperfleet.com/v1/clusters/019466a0-8f8e-7abc-9def-0123456789ab + status: + conditions: + - type: Reconciled + status: 'True' + reason: ReconciledAll + message: All required adapters reported Available=True or Finalized=True at the current generation + observed_generation: 2 + created_time: '2021-01-01T10:00:00Z' + last_updated_time: '2021-01-01T10:00:00Z' + last_transition_time: '2021-01-01T10:00:00Z' + - type: LastKnownReconciled + status: 'True' + reason: AllAdaptersReconciled + message: All required adapters report Available=True for the tracked generation + observed_generation: 2 + created_time: '2021-01-01T10:00:00Z' + last_updated_time: '2021-01-01T10:00:00Z' + last_transition_time: '2021-01-01T10:00:00Z' + - type: ValidationSuccessful + status: 'True' + reason: All validations passed + message: NodePool validation passed + observed_generation: 2 + created_time: '2021-01-01T10:00:00Z' + last_updated_time: '2021-01-01T10:00:00Z' + last_transition_time: '2021-01-01T10:00:00Z' + - type: NodePoolSuccessful + status: 'True' + reason: NodePool provisioned successfully + message: NodePool has 3 nodes running + observed_generation: 2 + created_time: '2021-01-01T10:01:00Z' + last_updated_time: '2021-01-01T10:01:00Z' + last_transition_time: '2021-01-01T10:01:00Z' + created_time: '2021-01-01T00:00:00Z' + updated_time: '2021-01-01T10:02:00Z' + deleted_time: '2021-01-01T10:05:00Z' + created_by: user-123@example.com + updated_by: user-123@example.com + deleted_by: user-123@example.com + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - NodePools + security: + - BearerAuth: [] + patch: + operationId: patchNodePoolById + summary: Patch nodepool by ID + description: Patch a specific nodepool within a cluster + parameters: + - name: cluster_id + in: path + required: true + description: Cluster ID + schema: + type: string + - name: nodepool_id + in: path + required: true + description: NodePool ID + schema: + type: string + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/NodePool' + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - NodePools + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NodePoolPatchRequest' + security: + - BearerAuth: [] + /api/hyperfleet/v1/nodepools: + get: + operationId: getNodePools + summary: List all nodepools for cluster + description: Returns the list of all nodepools + parameters: + - $ref: '#/components/parameters/SearchParams' + - $ref: '#/components/parameters/QueryParams.page' + - $ref: '#/components/parameters/QueryParams.pageSize' + - $ref: '#/components/parameters/QueryParams.orderBy' + - $ref: '#/components/parameters/QueryParams.order' + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/NodePoolList' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - NodePools + security: + - BearerAuth: [] + /api/hyperfleet/v1/resources: + get: + operationId: getResources + summary: List resources + description: Returns a paginated list of all resources, optionally filtered by kind, labels, or TSL query. + parameters: + - $ref: '#/components/parameters/SearchParams' + - $ref: '#/components/parameters/QueryParams.page' + - $ref: '#/components/parameters/QueryParams.pageSize' + - $ref: '#/components/parameters/QueryParams.orderBy' + - $ref: '#/components/parameters/QueryParams.order' + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceList' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - Resources + security: + - BearerAuth: [] + post: + operationId: postResource + summary: Create resource + description: |- + Create a new resource. Only top-level entity types (no parent) can be created + via this endpoint. Child entities must use the nested route under their parent. + parameters: [] + responses: + '201': + description: The request has succeeded and a new resource has been created as a result. + content: + application/json: + schema: + $ref: '#/components/schemas/Resource' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - Resources + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceCreateRequest' + security: + - BearerAuth: [] + /api/hyperfleet/v1/resources/{resource_id}: + get: + operationId: getResourceById + summary: Get resource by ID + description: Returns a single resource by its ID. + parameters: + - $ref: '#/components/parameters/SearchParams' + - name: resource_id + in: path + required: true + schema: + type: string + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/Resource' + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - Resources + security: + - BearerAuth: [] + patch: + operationId: patchResourceById + summary: Patch resource by ID + description: Patch a resource by ID. Supports partial updates to spec, labels, and references. + parameters: + - name: resource_id + in: path + required: true + schema: + type: string + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/Resource' + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. + default: + description: An unexpected error response. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Error' + tags: + - Resources + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ResourcePatchRequest' + security: + - BearerAuth: [] + delete: + operationId: deleteResourceById + summary: Request resource deletion + description: |- + Marks the resource for deletion. Child resources are handled per their + OnParentDelete policy (cascade or restrict). Returns 409 if a restrict-policy + child exists or if another resource holds a reference to this one. + parameters: + - name: resource_id + in: path + required: true + schema: + type: string + responses: + '202': + description: The request has been accepted for processing, but processing has not yet completed. content: application/json: schema: - $ref: '#/components/schemas/NodePoolList' + $ref: '#/components/schemas/Resource' '400': description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. default: description: An unexpected error response. content: @@ -628,7 +1082,7 @@ paths: schema: $ref: '#/components/schemas/Error' tags: - - NodePools + - Resources security: - BearerAuth: [] components: @@ -688,141 +1142,159 @@ components: count: type: integer minimum: 1 - AdapterCondition: + AutoscalingSpec: + type: object + properties: + enabled: + type: boolean + minNodes: + type: integer + minimum: 0 + maxNodes: + type: integer + minimum: 1 + targetCPUUtilization: + type: integer + minimum: 1 + maximum: 100 + targetMemoryUtilization: + type: integer + minimum: 1 + maximum: 100 + scaleDownDelay: + type: string + scaleUpDelay: + type: string + BearerAuth: type: object required: - type - - last_transition_time - - status + - scheme properties: type: type: string - description: Condition type - reason: - type: string - description: Machine-readable reason code - message: - type: string - description: Human-readable message - last_transition_time: + enum: + - http + scheme: type: string - format: date-time - description: |- - When this condition last transitioned status (API-managed) - Only updated when status changes (True/False), not when reason/message changes - status: - $ref: '#/components/schemas/AdapterConditionStatus' - description: |- - Condition in AdapterStatus - Used for standard Kubernetes condition types: "Available", "Applied", "Health", "Finalized" - Note: observed_generation is at AdapterStatus level, not per-condition, - since all conditions in one AdapterStatus share the same observed generation - AdapterConditionStatus: - type: string - enum: - - 'True' - - 'False' - - Unknown - description: Status value for adapter conditions - AdapterStatus: + enum: + - bearer + Channel: type: object required: - - adapter - - observed_generation - - conditions + - name + - spec - created_time - - last_report_time + - updated_time + - created_by + - updated_by + - generation + - status properties: - adapter: + id: type: string - description: Adapter name (e.g., "validator", "dns", "provisioner") - observed_generation: - type: integer - format: int32 - description: Which generation of the resource this status reflects - metadata: - type: object - properties: - job_name: - type: string - job_namespace: - type: string - attempt: - type: integer - format: int32 - started_time: - type: string - format: date-time - completed_time: - type: string - format: date-time - duration: - type: string - description: Job execution metadata - data: + description: Resource identifier + kind: + type: string + description: Resource kind + href: + type: string + description: Resource URI + labels: type: object - additionalProperties: {} - description: Adapter-specific data (structure varies by adapter type) - conditions: - type: array - items: - $ref: '#/components/schemas/AdapterCondition' - description: |- - Kubernetes-style conditions tracking adapter state - Typically includes: Available, Applied, Health, Finalized + additionalProperties: + type: string + description: labels for the API resource as pairs of name:value strings + name: + type: string + minLength: 1 + maxLength: 63 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + spec: + $ref: '#/components/schemas/ChannelSpec' created_time: type: string format: date-time - description: When this adapter status was first created (API-managed) - last_report_time: + description: Timestamp when the resource was created + updated_time: type: string format: date-time - description: |- - When this adapter last reported its status (API-managed) - Updated every time the adapter PUTs, even if conditions haven't changed - Used by Sentinel to detect adapter liveness - description: |- - AdapterStatus represents the complete status report from an adapter - Contains multiple conditions, job metadata, and adapter-specific data + description: Timestamp when the resource was last updated + created_by: + type: string + format: email + description: Identity that created the resource + updated_by: + type: string + format: email + description: Identity that last updated the resource + deleted_time: + type: string + format: date-time + description: Timestamp when deletion was requested; omitted if not marked for deletion + deleted_by: + type: string + format: email + description: Identity that requested deletion; omitted if not marked for deletion + generation: + type: integer + format: int32 + minimum: 1 + status: + $ref: '#/components/schemas/ResourceStatus' example: - adapter: adapter1 - observed_generation: 1 - conditions: - - type: Available - status: 'True' - reason: This adapter1 is available - message: This adapter1 is available - last_transition_time: '2021-01-01T10:00:00Z' - - type: Applied - status: 'True' - reason: Validation job applied - message: Adapter1 validation job applied successfully - last_transition_time: '2021-01-01T10:00:00Z' - - type: Health - status: 'True' - reason: All adapter1 operations completed successfully - message: All adapter1 runtime operations completed successfully - last_transition_time: '2021-01-01T10:00:00Z' - - type: Finalized - status: 'True' - reason: All resources deleted; cleanup confirmed - message: All resources deleted; cleanup confirmed - last_transition_time: '2021-01-01T10:00:00Z' - metadata: - job_name: validator-job-abc123 - job_namespace: hyperfleet-system - attempt: 1 - started_time: '2021-01-01T10:00:00Z' - completed_time: '2021-01-01T10:02:00Z' - duration: 2m - data: - validation_results: - total_tests: 30 - passed: 30 - failed: 0 - created_time: '2021-01-01T10:00:00Z' - last_report_time: '2021-01-01T10:02:00Z' - AdapterStatusList: + kind: Channel + id: 019466a2-1234-7abc-9def-0123456789ab + href: /api/hyperfleet/v1/channels/019466a2-1234-7abc-9def-0123456789ab + name: stable + labels: + tier: production + spec: + is_default: true + enabled_regex: ^4\.\d+\.\d+$ + generation: 1 + status: + conditions: [] + created_time: '2025-06-01T00:00:00Z' + updated_time: '2025-06-01T10:02:00Z' + created_by: user-123@example.com + updated_by: user-123@example.com + ChannelCreateRequest: + type: object + required: + - name + - spec + properties: + id: + type: string + description: Resource identifier + kind: + type: string + description: Resource kind + href: + type: string + description: Resource URI + labels: + type: object + additionalProperties: + type: string + description: labels for the API resource as pairs of name:value strings + name: + type: string + minLength: 1 + maxLength: 63 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + spec: + $ref: '#/components/schemas/ChannelSpec' + example: + kind: Channel + name: stable + labels: + tier: production + spec: + is_default: true + enabled_regex: ^4\.\d+\.\d+$ + ChannelList: type: object required: - kind @@ -845,74 +1317,45 @@ components: items: type: array items: - $ref: '#/components/schemas/AdapterStatus' - description: List of adapter statuses with pagination metadata + $ref: '#/components/schemas/Channel' + ChannelPatchRequest: + type: object + properties: + spec: + $ref: '#/components/schemas/ChannelSpecUpdate' + labels: + type: object + additionalProperties: + type: string example: - kind: AdapterStatusList - page: 1 - size: 2 - total: 2 - items: - - adapter: adapter1 - observed_generation: 1 - conditions: - - type: Available - status: 'True' - reason: This adapter1 is available - message: This adapter1 is available - last_transition_time: '2021-01-01T10:00:00Z' - metadata: - job_name: validator-job-abc123 - duration: 2m - created_time: '2021-01-01T10:00:00Z' - last_report_time: '2021-01-01T10:02:00Z' - - adapter: adapter2 - observed_generation: 1 - conditions: - - type: Available - status: 'True' - reason: This adapter2 is available - message: This adapter2 is available - last_transition_time: '2021-01-01T10:01:00Z' - created_time: '2021-01-01T10:01:00Z' - last_report_time: '2021-01-01T10:01:30Z' - AutoscalingSpec: + spec: + is_default: false + enabled_regex: ^4\.17\.\d+$ + labels: + tier: staging + additionalProperties: false + minProperties: 1 + ChannelSpec: type: object + required: + - is_default + - enabled_regex properties: - enabled: + is_default: type: boolean - minNodes: - type: integer - minimum: 0 - maxNodes: - type: integer - minimum: 1 - targetCPUUtilization: - type: integer - minimum: 1 - maximum: 100 - targetMemoryUtilization: - type: integer - minimum: 1 - maximum: 100 - scaleDownDelay: - type: string - scaleUpDelay: + description: Whether this is the default channel for new clusters + enabled_regex: type: string - BearerAuth: + description: Regex pattern for matching enabled version strings + ChannelSpecUpdate: type: object - required: - - type - - scheme properties: - type: - type: string - enum: - - http - scheme: + is_default: + type: boolean + description: Whether this is the default channel for new clusters + enabled_regex: type: string - enum: - - bearer + description: Regex pattern for matching enabled version strings Cluster: type: object required: @@ -1738,27 +2181,122 @@ components: properties: id: type: string - description: Resource identifier - kind: + description: Resource identifier + kind: + type: string + description: Resource kind + href: + type: string + description: Resource URI + OrderDirection: + type: string + enum: + - asc + - desc + ReleaseSpec: + type: object + properties: + image: + type: string + version: + type: string + channelGroup: + type: string + Resource: + type: object + required: + - id + - kind + - name + - spec + - status + - generation + - created_time + - updated_time + - created_by + - updated_by + properties: + id: + type: string + description: Resource identifier (UUID v7) + kind: + type: string + description: Entity type discriminator + name: + type: string + minLength: 1 + maxLength: 253 + description: Resource name (unique per kind, or per kind+owner for child entities) + href: + type: string + description: Resource URI (computed at creation time) + spec: + type: object + additionalProperties: {} + description: Entity-specific payload, validated at runtime against the entity's spec schema + labels: + type: object + additionalProperties: + type: string + description: Key-value pairs for filtering and grouping + status: + $ref: '#/components/schemas/ResourceStatus' + generation: + type: integer + format: int32 + minimum: 1 + description: Incremented on spec or label changes + owner_references: + allOf: + - $ref: '#/components/schemas/ObjectReference' + description: Parent resource reference (present only on child entities) + references: + type: object + additionalProperties: + type: array + items: + $ref: '#/components/schemas/ObjectReference' + description: Non-ownership associations to other resources, keyed by reference type + created_time: + type: string + format: date-time + description: Timestamp when the resource was created + updated_time: type: string - description: Resource kind - href: + format: date-time + description: Timestamp when the resource was last updated + created_by: type: string - description: Resource URI - OrderDirection: - type: string - enum: - - asc - - desc - ReleaseSpec: - type: object - properties: - image: + format: email + description: Identity that created the resource + updated_by: type: string - version: + format: email + description: Identity that last updated the resource + deleted_time: type: string - channelGroup: + format: date-time + description: Timestamp when deletion was requested; omitted if not marked for deletion + deleted_by: type: string + format: email + description: Identity that requested deletion; omitted if not marked for deletion + example: + kind: MyResource + id: 019466a0-8f8e-7abc-9def-0123456789ab + href: /api/hyperfleet/v1/resources/019466a0-8f8e-7abc-9def-0123456789ab + name: my-resource-1 + labels: + environment: production + team: platform + spec: {} + generation: 1 + status: + conditions: [] + created_time: '2025-06-01T00:00:00Z' + updated_time: '2025-06-01T10:02:00Z' + created_by: user-123@example.com + updated_by: user-123@example.com ResourceCondition: type: object required: @@ -1811,6 +2349,102 @@ components: - 'True' - 'False' description: Status value for resource conditions + ResourceCreateRequest: + type: object + required: + - kind + - name + - spec + properties: + kind: + type: string + description: Entity type discriminator + name: + type: string + minLength: 1 + maxLength: 253 + description: Resource name + spec: + type: object + additionalProperties: {} + description: Entity-specific payload + labels: + type: object + additionalProperties: + type: string + description: Key-value pairs for filtering and grouping + references: + type: object + additionalProperties: + type: array + items: + $ref: '#/components/schemas/ObjectReference' + description: Non-ownership associations to other resources + example: + kind: MyResource + name: my-resource-1 + spec: {} + labels: + environment: production + team: platform + ResourceList: + type: object + required: + - kind + - page + - size + - total + - items + properties: + kind: + type: string + page: + type: integer + format: int32 + size: + type: integer + format: int32 + total: + type: integer + format: int64 + items: + type: array + items: + $ref: '#/components/schemas/Resource' + ResourcePatchRequest: + type: object + properties: + spec: + type: object + additionalProperties: {} + labels: + type: object + additionalProperties: + type: string + references: + type: object + additionalProperties: + type: array + items: + $ref: '#/components/schemas/ObjectReference' + example: + spec: {} + labels: + env: staging + additionalProperties: false + minProperties: 1 + ResourceStatus: + type: object + required: + - conditions + properties: + conditions: + type: array + items: + $ref: '#/components/schemas/ResourceCondition' + description: |- + Aggregated status of the resource, populated by the status aggregation + pipeline from adapter condition reports. TaintSpec: type: object required: @@ -1858,6 +2492,214 @@ components: description: Human-readable error message for this field example: Cluster name is required description: Field-level validation error detail + Version: + type: object + required: + - name + - spec + - created_time + - updated_time + - created_by + - updated_by + - generation + - owner_references + - status + properties: + id: + type: string + description: Resource identifier + kind: + type: string + description: Resource kind + href: + type: string + description: Resource URI + labels: + type: object + additionalProperties: + type: string + description: labels for the API resource as pairs of name:value strings + name: + type: string + minLength: 1 + maxLength: 63 + spec: + $ref: '#/components/schemas/VersionSpec' + created_time: + type: string + format: date-time + description: Timestamp when the resource was created + updated_time: + type: string + format: date-time + description: Timestamp when the resource was last updated + created_by: + type: string + format: email + description: Identity that created the resource + updated_by: + type: string + format: email + description: Identity that last updated the resource + deleted_time: + type: string + format: date-time + description: Timestamp when deletion was requested; omitted if not marked for deletion + deleted_by: + type: string + format: email + description: Identity that requested deletion; omitted if not marked for deletion + generation: + type: integer + format: int32 + minimum: 1 + owner_references: + $ref: '#/components/schemas/ObjectReference' + status: + $ref: '#/components/schemas/ResourceStatus' + example: + kind: Version + id: 019466a3-5678-7abc-9def-0123456789ab + href: /api/hyperfleet/v1/channels/019466a2-1234-7abc-9def-0123456789ab/versions/019466a3-5678-7abc-9def-0123456789ab + name: 4.17.12 + labels: {} + spec: + raw_version: 4.17.12 + enabled: true + is_default: true + release_image: quay.io/openshift-release-dev/ocp-release:4.17.12-multi + generation: 1 + owner_references: + id: 019466a2-1234-7abc-9def-0123456789ab + kind: Channel + href: /api/hyperfleet/v1/channels/019466a2-1234-7abc-9def-0123456789ab + status: + conditions: [] + created_time: '2025-06-01T00:00:00Z' + updated_time: '2025-06-01T10:02:00Z' + created_by: user-123@example.com + updated_by: user-123@example.com + VersionCreateRequest: + type: object + required: + - name + - spec + properties: + id: + type: string + description: Resource identifier + kind: + type: string + description: Resource kind + href: + type: string + description: Resource URI + labels: + type: object + additionalProperties: + type: string + description: labels for the API resource as pairs of name:value strings + name: + type: string + minLength: 1 + maxLength: 63 + spec: + $ref: '#/components/schemas/VersionSpec' + example: + kind: Version + name: 4.17.12 + labels: {} + spec: + raw_version: 4.17.12 + enabled: true + is_default: true + release_image: quay.io/openshift-release-dev/ocp-release:4.17.12-multi + VersionList: + type: object + required: + - kind + - page + - size + - total + - items + properties: + kind: + type: string + page: + type: integer + format: int32 + size: + type: integer + format: int32 + total: + type: integer + format: int32 + items: + type: array + items: + $ref: '#/components/schemas/Version' + VersionPatchRequest: + type: object + properties: + spec: + $ref: '#/components/schemas/VersionSpecUpdate' + labels: + type: object + additionalProperties: + type: string + example: + spec: + raw_version: 4.17.12 + enabled: false + is_default: false + release_image: quay.io/openshift-release-dev/ocp-release:4.17.12-multi + labels: + deprecated: 'true' + additionalProperties: false + minProperties: 1 + VersionSpec: + type: object + required: + - raw_version + - enabled + - is_default + - release_image + properties: + raw_version: + type: string + description: Raw version string (e.g., "4.17.12") + enabled: + type: boolean + description: Whether this version is enabled for provisioning + is_default: + type: boolean + description: Whether this is the default version for its channel + release_image: + type: string + description: Container image reference for the release + end_of_life_time: + type: string + format: date-time + description: When this version reaches end of life + VersionSpecUpdate: + type: object + properties: + raw_version: + type: string + description: Raw version string (e.g., "4.17.12") + enabled: + type: boolean + description: Whether this version is enabled for provisioning + is_default: + type: boolean + description: Whether this is the default version for its channel + release_image: + type: string + description: Container image reference for the release + end_of_life_time: + type: string + format: date-time + description: When this version reaches end of life securitySchemes: BearerAuth: type: http diff --git a/schemas/gcp/swagger.yaml b/schemas/gcp/swagger.yaml index d9bb222..f96773d 100644 --- a/schemas/gcp/swagger.yaml +++ b/schemas/gcp/swagger.yaml @@ -17,13 +17,13 @@ info: name: Apache 2.0 url: 'https://www.apache.org/licenses/LICENSE-2.0' title: HyperFleet API - version: 1.0.16 + version: 1.0.17 host: hyperfleet.redhat.com basePath: / schemes: - https paths: - /api/hyperfleet/v1/clusters: + /api/hyperfleet/v1/channels: get: produces: - application/json @@ -66,7 +66,7 @@ paths: '200': description: The request has succeeded. schema: - $ref: '#/definitions/ClusterList' + $ref: '#/definitions/ChannelList' '400': description: The server could not understand the request due to invalid syntax. default: @@ -76,10 +76,12 @@ paths: security: - BearerAuth: [] tags: - - Clusters - description: Returns a list of all clusters. - operationId: getClusters - summary: List clusters + - Channels + description: >- + Returns a paginated list of channels, optionally filtered by labels or + TSL query. + operationId: getChannels + summary: List channels post: consumes: - application/json @@ -91,14 +93,14 @@ paths: name: body required: true schema: - $ref: '#/definitions/ClusterCreateRequest' + $ref: '#/definitions/ChannelCreateRequest' responses: '201': description: >- The request has succeeded and a new resource has been created as a result. schema: - $ref: '#/definitions/Cluster' + $ref: '#/definitions/Channel' '400': description: The server could not understand the request due to invalid syntax. default: @@ -108,28 +110,18 @@ paths: security: - BearerAuth: [] tags: - - Clusters - description: >- - Create a new cluster resource. - - - **Note**: The `status` object in the response is read-only and computed - by the service. - - It is NOT part of the request body. Initially, - - status.conditions will include mandatory "LastKnownReconciled" and - "Reconciled" conditions. - operationId: postCluster - summary: Create cluster - '/api/hyperfleet/v1/clusters/{cluster_id}': + - Channels + description: Creates a new channel. + operationId: postChannel + summary: Create channel + '/api/hyperfleet/v1/channels/{channel_id}': delete: produces: - application/json - application/problem+json parameters: - in: path - name: cluster_id + name: channel_id required: true type: string responses: @@ -137,89 +129,14 @@ paths: description: >- The request has been accepted for processing, but processing has not yet completed. - examples: - application/json: - created_by: user-123@example.com - created_time: '2021-01-01T00:00:00Z' - deleted_by: user-123@example.com - deleted_time: '2021-01-01T10:05:00Z' - generation: 2 - href: >- - https://api.hyperfleet.com/v1/clusters/019466a0-8f8e-7abc-9def-0123456789ab - id: 019466a0-8f8e-7abc-9def-0123456789ab - kind: Cluster - labels: - environment: production - team: platform - name: cluster-123 - spec: - dns: - baseDomain: example.com - networking: - clusterNetwork: - - cidr: 10.10.0.0/16 - hostPrefix: 24 - serviceNetwork: - - 10.96.0.0/12 - platform: - gcp: - network: network-123 - projectID: project-123 - region: us-central1 - subnet: subnet-123 - zone: us-central1-a - type: gcp - release: - channelGroup: candidate - image: >- - registry.redhat.io/openshift4/ose-cluster-version-operator:v4.22.0-ec.4 - version: 4.22.0-ec.4 - status: - conditions: - - created_time: '2021-01-01T10:00:00Z' - last_transition_time: '2021-01-01T10:00:00Z' - last_updated_time: '2021-01-01T10:00:00Z' - message: >- - All required adapters reported Available=True or - Finalized=True at the current generation - observed_generation: 2 - reason: ReconciledAll - status: 'True' - type: Reconciled - - created_time: '2021-01-01T10:00:00Z' - last_transition_time: '2021-01-01T10:00:00Z' - last_updated_time: '2021-01-01T10:00:00Z' - message: >- - All required adapters report Available=True for the - tracked generation - observed_generation: 2 - reason: AllAdaptersReconciled - status: 'True' - type: LastKnownReconciled - - created_time: '2021-01-01T10:00:00Z' - last_transition_time: '2021-01-01T10:00:00Z' - last_updated_time: '2021-01-01T10:00:00Z' - message: This adapter1 is available - observed_generation: 2 - reason: This adapter1 is available - status: 'True' - type: Adapter1Successful - - created_time: '2021-01-01T10:01:00Z' - last_transition_time: '2021-01-01T10:01:00Z' - last_updated_time: '2021-01-01T10:01:00Z' - message: This adapter2 is available - observed_generation: 2 - reason: This adapter2 is available - status: 'True' - type: Adapter2Successful - updated_by: user-123@example.com - updated_time: '2021-01-01T10:02:00Z' schema: - $ref: '#/definitions/Cluster' + $ref: '#/definitions/Channel' '400': description: The server could not understand the request due to invalid syntax. '404': description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. default: description: An unexpected error response. schema: @@ -227,16 +144,12 @@ paths: security: - BearerAuth: [] tags: - - Clusters + - Channels description: >- - Marks the cluster for deletion by setting deleted_time to the current - time, cascades to its nodepools. - - The cluster remains in the database until it is fully deleted. - - Returns the updated cluster with generation incremented. - operationId: deleteClusterById - summary: Request cluster deletion + Marks the channel for deletion. Returns 409 if versions still exist + (RESTRICT policy). + operationId: deleteChannelById + summary: Request channel deletion get: produces: - application/json @@ -252,16 +165,18 @@ paths: required: false type: string - in: path - name: cluster_id + name: channel_id required: true type: string responses: '200': description: The request has succeeded. schema: - $ref: '#/definitions/Cluster' + $ref: '#/definitions/Channel' '400': description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. default: description: An unexpected error response. schema: @@ -269,10 +184,10 @@ paths: security: - BearerAuth: [] tags: - - Clusters - description: Returns a single cluster by its ID. - operationId: getClusterById - summary: Get cluster by ID + - Channels + description: Returns a single channel by its ID. + operationId: getChannelById + summary: Get channel by ID patch: consumes: - application/json @@ -280,21 +195,20 @@ paths: - application/json - application/problem+json parameters: - - description: Cluster ID - in: path - name: cluster_id + - in: path + name: channel_id required: true type: string - in: body name: body required: true schema: - $ref: '#/definitions/ClusterPatchRequest' + $ref: '#/definitions/ChannelPatchRequest' responses: '200': description: The request has succeeded. schema: - $ref: '#/definitions/Cluster' + $ref: '#/definitions/Channel' '400': description: The server could not understand the request due to invalid syntax. '404': @@ -308,19 +222,18 @@ paths: security: - BearerAuth: [] tags: - - Clusters - description: Patch a specific cluster by ID - operationId: patchClusterById - summary: Patch cluster by ID - '/api/hyperfleet/v1/clusters/{cluster_id}/nodepools': + - Channels + description: Patches a channel by ID. Supports partial updates to spec and labels. + operationId: patchChannelById + summary: Patch channel by ID + '/api/hyperfleet/v1/channels/{channel_id}/versions': get: produces: - application/json - application/problem+json parameters: - - description: Cluster ID - in: path - name: cluster_id + - in: path + name: channel_id required: true type: string - description: >- @@ -360,7 +273,7 @@ paths: '200': description: The request has succeeded. schema: - $ref: '#/definitions/NodePoolList' + $ref: '#/definitions/VersionList' '400': description: The server could not understand the request due to invalid syntax. default: @@ -370,10 +283,10 @@ paths: security: - BearerAuth: [] tags: - - NodePools - description: Returns the list of all nodepools for a cluster - operationId: getNodePoolsByClusterId - summary: List all nodepools for cluster + - Versions + description: Returns a paginated list of versions for a channel. + operationId: getVersionsByChannelId + summary: List versions for channel post: consumes: - application/json @@ -381,27 +294,24 @@ paths: - application/json - application/problem+json parameters: - - description: Cluster ID - in: path - name: cluster_id + - in: path + name: channel_id required: true type: string - in: body name: body required: true schema: - $ref: '#/definitions/NodePoolCreateRequest' + $ref: '#/definitions/VersionCreateRequest' responses: '201': description: >- The request has succeeded and a new resource has been created as a result. schema: - $ref: '#/definitions/NodePoolCreateResponse' + $ref: '#/definitions/Version' '400': description: The server could not understand the request due to invalid syntax. - '409': - description: The request conflicts with the current state of the server. default: description: An unexpected error response. schema: @@ -409,24 +319,22 @@ paths: security: - BearerAuth: [] tags: - - NodePools - description: Create a NodePool for a cluster - operationId: createNodePool - summary: Create nodepool - '/api/hyperfleet/v1/clusters/{cluster_id}/nodepools/{nodepool_id}': + - Versions + description: Creates a new version under a channel. + operationId: postVersion + summary: Create version + '/api/hyperfleet/v1/channels/{channel_id}/versions/{version_id}': delete: produces: - application/json - application/problem+json parameters: - - description: Cluster ID - in: path - name: cluster_id + - in: path + name: channel_id required: true type: string - - description: NodePool ID - in: path - name: nodepool_id + - in: path + name: version_id required: true type: string responses: @@ -434,92 +342,14 @@ paths: description: >- The request has been accepted for processing, but processing has not yet completed. - examples: - application/json: - created_by: user-123@example.com - created_time: '2021-01-01T00:00:00Z' - deleted_by: user-123@example.com - deleted_time: '2021-01-01T10:05:00Z' - generation: 2 - href: >- - https://api.hyperfleet.com/v1/nodepools/019466a1-2b3c-7def-8abc-456789abcdef - id: 019466a1-2b3c-7def-8abc-456789abcdef - kind: NodePool - labels: - environment: production - pooltype: worker - name: worker-pool-1 - owner_references: - href: >- - https://api.hyperfleet.com/v1/clusters/019466a0-8f8e-7abc-9def-0123456789ab - id: 019466a0-8f8e-7abc-9def-0123456789ab - kind: Cluster - spec: - autoscaling: - enabled: true - maxNodes: 10 - minNodes: 1 - targetCPUUtilization: 80 - nodeCount: 3 - platform: - gcp: - diskSize: 100 - diskType: pd-standard - labels: - managedby: hyperfleet - team: platform - machineType: n1-standard-4 - preemptible: false - zones: - - us-central1-a - - us-central1-b - type: gcp - status: - conditions: - - created_time: '2021-01-01T10:00:00Z' - last_transition_time: '2021-01-01T10:00:00Z' - last_updated_time: '2021-01-01T10:00:00Z' - message: >- - All required adapters reported Available=True or - Finalized=True at the current generation - observed_generation: 2 - reason: ReconciledAll - status: 'True' - type: Reconciled - - created_time: '2021-01-01T10:00:00Z' - last_transition_time: '2021-01-01T10:00:00Z' - last_updated_time: '2021-01-01T10:00:00Z' - message: >- - All required adapters report Available=True for the - tracked generation - observed_generation: 2 - reason: AllAdaptersReconciled - status: 'True' - type: LastKnownReconciled - - created_time: '2021-01-01T10:00:00Z' - last_transition_time: '2021-01-01T10:00:00Z' - last_updated_time: '2021-01-01T10:00:00Z' - message: NodePool validation passed - observed_generation: 2 - reason: All validations passed - status: 'True' - type: ValidationSuccessful - - created_time: '2021-01-01T10:01:00Z' - last_transition_time: '2021-01-01T10:01:00Z' - last_updated_time: '2021-01-01T10:01:00Z' - message: NodePool has 3 nodes running - observed_generation: 2 - reason: NodePool provisioned successfully - status: 'True' - type: NodePoolSuccessful - updated_by: user-123@example.com - updated_time: '2021-01-01T10:02:00Z' schema: - $ref: '#/definitions/NodePool' + $ref: '#/definitions/Version' '400': description: The server could not understand the request due to invalid syntax. '404': description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. default: description: An unexpected error response. schema: @@ -527,36 +357,32 @@ paths: security: - BearerAuth: [] tags: - - NodePools - description: >- - Marks the nodepool for deletion by setting deleted_time and deleted_by. - Does not affect the parent cluster. - - Returns the updated nodepool with generation incremented. - operationId: deleteNodePoolById - summary: Request nodepool deletion + - Versions + description: Marks a version for deletion. + operationId: deleteVersionById + summary: Request version deletion get: produces: - application/json - application/problem+json parameters: - - description: Cluster ID - in: path - name: cluster_id + - in: path + name: channel_id required: true type: string - - description: NodePool ID - in: path - name: nodepool_id + - in: path + name: version_id required: true type: string responses: '200': description: The request has succeeded. schema: - $ref: '#/definitions/NodePool' + $ref: '#/definitions/Version' '400': description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. default: description: An unexpected error response. schema: @@ -564,10 +390,10 @@ paths: security: - BearerAuth: [] tags: - - NodePools - description: Returns specific nodepool - operationId: getNodePoolById - summary: Get nodepool by ID + - Versions + description: Returns a single version by its ID within a channel. + operationId: getVersionById + summary: Get version by ID patch: consumes: - application/json @@ -575,26 +401,24 @@ paths: - application/json - application/problem+json parameters: - - description: Cluster ID - in: path - name: cluster_id + - in: path + name: channel_id required: true type: string - - description: NodePool ID - in: path - name: nodepool_id + - in: path + name: version_id required: true type: string - in: body name: body required: true schema: - $ref: '#/definitions/NodePoolPatchRequest' + $ref: '#/definitions/VersionPatchRequest' responses: '200': description: The request has succeeded. schema: - $ref: '#/definitions/NodePool' + $ref: '#/definitions/Version' '400': description: The server could not understand the request due to invalid syntax. '404': @@ -608,25 +432,16 @@ paths: security: - BearerAuth: [] tags: - - NodePools - description: Patch a specific nodepool within a cluster - operationId: patchNodePoolById - summary: Patch nodepool by ID - '/api/hyperfleet/v1/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses': + - Versions + description: Patch a version by ID. Supports partial updates to spec and labels. + operationId: patchVersionById + summary: Patch version by ID + /api/hyperfleet/v1/clusters: get: produces: - application/json - application/problem+json parameters: - - description: Cluster ID - in: path - name: cluster_id - required: true - type: string - - in: path - name: nodepool_id - required: true - type: string - description: >- Filter results using TSL (Tree Search Language) query syntax. @@ -664,78 +479,177 @@ paths: '200': description: The request has succeeded. schema: - $ref: '#/definitions/AdapterStatusList' + $ref: '#/definitions/ClusterList' '400': description: The server could not understand the request due to invalid syntax. default: description: An unexpected error response. schema: $ref: '#/definitions/Error' + security: + - BearerAuth: [] tags: - - NodePool statuses - description: Returns adapter status reports for this nodepool - operationId: getNodePoolsStatuses - summary: List all adapter statuses for nodepools - '/api/hyperfleet/v1/clusters/{cluster_id}/statuses': - get: + - Clusters + description: Returns a list of all clusters. + operationId: getClusters + summary: List clusters + post: + consumes: + - application/json produces: - application/json + - application/problem+json parameters: - - description: Cluster ID - in: path - name: cluster_id + - in: body + name: body required: true - type: string - - description: >- - Filter results using TSL (Tree Search Language) query syntax. + schema: + $ref: '#/definitions/ClusterCreateRequest' + responses: + '201': + description: >- + The request has succeeded and a new resource has been created as a + result. + schema: + $ref: '#/definitions/Cluster' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - Clusters + description: >- + Create a new cluster resource. - Examples: `status.conditions.Reconciled='True'`, `name in - ('c1','c2')`, `labels.region='us-east'` - in: query - name: search - required: false - type: string - - default: 1 - format: int32 - in: query - name: page - required: false - type: integer - - default: 20 - format: int32 - in: query - name: pageSize - required: false - type: integer - - default: created_time - in: query - name: orderBy - required: false - type: string - - enum: - - asc - - desc - in: query - name: order - required: false + + **Note**: The `status` object in the response is read-only and computed + by the service. + + It is NOT part of the request body. Initially, + + status.conditions will include mandatory "LastKnownReconciled" and + "Reconciled" conditions. + operationId: postCluster + summary: Create cluster + '/api/hyperfleet/v1/clusters/{cluster_id}': + delete: + produces: + - application/json + - application/problem+json + parameters: + - in: path + name: cluster_id + required: true type: string responses: - '200': - description: The request has succeeded. + '202': + description: >- + The request has been accepted for processing, but processing has not + yet completed. + examples: + application/json: + created_by: user-123@example.com + created_time: '2021-01-01T00:00:00Z' + deleted_by: user-123@example.com + deleted_time: '2021-01-01T10:05:00Z' + generation: 2 + href: >- + https://api.hyperfleet.com/v1/clusters/019466a0-8f8e-7abc-9def-0123456789ab + id: 019466a0-8f8e-7abc-9def-0123456789ab + kind: Cluster + labels: + environment: production + team: platform + name: cluster-123 + spec: + dns: + baseDomain: example.com + networking: + clusterNetwork: + - cidr: 10.10.0.0/16 + hostPrefix: 24 + serviceNetwork: + - 10.96.0.0/12 + platform: + gcp: + network: network-123 + projectID: project-123 + region: us-central1 + subnet: subnet-123 + zone: us-central1-a + type: gcp + release: + channelGroup: candidate + image: >- + registry.redhat.io/openshift4/ose-cluster-version-operator:v4.22.0-ec.4 + version: 4.22.0-ec.4 + status: + conditions: + - created_time: '2021-01-01T10:00:00Z' + last_transition_time: '2021-01-01T10:00:00Z' + last_updated_time: '2021-01-01T10:00:00Z' + message: >- + All required adapters reported Available=True or + Finalized=True at the current generation + observed_generation: 2 + reason: ReconciledAll + status: 'True' + type: Reconciled + - created_time: '2021-01-01T10:00:00Z' + last_transition_time: '2021-01-01T10:00:00Z' + last_updated_time: '2021-01-01T10:00:00Z' + message: >- + All required adapters report Available=True for the + tracked generation + observed_generation: 2 + reason: AllAdaptersReconciled + status: 'True' + type: LastKnownReconciled + - created_time: '2021-01-01T10:00:00Z' + last_transition_time: '2021-01-01T10:00:00Z' + last_updated_time: '2021-01-01T10:00:00Z' + message: This adapter1 is available + observed_generation: 2 + reason: This adapter1 is available + status: 'True' + type: Adapter1Successful + - created_time: '2021-01-01T10:01:00Z' + last_transition_time: '2021-01-01T10:01:00Z' + last_updated_time: '2021-01-01T10:01:00Z' + message: This adapter2 is available + observed_generation: 2 + reason: This adapter2 is available + status: 'True' + type: Adapter2Successful + updated_by: user-123@example.com + updated_time: '2021-01-01T10:02:00Z' schema: - $ref: '#/definitions/AdapterStatusList' + $ref: '#/definitions/Cluster' '400': description: The server could not understand the request due to invalid syntax. '404': description: The server cannot find the requested resource. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' security: - BearerAuth: [] tags: - - Cluster statuses - description: Returns adapter status reports for this cluster - operationId: getClusterStatuses - summary: List all adapter statuses for cluster - /api/hyperfleet/v1/nodepools: + - Clusters + description: >- + Marks the cluster for deletion by setting deleted_time to the current + time, cascades to its nodepools. + + The cluster remains in the database until it is fully deleted. + + Returns the updated cluster with generation incremented. + operationId: deleteClusterById + summary: Request cluster deletion get: produces: - application/json @@ -750,35 +664,15 @@ paths: name: search required: false type: string - - default: 1 - format: int32 - in: query - name: page - required: false - type: integer - - default: 20 - format: int32 - in: query - name: pageSize - required: false - type: integer - - default: created_time - in: query - name: orderBy - required: false - type: string - - enum: - - asc - - desc - in: query - name: order - required: false + - in: path + name: cluster_id + required: true type: string responses: '200': description: The request has succeeded. schema: - $ref: '#/definitions/NodePoolList' + $ref: '#/definitions/Cluster' '400': description: The server could not understand the request due to invalid syntax. default: @@ -788,10 +682,620 @@ paths: security: - BearerAuth: [] tags: - - NodePools - description: Returns the list of all nodepools - operationId: getNodePools + - Clusters + description: Returns a single cluster by its ID. + operationId: getClusterById + summary: Get cluster by ID + patch: + consumes: + - application/json + produces: + - application/json + - application/problem+json + parameters: + - description: Cluster ID + in: path + name: cluster_id + required: true + type: string + - in: body + name: body + required: true + schema: + $ref: '#/definitions/ClusterPatchRequest' + responses: + '200': + description: The request has succeeded. + schema: + $ref: '#/definitions/Cluster' + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - Clusters + description: Patch a specific cluster by ID + operationId: patchClusterById + summary: Patch cluster by ID + '/api/hyperfleet/v1/clusters/{cluster_id}/nodepools': + get: + produces: + - application/json + - application/problem+json + parameters: + - description: Cluster ID + in: path + name: cluster_id + required: true + type: string + - description: >- + Filter results using TSL (Tree Search Language) query syntax. + + Examples: `status.conditions.Reconciled='True'`, `name in + ('c1','c2')`, `labels.region='us-east'` + in: query + name: search + required: false + type: string + - default: 1 + format: int32 + in: query + name: page + required: false + type: integer + - default: 20 + format: int32 + in: query + name: pageSize + required: false + type: integer + - default: created_time + in: query + name: orderBy + required: false + type: string + - enum: + - asc + - desc + in: query + name: order + required: false + type: string + responses: + '200': + description: The request has succeeded. + schema: + $ref: '#/definitions/NodePoolList' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - NodePools + description: Returns the list of all nodepools for a cluster + operationId: getNodePoolsByClusterId + summary: List all nodepools for cluster + post: + consumes: + - application/json + produces: + - application/json + - application/problem+json + parameters: + - description: Cluster ID + in: path + name: cluster_id + required: true + type: string + - in: body + name: body + required: true + schema: + $ref: '#/definitions/NodePoolCreateRequest' + responses: + '201': + description: >- + The request has succeeded and a new resource has been created as a + result. + schema: + $ref: '#/definitions/NodePoolCreateResponse' + '400': + description: The server could not understand the request due to invalid syntax. + '409': + description: The request conflicts with the current state of the server. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - NodePools + description: Create a NodePool for a cluster + operationId: createNodePool + summary: Create nodepool + '/api/hyperfleet/v1/clusters/{cluster_id}/nodepools/{nodepool_id}': + delete: + produces: + - application/json + - application/problem+json + parameters: + - description: Cluster ID + in: path + name: cluster_id + required: true + type: string + - description: NodePool ID + in: path + name: nodepool_id + required: true + type: string + responses: + '202': + description: >- + The request has been accepted for processing, but processing has not + yet completed. + examples: + application/json: + created_by: user-123@example.com + created_time: '2021-01-01T00:00:00Z' + deleted_by: user-123@example.com + deleted_time: '2021-01-01T10:05:00Z' + generation: 2 + href: >- + https://api.hyperfleet.com/v1/nodepools/019466a1-2b3c-7def-8abc-456789abcdef + id: 019466a1-2b3c-7def-8abc-456789abcdef + kind: NodePool + labels: + environment: production + pooltype: worker + name: worker-pool-1 + owner_references: + href: >- + https://api.hyperfleet.com/v1/clusters/019466a0-8f8e-7abc-9def-0123456789ab + id: 019466a0-8f8e-7abc-9def-0123456789ab + kind: Cluster + spec: + autoscaling: + enabled: true + maxNodes: 10 + minNodes: 1 + targetCPUUtilization: 80 + nodeCount: 3 + platform: + gcp: + diskSize: 100 + diskType: pd-standard + labels: + managedby: hyperfleet + team: platform + machineType: n1-standard-4 + preemptible: false + zones: + - us-central1-a + - us-central1-b + type: gcp + status: + conditions: + - created_time: '2021-01-01T10:00:00Z' + last_transition_time: '2021-01-01T10:00:00Z' + last_updated_time: '2021-01-01T10:00:00Z' + message: >- + All required adapters reported Available=True or + Finalized=True at the current generation + observed_generation: 2 + reason: ReconciledAll + status: 'True' + type: Reconciled + - created_time: '2021-01-01T10:00:00Z' + last_transition_time: '2021-01-01T10:00:00Z' + last_updated_time: '2021-01-01T10:00:00Z' + message: >- + All required adapters report Available=True for the + tracked generation + observed_generation: 2 + reason: AllAdaptersReconciled + status: 'True' + type: LastKnownReconciled + - created_time: '2021-01-01T10:00:00Z' + last_transition_time: '2021-01-01T10:00:00Z' + last_updated_time: '2021-01-01T10:00:00Z' + message: NodePool validation passed + observed_generation: 2 + reason: All validations passed + status: 'True' + type: ValidationSuccessful + - created_time: '2021-01-01T10:01:00Z' + last_transition_time: '2021-01-01T10:01:00Z' + last_updated_time: '2021-01-01T10:01:00Z' + message: NodePool has 3 nodes running + observed_generation: 2 + reason: NodePool provisioned successfully + status: 'True' + type: NodePoolSuccessful + updated_by: user-123@example.com + updated_time: '2021-01-01T10:02:00Z' + schema: + $ref: '#/definitions/NodePool' + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - NodePools + description: >- + Marks the nodepool for deletion by setting deleted_time and deleted_by. + Does not affect the parent cluster. + + Returns the updated nodepool with generation incremented. + operationId: deleteNodePoolById + summary: Request nodepool deletion + get: + produces: + - application/json + - application/problem+json + parameters: + - description: Cluster ID + in: path + name: cluster_id + required: true + type: string + - description: NodePool ID + in: path + name: nodepool_id + required: true + type: string + responses: + '200': + description: The request has succeeded. + schema: + $ref: '#/definitions/NodePool' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - NodePools + description: Returns specific nodepool + operationId: getNodePoolById + summary: Get nodepool by ID + patch: + consumes: + - application/json + produces: + - application/json + - application/problem+json + parameters: + - description: Cluster ID + in: path + name: cluster_id + required: true + type: string + - description: NodePool ID + in: path + name: nodepool_id + required: true + type: string + - in: body + name: body + required: true + schema: + $ref: '#/definitions/NodePoolPatchRequest' + responses: + '200': + description: The request has succeeded. + schema: + $ref: '#/definitions/NodePool' + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - NodePools + description: Patch a specific nodepool within a cluster + operationId: patchNodePoolById + summary: Patch nodepool by ID + /api/hyperfleet/v1/nodepools: + get: + produces: + - application/json + - application/problem+json + parameters: + - description: >- + Filter results using TSL (Tree Search Language) query syntax. + + Examples: `status.conditions.Reconciled='True'`, `name in + ('c1','c2')`, `labels.region='us-east'` + in: query + name: search + required: false + type: string + - default: 1 + format: int32 + in: query + name: page + required: false + type: integer + - default: 20 + format: int32 + in: query + name: pageSize + required: false + type: integer + - default: created_time + in: query + name: orderBy + required: false + type: string + - enum: + - asc + - desc + in: query + name: order + required: false + type: string + responses: + '200': + description: The request has succeeded. + schema: + $ref: '#/definitions/NodePoolList' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - NodePools + description: Returns the list of all nodepools + operationId: getNodePools summary: List all nodepools for cluster + /api/hyperfleet/v1/resources: + get: + produces: + - application/json + - application/problem+json + parameters: + - description: >- + Filter results using TSL (Tree Search Language) query syntax. + + Examples: `status.conditions.Reconciled='True'`, `name in + ('c1','c2')`, `labels.region='us-east'` + in: query + name: search + required: false + type: string + - default: 1 + format: int32 + in: query + name: page + required: false + type: integer + - default: 20 + format: int32 + in: query + name: pageSize + required: false + type: integer + - default: created_time + in: query + name: orderBy + required: false + type: string + - enum: + - asc + - desc + in: query + name: order + required: false + type: string + responses: + '200': + description: The request has succeeded. + schema: + $ref: '#/definitions/ResourceList' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - Resources + description: >- + Returns a paginated list of all resources, optionally filtered by kind, + labels, or TSL query. + operationId: getResources + summary: List resources + post: + consumes: + - application/json + produces: + - application/json + - application/problem+json + parameters: + - in: body + name: body + required: true + schema: + $ref: '#/definitions/ResourceCreateRequest' + responses: + '201': + description: >- + The request has succeeded and a new resource has been created as a + result. + schema: + $ref: '#/definitions/Resource' + '400': + description: The server could not understand the request due to invalid syntax. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - Resources + description: >- + Create a new resource. Only top-level entity types (no parent) can be + created + + via this endpoint. Child entities must use the nested route under their + parent. + operationId: postResource + summary: Create resource + '/api/hyperfleet/v1/resources/{resource_id}': + delete: + produces: + - application/json + - application/problem+json + parameters: + - in: path + name: resource_id + required: true + type: string + responses: + '202': + description: >- + The request has been accepted for processing, but processing has not + yet completed. + schema: + $ref: '#/definitions/Resource' + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - Resources + description: >- + Marks the resource for deletion. Child resources are handled per their + + OnParentDelete policy (cascade or restrict). Returns 409 if a + restrict-policy + + child exists or if another resource holds a reference to this one. + operationId: deleteResourceById + summary: Request resource deletion + get: + produces: + - application/json + - application/problem+json + parameters: + - description: >- + Filter results using TSL (Tree Search Language) query syntax. + + Examples: `status.conditions.Reconciled='True'`, `name in + ('c1','c2')`, `labels.region='us-east'` + in: query + name: search + required: false + type: string + - in: path + name: resource_id + required: true + type: string + responses: + '200': + description: The request has succeeded. + schema: + $ref: '#/definitions/Resource' + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - Resources + description: Returns a single resource by its ID. + operationId: getResourceById + summary: Get resource by ID + patch: + consumes: + - application/json + produces: + - application/json + - application/problem+json + parameters: + - in: path + name: resource_id + required: true + type: string + - in: body + name: body + required: true + schema: + $ref: '#/definitions/ResourcePatchRequest' + responses: + '200': + description: The request has succeeded. + schema: + $ref: '#/definitions/Resource' + '400': + description: The server could not understand the request due to invalid syntax. + '404': + description: The server cannot find the requested resource. + '409': + description: The request conflicts with the current state of the server. + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/Error' + security: + - BearerAuth: [] + tags: + - Resources + description: >- + Patch a resource by ID. Supports partial updates to spec, labels, and + references. + operationId: patchResourceById + summary: Patch resource by ID definitions: AcceleratorSpec: properties: @@ -804,185 +1308,165 @@ definitions: - type - count type: object - AdapterCondition: - description: >- - Condition in AdapterStatus - - Used for standard Kubernetes condition types: "Available", "Applied", - "Health", "Finalized" - - Note: observed_generation is at AdapterStatus level, not per-condition, - - since all conditions in one AdapterStatus share the same observed - generation + AutoscalingSpec: properties: - last_transition_time: - description: >- - When this condition last transitioned status (API-managed) - - Only updated when status changes (True/False), not when reason/message - changes - format: date-time + enabled: + type: boolean + maxNodes: + minimum: 1 + type: integer + minNodes: + minimum: 0 + type: integer + scaleDownDelay: type: string - message: - description: Human-readable message + scaleUpDelay: type: string - reason: - description: Machine-readable reason code + targetCPUUtilization: + maximum: 100 + minimum: 1 + type: integer + targetMemoryUtilization: + maximum: 100 + minimum: 1 + type: integer + type: object + BearerAuth: + properties: + scheme: + enum: + - bearer type: string - status: - $ref: '#/definitions/AdapterConditionStatus' type: - description: Condition type + enum: + - http type: string required: - type - - last_transition_time - - status + - scheme type: object - AdapterConditionStatus: - description: Status value for adapter conditions - enum: - - 'True' - - 'False' - - Unknown - type: string - AdapterStatus: - description: |- - AdapterStatus represents the complete status report from an adapter - Contains multiple conditions, job metadata, and adapter-specific data + Channel: example: - adapter: adapter1 - conditions: - - last_transition_time: '2021-01-01T10:00:00Z' - message: This adapter1 is available - reason: This adapter1 is available - status: 'True' - type: Available - - last_transition_time: '2021-01-01T10:00:00Z' - message: Adapter1 validation job applied successfully - reason: Validation job applied - status: 'True' - type: Applied - - last_transition_time: '2021-01-01T10:00:00Z' - message: All adapter1 runtime operations completed successfully - reason: All adapter1 operations completed successfully - status: 'True' - type: Health - - last_transition_time: '2021-01-01T10:00:00Z' - message: All resources deleted; cleanup confirmed - reason: All resources deleted; cleanup confirmed - status: 'True' - type: Finalized - created_time: '2021-01-01T10:00:00Z' - data: - validation_results: - failed: 0 - passed: 30 - total_tests: 30 - last_report_time: '2021-01-01T10:02:00Z' - metadata: - attempt: 1 - completed_time: '2021-01-01T10:02:00Z' - duration: 2m - job_name: validator-job-abc123 - job_namespace: hyperfleet-system - started_time: '2021-01-01T10:00:00Z' - observed_generation: 1 + created_by: user-123@example.com + created_time: '2025-06-01T00:00:00Z' + generation: 1 + href: /api/hyperfleet/v1/channels/019466a2-1234-7abc-9def-0123456789ab + id: 019466a2-1234-7abc-9def-0123456789ab + kind: Channel + labels: + tier: production + name: stable + spec: + enabled_regex: ^4\.\d+\.\d+$ + is_default: true + status: + conditions: [] + updated_by: user-123@example.com + updated_time: '2025-06-01T10:02:00Z' properties: - adapter: - description: 'Adapter name (e.g., "validator", "dns", "provisioner")' + created_by: + description: Identity that created the resource + format: email type: string - conditions: - description: |- - Kubernetes-style conditions tracking adapter state - Typically includes: Available, Applied, Health, Finalized - items: - $ref: '#/definitions/AdapterCondition' - type: array created_time: - description: When this adapter status was first created (API-managed) + description: Timestamp when the resource was created format: date-time type: string - data: - additionalProperties: {} - description: Adapter-specific data (structure varies by adapter type) - type: object - last_report_time: + deleted_by: + description: Identity that requested deletion; omitted if not marked for deletion + format: email + type: string + deleted_time: description: >- - When this adapter last reported its status (API-managed) - - Updated every time the adapter PUTs, even if conditions haven't - changed - - Used by Sentinel to detect adapter liveness + Timestamp when deletion was requested; omitted if not marked for + deletion format: date-time type: string - metadata: - description: Job execution metadata - properties: - attempt: - format: int32 - type: integer - completed_time: - format: date-time - type: string - duration: - type: string - job_name: - type: string - job_namespace: - type: string - started_time: - format: date-time - type: string - type: object - observed_generation: - description: Which generation of the resource this status reflects + generation: format: int32 + minimum: 1 type: integer + href: + description: Resource URI + type: string + id: + description: Resource identifier + type: string + kind: + description: Resource kind + type: string + labels: + additionalProperties: + type: string + description: 'labels for the API resource as pairs of name:value strings' + type: object + name: + maxLength: 63 + minLength: 1 + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + type: string + spec: + $ref: '#/definitions/ChannelSpec' + status: + $ref: '#/definitions/ResourceStatus' + updated_by: + description: Identity that last updated the resource + format: email + type: string + updated_time: + description: Timestamp when the resource was last updated + format: date-time + type: string required: - - adapter - - observed_generation - - conditions + - name + - spec - created_time - - last_report_time + - updated_time + - created_by + - updated_by + - generation + - status type: object - AdapterStatusList: - description: List of adapter statuses with pagination metadata + ChannelCreateRequest: example: - items: - - adapter: adapter1 - conditions: - - last_transition_time: '2021-01-01T10:00:00Z' - message: This adapter1 is available - reason: This adapter1 is available - status: 'True' - type: Available - created_time: '2021-01-01T10:00:00Z' - last_report_time: '2021-01-01T10:02:00Z' - metadata: - duration: 2m - job_name: validator-job-abc123 - observed_generation: 1 - - adapter: adapter2 - conditions: - - last_transition_time: '2021-01-01T10:01:00Z' - message: This adapter2 is available - reason: This adapter2 is available - status: 'True' - type: Available - created_time: '2021-01-01T10:01:00Z' - last_report_time: '2021-01-01T10:01:30Z' - observed_generation: 1 - kind: AdapterStatusList - page: 1 - size: 2 - total: 2 + kind: Channel + labels: + tier: production + name: stable + spec: + enabled_regex: ^4\.\d+\.\d+$ + is_default: true + properties: + href: + description: Resource URI + type: string + id: + description: Resource identifier + type: string + kind: + description: Resource kind + type: string + labels: + additionalProperties: + type: string + description: 'labels for the API resource as pairs of name:value strings' + type: object + name: + maxLength: 63 + minLength: 1 + pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$' + type: string + spec: + $ref: '#/definitions/ChannelSpec' + required: + - name + - spec + type: object + ChannelList: properties: items: items: - $ref: '#/definitions/AdapterStatus' + $ref: '#/definitions/Channel' type: array kind: type: string @@ -1002,42 +1486,43 @@ definitions: - total - items type: object - AutoscalingSpec: + ChannelPatchRequest: + additionalProperties: false + example: + labels: + tier: staging + spec: + enabled_regex: ^4\.17\.\d+$ + is_default: false + minProperties: 1 properties: - enabled: - type: boolean - maxNodes: - minimum: 1 - type: integer - minNodes: - minimum: 0 - type: integer - scaleDownDelay: - type: string - scaleUpDelay: - type: string - targetCPUUtilization: - maximum: 100 - minimum: 1 - type: integer - targetMemoryUtilization: - maximum: 100 - minimum: 1 - type: integer + labels: + additionalProperties: + type: string + type: object + spec: + $ref: '#/definitions/ChannelSpecUpdate' type: object - BearerAuth: + ChannelSpec: properties: - scheme: - enum: - - bearer - type: string - type: - enum: - - http + enabled_regex: + description: Regex pattern for matching enabled version strings type: string + is_default: + description: Whether this is the default channel for new clusters + type: boolean required: - - type - - scheme + - is_default + - enabled_regex + type: object + ChannelSpecUpdate: + properties: + enabled_regex: + description: Regex pattern for matching enabled version strings + type: string + is_default: + description: Whether this is the default channel for new clusters + type: boolean type: object Cluster: example: @@ -1916,20 +2401,119 @@ definitions: kind: description: Resource kind type: string - type: object - OrderDirection: - enum: - - asc - - desc - type: string - ReleaseSpec: - properties: - channelGroup: + type: object + OrderDirection: + enum: + - asc + - desc + type: string + ReleaseSpec: + properties: + channelGroup: + type: string + image: + type: string + version: + type: string + type: object + Resource: + example: + created_by: user-123@example.com + created_time: '2025-06-01T00:00:00Z' + generation: 1 + href: /api/hyperfleet/v1/resources/019466a0-8f8e-7abc-9def-0123456789ab + id: 019466a0-8f8e-7abc-9def-0123456789ab + kind: MyResource + labels: + environment: production + team: platform + name: my-resource-1 + spec: {} + status: + conditions: [] + updated_by: user-123@example.com + updated_time: '2025-06-01T10:02:00Z' + properties: + created_by: + description: Identity that created the resource + format: email + type: string + created_time: + description: Timestamp when the resource was created + format: date-time + type: string + deleted_by: + description: Identity that requested deletion; omitted if not marked for deletion + format: email + type: string + deleted_time: + description: >- + Timestamp when deletion was requested; omitted if not marked for + deletion + format: date-time + type: string + generation: + description: Incremented on spec or label changes + format: int32 + minimum: 1 + type: integer + href: + description: Resource URI (computed at creation time) + type: string + id: + description: Resource identifier (UUID v7) + type: string + kind: + description: Entity type discriminator + type: string + labels: + additionalProperties: + type: string + description: Key-value pairs for filtering and grouping + type: object + name: + description: 'Resource name (unique per kind, or per kind+owner for child entities)' + maxLength: 253 + minLength: 1 type: string - image: + owner_references: + allOf: + - $ref: '#/definitions/ObjectReference' + description: Parent resource reference (present only on child entities) + references: + additionalProperties: + items: + $ref: '#/definitions/ObjectReference' + type: array + description: 'Non-ownership associations to other resources, keyed by reference type' + type: object + spec: + additionalProperties: {} + description: >- + Entity-specific payload, validated at runtime against the entity's + spec schema + type: object + status: + $ref: '#/definitions/ResourceStatus' + updated_by: + description: Identity that last updated the resource + format: email type: string - version: + updated_time: + description: Timestamp when the resource was last updated + format: date-time type: string + required: + - id + - kind + - name + - spec + - status + - generation + - created_time + - updated_time + - created_by + - updated_by type: object ResourceCondition: description: >- @@ -1992,6 +2576,102 @@ definitions: - 'True' - 'False' type: string + ResourceCreateRequest: + example: + kind: MyResource + labels: + environment: production + team: platform + name: my-resource-1 + spec: {} + properties: + kind: + description: Entity type discriminator + type: string + labels: + additionalProperties: + type: string + description: Key-value pairs for filtering and grouping + type: object + name: + description: Resource name + maxLength: 253 + minLength: 1 + type: string + references: + additionalProperties: + items: + $ref: '#/definitions/ObjectReference' + type: array + description: Non-ownership associations to other resources + type: object + spec: + additionalProperties: {} + description: Entity-specific payload + type: object + required: + - kind + - name + - spec + type: object + ResourceList: + properties: + items: + items: + $ref: '#/definitions/Resource' + type: array + kind: + type: string + page: + format: int32 + type: integer + size: + format: int32 + type: integer + total: + format: int64 + type: integer + required: + - kind + - page + - size + - total + - items + type: object + ResourcePatchRequest: + additionalProperties: false + example: + labels: + env: staging + spec: {} + minProperties: 1 + properties: + labels: + additionalProperties: + type: string + type: object + references: + additionalProperties: + items: + $ref: '#/definitions/ObjectReference' + type: array + type: object + spec: + additionalProperties: {} + type: object + type: object + ResourceStatus: + description: |- + Aggregated status of the resource, populated by the status aggregation + pipeline from adapter condition reports. + properties: + conditions: + items: + $ref: '#/definitions/ResourceCondition' + type: array + required: + - conditions + type: object TaintSpec: properties: effect: @@ -2039,6 +2719,217 @@ definitions: - field - message type: object + Version: + example: + created_by: user-123@example.com + created_time: '2025-06-01T00:00:00Z' + generation: 1 + href: >- + /api/hyperfleet/v1/channels/019466a2-1234-7abc-9def-0123456789ab/versions/019466a3-5678-7abc-9def-0123456789ab + id: 019466a3-5678-7abc-9def-0123456789ab + kind: Version + labels: {} + name: 4.17.12 + owner_references: + href: /api/hyperfleet/v1/channels/019466a2-1234-7abc-9def-0123456789ab + id: 019466a2-1234-7abc-9def-0123456789ab + kind: Channel + spec: + enabled: true + is_default: true + raw_version: 4.17.12 + release_image: 'quay.io/openshift-release-dev/ocp-release:4.17.12-multi' + status: + conditions: [] + updated_by: user-123@example.com + updated_time: '2025-06-01T10:02:00Z' + properties: + created_by: + description: Identity that created the resource + format: email + type: string + created_time: + description: Timestamp when the resource was created + format: date-time + type: string + deleted_by: + description: Identity that requested deletion; omitted if not marked for deletion + format: email + type: string + deleted_time: + description: >- + Timestamp when deletion was requested; omitted if not marked for + deletion + format: date-time + type: string + generation: + format: int32 + minimum: 1 + type: integer + href: + description: Resource URI + type: string + id: + description: Resource identifier + type: string + kind: + description: Resource kind + type: string + labels: + additionalProperties: + type: string + description: 'labels for the API resource as pairs of name:value strings' + type: object + name: + maxLength: 63 + minLength: 1 + type: string + owner_references: + $ref: '#/definitions/ObjectReference' + spec: + $ref: '#/definitions/VersionSpec' + status: + $ref: '#/definitions/ResourceStatus' + updated_by: + description: Identity that last updated the resource + format: email + type: string + updated_time: + description: Timestamp when the resource was last updated + format: date-time + type: string + required: + - name + - spec + - created_time + - updated_time + - created_by + - updated_by + - generation + - owner_references + - status + type: object + VersionCreateRequest: + example: + kind: Version + labels: {} + name: 4.17.12 + spec: + enabled: true + is_default: true + raw_version: 4.17.12 + release_image: 'quay.io/openshift-release-dev/ocp-release:4.17.12-multi' + properties: + href: + description: Resource URI + type: string + id: + description: Resource identifier + type: string + kind: + description: Resource kind + type: string + labels: + additionalProperties: + type: string + description: 'labels for the API resource as pairs of name:value strings' + type: object + name: + maxLength: 63 + minLength: 1 + type: string + spec: + $ref: '#/definitions/VersionSpec' + required: + - name + - spec + type: object + VersionList: + properties: + items: + items: + $ref: '#/definitions/Version' + type: array + kind: + type: string + page: + format: int32 + type: integer + size: + format: int32 + type: integer + total: + format: int32 + type: integer + required: + - kind + - page + - size + - total + - items + type: object + VersionPatchRequest: + additionalProperties: false + example: + labels: + deprecated: 'true' + spec: + enabled: false + is_default: false + raw_version: 4.17.12 + release_image: 'quay.io/openshift-release-dev/ocp-release:4.17.12-multi' + minProperties: 1 + properties: + labels: + additionalProperties: + type: string + type: object + spec: + $ref: '#/definitions/VersionSpecUpdate' + type: object + VersionSpec: + properties: + enabled: + description: Whether this version is enabled for provisioning + type: boolean + end_of_life_time: + description: When this version reaches end of life + format: date-time + type: string + is_default: + description: Whether this is the default version for its channel + type: boolean + raw_version: + description: 'Raw version string (e.g., "4.17.12")' + type: string + release_image: + description: Container image reference for the release + type: string + required: + - raw_version + - enabled + - is_default + - release_image + type: object + VersionSpecUpdate: + properties: + enabled: + description: Whether this version is enabled for provisioning + type: boolean + end_of_life_time: + description: When this version reaches end of life + format: date-time + type: string + is_default: + description: Whether this is the default version for its channel + type: boolean + raw_version: + description: 'Raw version string (e.g., "4.17.12")' + type: string + release_image: + description: Container image reference for the release + type: string + type: object securityDefinitions: BearerAuth: in: header @@ -2046,9 +2937,10 @@ securityDefinitions: type: apiKey tags: - name: Clusters - - name: Cluster statuses - - name: NodePool statuses + - name: Channels + - name: Versions - name: NodePools + - name: Resources x-components: parameters: QueryParams.order: diff --git a/services/channels.tsp b/services/channels.tsp new file mode 100644 index 0000000..161516c --- /dev/null +++ b/services/channels.tsp @@ -0,0 +1,89 @@ +import "@typespec/http"; +import "@typespec/openapi"; +import "@typespec/openapi3"; + +import "../models-gcp/channel/model.tsp"; +import "../models/common/model.tsp"; + +using Http; +using OpenAPI; + +namespace HyperFleet; + +@tag("Channels") +@route("/channels") +@useAuth(HyperFleet.BearerAuth) +interface Channels { + /** + * Returns a paginated list of channels, optionally filtered by labels or TSL query. + */ + @get + @route("") + @summary("List channels") + @operationId("getChannels") + getChannels(...QueryParams): Body + | Error + | BadRequestResponse; + + /** + * Returns a single channel by its ID. + */ + @route("/{channel_id}") + @get + @summary("Get channel by ID") + @operationId("getChannelById") + getChannelById( + ...SearchParams, + @path channel_id: string, + ): Channel + | Error + | NotFoundResponse + | BadRequestResponse; + + /** + * Creates a new channel. + */ + @route("") + @post + @summary("Create channel") + @operationId("postChannel") + postChannel(@body body: ChannelCreateRequest): { + @statusCode statusCode: 201; + @body channel: Channel; + } | Error + | BadRequestResponse; + + /** + * Patches a channel by ID. Supports partial updates to spec and labels. + */ + @route("/{channel_id}") + @patch(#{implicitOptionality: true}) + @summary("Patch channel by ID") + @operationId("patchChannelById") + patchChannelById( + @path channel_id: string, + @body body: ChannelPatchRequest, + ): Channel + | Error + | NotFoundResponse + | BadRequestResponse + | ConflictResponse; + + /** + * Marks the channel for deletion. Returns 409 if versions still exist (RESTRICT policy). + */ + @route("/{channel_id}") + @delete + @summary("Request channel deletion") + @operationId("deleteChannelById") + deleteChannelById( + @path channel_id: string, + ): { + @statusCode statusCode: 202; + @body channel: Channel; + } | NotFoundResponse + | ConflictResponse + | Error + | BadRequestResponse; + +} diff --git a/services/resources.tsp b/services/resources.tsp new file mode 100644 index 0000000..1460a45 --- /dev/null +++ b/services/resources.tsp @@ -0,0 +1,93 @@ +import "@typespec/http"; +import "@typespec/openapi"; +import "@typespec/openapi3"; + +import "../models/resource/model.tsp"; +import "../models/common/model.tsp"; +import "../models/statuses/model.tsp"; + +using Http; +using OpenAPI; + +namespace HyperFleet; + +@tag("Resources") +@route("/resources") +@useAuth(HyperFleet.BearerAuth) +interface Resources { + /** + * Returns a paginated list of all resources, optionally filtered by kind, labels, or TSL query. + */ + @get + @route("") + @summary("List resources") + @operationId("getResources") + getResources(...QueryParams): Body + | Error + | BadRequestResponse; + + /** + * Returns a single resource by its ID. + */ + @route("/{resource_id}") + @get + @summary("Get resource by ID") + @operationId("getResourceById") + getResourceById( + ...SearchParams, + @path resource_id: string, + ): Resource + | Error + | NotFoundResponse + | BadRequestResponse; + + /** + * Create a new resource. Only top-level entity types (no parent) can be created + * via this endpoint. Child entities must use the nested route under their parent. + */ + @route("") + @post + @summary("Create resource") + @operationId("postResource") + postResource(@body body: ResourceCreateRequest): { + @statusCode statusCode: 201; + @body resource: Resource; + } | Error + | BadRequestResponse; + + /** + * Patch a resource by ID. Supports partial updates to spec, labels, and references. + */ + @route("/{resource_id}") + @patch(#{implicitOptionality: true}) + @summary("Patch resource by ID") + @operationId("patchResourceById") + patchResourceById( + @path resource_id: string, + @body body: ResourcePatchRequest, + ): Resource + | Error + | NotFoundResponse + | BadRequestResponse + | ConflictResponse; + + /** + * Marks the resource for deletion. Child resources are handled per their + * OnParentDelete policy (cascade or restrict). Returns 409 if a restrict-policy + * child exists or if another resource holds a reference to this one. + */ + @route("/{resource_id}") + @delete + @summary("Request resource deletion") + @operationId("deleteResourceById") + deleteResourceById( + @path resource_id: string, + ): { + @statusCode statusCode: 202; + @body resource: Resource; + } | NotFoundResponse + | ConflictResponse + | Error + | BadRequestResponse; + +} diff --git a/services/statuses-internal.tsp b/services/statuses-internal.tsp index 5f5b999..a6de01b 100644 --- a/services/statuses-internal.tsp +++ b/services/statuses-internal.tsp @@ -5,6 +5,7 @@ import "@typespec/openapi3"; import "../models/statuses/model.tsp"; import "../models/common/model.tsp"; import "../models/nodepools/model.tsp"; +import "../models/resource/model.tsp"; using Http; using OpenAPI; @@ -61,3 +62,61 @@ interface NodePoolStatusesInternal { | NotFoundResponse | ConflictResponse; } + +@tag("Resource statuses") +@route("/resources/{resource_id}/statuses") +@useAuth(HyperFleet.BearerAuth) +interface ResourceStatusesInternal { + /** + * Returns adapter statuses for a resource. + */ + @route("") + @get + @summary("List resource statuses") + @operationId("getResourceStatuses") + getResourceStatuses( + @path resource_id: string, + ...QueryParams, + ): Body + | Error + | NotFoundResponse + | BadRequestResponse; + + @route("") + @put + @summary("Adapter creates or updates resource status") + @operationId("putResourceStatuses") + @doc("Adapters call this endpoint to report status for a resource after each evaluation. The adapter's status entry is created if it doesn't exist, or updated if it does (upserted by adapter name).") + putResourceStatuses( + @path resource_id: string, + @body body: AdapterStatusCreateRequest, + ): + | (CreatedResponse & AdapterStatus) + | BadRequestResponse + | NotFoundResponse + | ConflictResponse; +} + +@tag("Resources") +@route("/resources") +@useAuth(HyperFleet.BearerAuth) +interface ResourcesForceDelete { + /** + * Permanently removes the resource record from the database for a resource stuck in Finalizing state. + * This is a database-only operation. Requires a reason for audit purposes. + */ + @route("/{resource_id}/force-delete") + @post + @summary("Force-delete a resource") + @operationId("forceDeleteResource") + forceDeleteResource( + @path resource_id: string, + @body body: ForceDeleteRequest, + ): { + @statusCode statusCode: 204; + } | Error + | NotFoundResponse + | BadRequestResponse + | ConflictResponse; +} + diff --git a/services/statuses.tsp b/services/statuses.tsp index a97c0bc..2f442f5 100644 --- a/services/statuses.tsp +++ b/services/statuses.tsp @@ -36,6 +36,7 @@ interface ClusterStatuses{ @tag("NodePool statuses") @route("/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses") +@useAuth(HyperFleet.BearerAuth) interface NodePoolStatuses{ /** * Returns adapter status reports for this nodepool diff --git a/services/versions.tsp b/services/versions.tsp new file mode 100644 index 0000000..989d6fe --- /dev/null +++ b/services/versions.tsp @@ -0,0 +1,96 @@ +import "@typespec/http"; +import "@typespec/openapi"; +import "@typespec/openapi3"; + +import "../models-gcp/version/model.tsp"; +import "../models/common/model.tsp"; + +using Http; +using OpenAPI; + +namespace HyperFleet; + +@tag("Versions") +@useAuth(HyperFleet.BearerAuth) +interface Versions { + /** + * Returns a paginated list of versions for a channel. + */ + @route("/channels/{channel_id}/versions") + @get + @summary("List versions for channel") + @operationId("getVersionsByChannelId") + getVersionsByChannelId( + @path channel_id: string, + ...QueryParams, + ): Body + | Error + | BadRequestResponse; + + /** + * Creates a new version under a channel. + */ + @route("/channels/{channel_id}/versions") + @post + @summary("Create version") + @operationId("postVersion") + postVersion( + @path channel_id: string, + @body body: VersionCreateRequest, + ): { + @statusCode statusCode: 201; + @body version: Version; + } | Error + | BadRequestResponse; + + /** + * Returns a single version by its ID within a channel. + */ + @route("/channels/{channel_id}/versions/{version_id}") + @get + @summary("Get version by ID") + @operationId("getVersionById") + getVersionById( + @path channel_id: string, + @path version_id: string, + ): Version + | Error + | NotFoundResponse + | BadRequestResponse; + + /** + * Patch a version by ID. Supports partial updates to spec and labels. + */ + @route("/channels/{channel_id}/versions/{version_id}") + @patch(#{implicitOptionality: true}) + @summary("Patch version by ID") + @operationId("patchVersionById") + patchVersionById( + @path channel_id: string, + @path version_id: string, + @body body: VersionPatchRequest, + ): Version + | Error + | NotFoundResponse + | BadRequestResponse + | ConflictResponse; + + /** + * Marks a version for deletion. + */ + @route("/channels/{channel_id}/versions/{version_id}") + @delete + @summary("Request version deletion") + @operationId("deleteVersionById") + deleteVersionById( + @path channel_id: string, + @path version_id: string, + ): { + @statusCode statusCode: 202; + @body version: Version; + } | NotFoundResponse + | ConflictResponse + | Error + | BadRequestResponse; + +}