You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The **Ready** check and **Available** check are independent — both can apply to the same incoming report.
323
+
324
+
##### Report `Available=True` (obs_gen = X)
325
+
326
+
| Target | Current State | Required Condition | → status | → lut | → ltt | → obs_gen |
327
+
|---|---|---|---|---|---|---|
328
+
|`Ready`|`Ready=True`|`X==G` AND all `statuses[].obs_gen==G` AND all `statuses[].status==True`| unchanged |`min(adapter last_report_time)`|`—`|`—`|
329
+
|`Ready`|`Ready=False`|`X==G` AND all `statuses[].obs_gen==G` AND all `statuses[].status==True`|**`True`**|`min(adapter last_report_time)`|`obs_time`|`—`|
330
+
|`Ready`|`Ready=False`| Any required adapter has no stored status |`—`|`now`|`—`|`—`|
331
+
|`Ready`| any | Conditions above not met |`—`|`—`|`—`|`—`|
332
+
|`Available`|`Available=False`| all `statuses[].obs_gen==X`|**`True`**|`min(adapter last_report_time)`|`obs_time`|`X`|
333
+
|`Available`|`Available=True`| all `statuses[].obs_gen==X`| unchanged |`min(adapter last_report_time)`|`—`|`X`|
334
+
|`Available`| any | Conditions above not met |`—`|`—`|`—`|`—`|
335
+
336
+
##### Report `Available=False` (obs_gen = X)
337
+
338
+
| Target | Current State | Required Condition | → status | → lut | → ltt | → obs_gen |
|`Ready`| any | Conditions above not met |`—`|`—`|`—`|`—`|
343
+
|`Available`|`Available=False`| all `statuses[].obs_gen==X`| unchanged |`min(adapter last_report_time)`|`—`|`X`|
344
+
|`Available`|`Available=True`| all `statuses[].obs_gen==X`|**`False`**|`obs_time`|`obs_time`|`X`|
345
+
|`Available`| any | Conditions above not met |`—`|`—`|`—`|`—`|
346
+
252
347
## NodePool Management
253
348
254
349
### Endpoints
@@ -307,7 +402,7 @@ POST /api/hyperfleet/v1/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses
307
402
"status": "False",
308
403
"reason": "AwaitingAdapters",
309
404
"message": "Waiting for adapters to report status",
310
-
"observed_generation": 0,
405
+
"observed_generation": 1,
311
406
"created_time": "2025-01-01T00:00:00Z",
312
407
"last_updated_time": "2025-01-01T00:00:00Z",
313
408
"last_transition_time": "2025-01-01T00:00:00Z"
@@ -317,7 +412,7 @@ POST /api/hyperfleet/v1/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses
317
412
"status": "False",
318
413
"reason": "AwaitingAdapters",
319
414
"message": "Waiting for adapters to report status",
320
-
"observed_generation": 0,
415
+
"observed_generation": 1,
321
416
"created_time": "2025-01-01T00:00:00Z",
322
417
"last_updated_time": "2025-01-01T00:00:00Z",
323
418
"last_transition_time": "2025-01-01T00:00:00Z"
@@ -456,7 +551,7 @@ The status object contains synthesized conditions computed from adapter reports:
456
551
- All above fields plus:
457
552
-`observed_generation` - Generation this condition reflects
458
553
-`created_time` - When condition was first created (API-managed)
459
-
-`last_updated_time` - When adapter last reported (API-managed, from AdapterStatus.last_report_time)
554
+
-`last_updated_time` - When this condition was last refreshed (API-managed). For **Available**, always the evaluation time. For **Ready**: when Ready=True, the minimum of `last_report_time` across all required adapters that report Available=True at the current generation; when Ready=False, the evaluation time (so consumers can detect staleness).
460
555
-`last_transition_time` - When status last changed (API-managed)
`UpdateClusterStatusFromAdapters()` in `cluster.go` synthesizes two top-level conditions:
25
-
-**Available**: True if all required adapters report `Available=True` (any generation)
25
+
26
+
-**Available**: True when all required adapters report `Available=True` at the same `observed_generation` (not necessarily the current resource generation). When adapters are at different generations, Available preserves its previous value (last-known-good semantics). `ObservedGeneration` = the common adapter generation when consistent; preserved from existing state otherwise.
26
27
-**Ready**: True if all adapters report `Available=True` AND `observed_generation` matches current generation
27
28
29
+
Ready's `LastUpdatedTime` is computed in `status_aggregation.computeReadyLastUpdated`: when Ready=False it is the minimum of `LastReportTime` across all required adapters (falls back to `now` if any required adapter has no stored status yet); when Ready=True it is the minimum of `LastReportTime` across required adapters that have Available=True at the current generation. True→False transitions override this with the triggering adapter's `observedTime`.
30
+
28
31
`ProcessAdapterStatus()` validates mandatory conditions (`Available`, `Applied`, `Health`) before persisting. Rejects `Available=Unknown` on subsequent reports (only allowed on first report).
29
32
30
33
## GenericService
31
34
32
35
`generic.go` provides `List()` with pagination, search, and ordering.
36
+
33
37
-`ListArguments` has Page, Size, Search, OrderBy, Fields, Preloads
34
38
- Search validation: `SearchDisallowedFields` map blocks searching certain fields per resource type
0 commit comments