Skip to content

Commit 45a6701

Browse files
committed
HYPERFLEET-1083 feat: add generic Resource type and Channel/Version spec schemas
1 parent 541fe7a commit 45a6701

24 files changed

Lines changed: 4521 additions & 1060 deletions

CHANGELOG.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [1.0.17] - 2026-05-21
11+
12+
### Added
13+
14+
- Generic `Resource` type with `kind` discriminator and JSONB `spec` field, replacing per-entity model hierarchies for new resource types (HYPERFLEET-1083)
15+
- `ResourceCreateRequest`, `ResourcePatchRequest`, `ResourceList`, `ResourceStatus` types in core contract
16+
- Generic `/resources` CRUD routes in core contract (GET list, GET by ID, POST, PATCH, DELETE) per design doc Section 3.2
17+
- `/channels` and `/channels/{channel_id}/versions` CRUD routes in GCP contract
18+
- `references` field on Resource for non-ownership associations between entities (Section 9)
19+
- `ChannelSpec` validation schema in GCP contract (`is_default`, `enabled_regex`)
20+
- `VersionSpec` validation schema in GCP contract (`raw_version`, `enabled`, `is_default`, `release_image`, `end_of_life_time`)
21+
- `KindChannel` and `KindVersion` kind aliases in GCP contract
22+
23+
### Changed
24+
25+
- `GET /resources/{id}/statuses` and `POST /resources/{id}/force-delete` moved to core contract
26+
- `GET /clusters/{id}/statuses` and `GET /nodepools/{id}/statuses` moved to core contract
27+
1028
## [1.0.16] - 2026-05-20
1129

1230
### Added
@@ -152,7 +170,8 @@ First official stable release of the HyperFleet API specification.
152170
- Interactive API documentation
153171

154172
<!-- Links -->
155-
[Unreleased]: https://github.com/openshift-hyperfleet/hyperfleet-api-spec/compare/v1.0.16...HEAD
173+
[Unreleased]: https://github.com/openshift-hyperfleet/hyperfleet-api-spec/compare/v1.0.17...HEAD
174+
[1.0.17]: https://github.com/openshift-hyperfleet/hyperfleet-api-spec/compare/v1.0.16...v1.0.17
156175
[1.0.16]: https://github.com/openshift-hyperfleet/hyperfleet-api-spec/compare/v1.0.15...v1.0.16
157176
[1.0.15]: https://github.com/openshift-hyperfleet/hyperfleet-api-spec/compare/v1.0.14...v1.0.15
158177
[1.0.14]: https://github.com/openshift-hyperfleet/hyperfleet-api-spec/compare/v1.0.13...v1.0.14

aliases-core.tsp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ import "./models-core/nodepool/model.tsp";
66
import "./models-core/nodepool/example_nodepool.tsp";
77
import "./models-core/nodepool/example_post.tsp";
88
import "./models-core/nodepool/example_patch.tsp";
9+
import "./services/statuses.tsp";
910
import "./services/statuses-internal.tsp";
1011
import "./services/force-delete-internal.tsp";

aliases-gcp.tsp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,13 @@ import "./models-gcp/nodepool/model.tsp";
66
import "./models-gcp/nodepool/example_nodepool.tsp";
77
import "./models-gcp/nodepool/example_post.tsp";
88
import "./models-gcp/nodepool/example_patch.tsp";
9+
import "./models-gcp/channel/model.tsp";
10+
import "./models-gcp/channel/example_channel.tsp";
11+
import "./models-gcp/channel/example_post.tsp";
12+
import "./models-gcp/channel/example_patch.tsp";
13+
import "./models-gcp/version/model.tsp";
14+
import "./models-gcp/version/example_version.tsp";
15+
import "./models-gcp/version/example_post.tsp";
16+
import "./models-gcp/version/example_patch.tsp";
17+
import "./services/channels.tsp";
18+
import "./services/versions.tsp";

main.tsp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import "@typespec/openapi";
33
import "@typespec/openapi3";
44

55
import "./services/clusters.tsp";
6-
import "./services/statuses.tsp";
76
import "./services/nodepools.tsp";
7+
import "./services/resources.tsp";
88
// Provider-specific security is imported via aliases.tsp
99
import "./aliases.tsp";
1010

@@ -21,7 +21,7 @@ using OpenAPI;
2121
*/
2222
@service(#{ title: "HyperFleet API" })
2323
@info(#{
24-
version: "1.0.16",
24+
version: "1.0.17",
2525
contact: #{
2626
name: "HyperFleet Team",
2727
url: "https://github.com/openshift-hyperfleet",
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import "./model.tsp";
2+
import "../../models/common/model.tsp";
3+
4+
const exampleChannel: Channel = #{
5+
kind: "Channel",
6+
id: "019466a2-1234-7abc-9def-0123456789ab",
7+
href: "/api/hyperfleet/v1/channels/019466a2-1234-7abc-9def-0123456789ab",
8+
name: "stable",
9+
labels: #{ tier: "production" },
10+
spec: #{
11+
is_default: true,
12+
enabled_regex: "^4\\.\\d+\\.\\d+$",
13+
},
14+
generation: 1,
15+
status: #{
16+
conditions: #[],
17+
},
18+
created_time: "2025-06-01T00:00:00Z",
19+
updated_time: "2025-06-01T10:02:00Z",
20+
created_by: "user-123@example.com",
21+
updated_by: "user-123@example.com",
22+
};
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import "./model.tsp";
2+
3+
const exampleChannelPatchRequest: ChannelPatchRequest = #{
4+
spec: #{
5+
is_default: false,
6+
enabled_regex: "^4\\.17\\.\\d+$",
7+
},
8+
labels: #{ tier: "staging" },
9+
};
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import "./model.tsp";
2+
3+
const exampleChannelCreateRequest: ChannelCreateRequest = #{
4+
kind: "Channel",
5+
name: "stable",
6+
labels: #{ tier: "production" },
7+
spec: #{
8+
is_default: true,
9+
enabled_regex: "^4\\.\\d+\\.\\d+$",
10+
},
11+
};

models-gcp/channel/model.tsp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import "@typespec/openapi";
2+
import "../../models/common/model.tsp";
3+
import "../../models/statuses/model.tsp";
4+
import "../../models/resource/model.tsp";
5+
6+
using OpenAPI;
7+
8+
alias KindChannel = "Channel";
9+
10+
model ChannelSpec {
11+
/** Whether this is the default channel for new clusters */
12+
is_default: boolean;
13+
14+
/** Regex pattern for matching enabled version strings */
15+
enabled_regex: string;
16+
}
17+
18+
model ChannelBase {
19+
...APIResource;
20+
21+
@minLength(1)
22+
@maxLength(63)
23+
@pattern("^[a-z0-9]([-a-z0-9]*[a-z0-9])?$")
24+
name: string;
25+
26+
spec: ChannelSpec;
27+
}
28+
29+
@example(exampleChannel)
30+
model Channel {
31+
...ChannelBase;
32+
...APIMetadata;
33+
34+
@minValue(1)
35+
generation: int32;
36+
37+
status: ResourceStatus;
38+
}
39+
40+
@example(exampleChannelCreateRequest)
41+
model ChannelCreateRequest {
42+
...ChannelBase;
43+
}
44+
45+
@extension("minProperties", 1)
46+
@extension("additionalProperties", false)
47+
@example(exampleChannelPatchRequest)
48+
model ChannelPatchRequest {
49+
spec?: ChannelSpec;
50+
labels?: Record<string>;
51+
}
52+
53+
model ChannelList {
54+
...List<Channel>;
55+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import "./model.tsp";
2+
3+
const exampleVersionPatchRequest: VersionPatchRequest = #{
4+
spec: #{
5+
raw_version: "4.17.12",
6+
enabled: false,
7+
is_default: false,
8+
release_image: "quay.io/openshift-release-dev/ocp-release:4.17.12-multi",
9+
},
10+
labels: #{ deprecated: "true" },
11+
};
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import "./model.tsp";
2+
3+
const exampleVersionCreateRequest: VersionCreateRequest = #{
4+
kind: "Version",
5+
name: "4.17.12",
6+
labels: #{},
7+
spec: #{
8+
raw_version: "4.17.12",
9+
enabled: true,
10+
is_default: true,
11+
release_image: "quay.io/openshift-release-dev/ocp-release:4.17.12-multi",
12+
},
13+
};

0 commit comments

Comments
 (0)