Skip to content

Commit c582bd1

Browse files
authored
Add Resource Health Status (#136)
Also, we can tidy up the common API conversion routines using the power of interface type assertion to simplify every handler in the system.
1 parent f1c0fe8 commit c582bd1

File tree

7 files changed

+131
-48
lines changed

7 files changed

+131
-48
lines changed

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ CONTROLLER_TOOLS_VERSION=v0.17.3
2929
# This should be kept in sync with the Kubenetes library versions defined in go.mod.
3030
CODEGEN_VERSION := $(shell grep k8s.io/apimachinery go.mod | awk '{ print $$2; }')
3131

32-
OPENAPI_CODEGEN_VERSION=v1.16.2
32+
OPENAPI_CODEGEN_VERSION=v2.4.1
3333

3434
OPENAPI_FILES = pkg/openapi/types.go pkg/openapi/schema.go
3535

@@ -68,11 +68,11 @@ test-unit:
6868
go tool cover -html cover.out -o cover.html
6969

7070
pkg/openapi/types.go: pkg/openapi/common.spec.yaml
71-
@go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@$(OPENAPI_CODEGEN_VERSION)
71+
@go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@$(OPENAPI_CODEGEN_VERSION)
7272
oapi-codegen -generate types,skip-prune -package openapi -o $@ $<
7373

7474
pkg/openapi/schema.go: pkg/openapi/common.spec.yaml
75-
@go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@$(OPENAPI_CODEGEN_VERSION)
75+
@go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@$(OPENAPI_CODEGEN_VERSION)
7676
oapi-codegen -generate spec,skip-prune -package openapi -o $@ $<
7777

7878
# Create any CRDs defined into the target directory.

charts/core/Chart.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ description: A Helm chart for deploying Unikorn Core
44

55
type: application
66

7-
version: v1.1.0-rc1
8-
appVersion: v1.1.0-rc1
7+
version: v1.1.0-rc2
8+
appVersion: v1.1.0-rc2
99

1010
icon: https://assets.unikorn-cloud.org/images/logos/dark-on-light/icon.svg
1111

pkg/apis/unikorn/v1alpha1/types.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,13 +275,17 @@ const (
275275
// resource is not ready, or is known to be in a bad state and should
276276
// not be used. When true, while not guaranteed to be fully functional.
277277
ConditionAvailable ConditionType = "Available"
278+
// ConditionHealthy if defined describes the current healthiness of
279+
// the resource.
280+
ConditionHealthy ConditionType = "Healthy"
278281
)
279282

280283
// ConditionReason defines the possible reasons of a resource
281284
// condition. These are generic and may be used by any condition.
282285
// +kubebuilder:validation:Enum=Provisioning;Provisioned;Cancelled;Errored;Deprovisioning;Deprovisioned
283286
type ConditionReason string
284287

288+
// Condition reasons for ConditionAvailable.
285289
const (
286290
// ConditionReasonProvisioning is used for the Available condition
287291
// to indicate that a resource has been seen, it has no pre-existing condition
@@ -306,6 +310,16 @@ const (
306310
ConditionReasonDeprovisioned ConditionReason = "Deprovisioned"
307311
)
308312

313+
// Condition reasons for ConditionHealthy.
314+
const (
315+
// ConditionReasonHealthy means all subresources associated with the
316+
// resource are in a healthy state.
317+
ConditionReasonHealthy ConditionReason = "Healthy"
318+
// ConditionReasonDegraded means some subresources associated with the
319+
// resource are degraded e.g. a deployment not correctly scaled etc.
320+
ConditionReasonDegraded ConditionReason = "Degraded"
321+
)
322+
309323
// Condition is a generic condition type for use across all resource types.
310324
// It's generic so that the underlying controller-manager functionality can
311325
// be shared across all resources.

pkg/openapi/common.spec.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,20 +116,30 @@ components:
116116
- provisioned
117117
- deprovisioning
118118
- error
119+
resourceHealthStatus:
120+
description: The health state of a resource.
121+
type: string
122+
enum:
123+
- unknown
124+
- healthy
125+
- degraded
119126
resourceReadMetadata:
120127
description: Resource metadata valid for all reads.
121128
allOf:
122129
- $ref: '#/components/schemas/staticResourceMetadata'
123130
- type: object
124131
required:
125132
- provisioningStatus
133+
- healthStatus
126134
properties:
127135
deletionTime:
128136
description: The time the resource was deleted.
129137
type: string
130138
format: date-time
131139
provisioningStatus:
132140
$ref: '#/components/schemas/resourceProvisioningStatus'
141+
healthStatus:
142+
$ref: '#/components/schemas/resourceHealthStatus'
133143
organizationScopedResourceReadMetadata:
134144
allOf:
135145
- $ref: '#/components/schemas/resourceReadMetadata'

pkg/openapi/schema.go

Lines changed: 31 additions & 31 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/openapi/types.go

Lines changed: 20 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/server/conversion/conversion.go

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,22 @@ var (
3434
ErrAnnotation = errors.New("a required annotation was missing")
3535
)
3636

37-
// ConvertStatusCondition translates from Kubernetes status conditions to API ones.
38-
func ConvertStatusCondition(in *unikornv1.Condition) openapi.ResourceProvisioningStatus {
37+
// convertStatusCondition translates from Kubernetes status conditions to API ones.
38+
func convertStatusCondition(in any) openapi.ResourceProvisioningStatus {
39+
// Not a resource with status conditions, consider it provisioned.
40+
reader, ok := in.(unikornv1.StatusConditionReader)
41+
if !ok {
42+
return openapi.ResourceProvisioningStatusProvisioned
43+
}
44+
45+
// No condition yet, it's unknown.
46+
condition, err := reader.StatusConditionRead(unikornv1.ConditionAvailable)
47+
if err != nil {
48+
return openapi.ResourceProvisioningStatusUnknown
49+
}
50+
3951
//nolint:exhaustive
40-
switch in.Reason {
52+
switch condition.Reason {
4153
case unikornv1.ConditionReasonProvisioning:
4254
return openapi.ResourceProvisioningStatusProvisioning
4355
case unikornv1.ConditionReasonProvisioned:
@@ -46,21 +58,47 @@ func ConvertStatusCondition(in *unikornv1.Condition) openapi.ResourceProvisionin
4658
return openapi.ResourceProvisioningStatusError
4759
case unikornv1.ConditionReasonDeprovisioning:
4860
return openapi.ResourceProvisioningStatusDeprovisioning
49-
default:
50-
return openapi.ResourceProvisioningStatusUnknown
5161
}
62+
63+
return openapi.ResourceProvisioningStatusUnknown
64+
}
65+
66+
// convertHealthCondition translates from Kubernetes heath conditions to API ones.
67+
func convertHealthCondition(in any) openapi.ResourceHealthStatus {
68+
// Not a resource with status conditions, consider it healthy.
69+
reader, ok := in.(unikornv1.StatusConditionReader)
70+
if !ok {
71+
return openapi.ResourceHealthStatusHealthy
72+
}
73+
74+
// No condition yet, it's unknown.
75+
condition, err := reader.StatusConditionRead(unikornv1.ConditionHealthy)
76+
if err != nil {
77+
return openapi.ResourceHealthStatusUnknown
78+
}
79+
80+
//nolint:exhaustive
81+
switch condition.Reason {
82+
case unikornv1.ConditionReasonHealthy:
83+
return openapi.ResourceHealthStatusHealthy
84+
case unikornv1.ConditionReasonDegraded:
85+
return openapi.ResourceHealthStatusDegraded
86+
}
87+
88+
return openapi.ResourceHealthStatusUnknown
5289
}
5390

5491
// ResourceReadMetadata extracts generic metadata from a resource for GET APIs.
55-
func ResourceReadMetadata(in metav1.Object, tags unikornv1.TagList, status openapi.ResourceProvisioningStatus) openapi.ResourceReadMetadata {
92+
func ResourceReadMetadata(in metav1.Object, tags unikornv1.TagList) openapi.ResourceReadMetadata {
5693
labels := in.GetLabels()
5794
annotations := in.GetAnnotations()
5895

5996
out := openapi.ResourceReadMetadata{
6097
Id: in.GetName(),
6198
Name: labels[constants.NameLabel],
6299
CreationTime: in.GetCreationTimestamp().Time,
63-
ProvisioningStatus: status,
100+
ProvisioningStatus: convertStatusCondition(in),
101+
HealthStatus: convertHealthCondition(in),
64102
}
65103

66104
if v, ok := annotations[constants.DescriptionAnnotation]; ok {
@@ -95,10 +133,10 @@ func ResourceReadMetadata(in metav1.Object, tags unikornv1.TagList, status opena
95133

96134
// OrganizationScopedResourceReadMetadata extracts organization scoped metdata from a resource
97135
// for GET APIS.
98-
func OrganizationScopedResourceReadMetadata(in metav1.Object, tags unikornv1.TagList, status openapi.ResourceProvisioningStatus) openapi.OrganizationScopedResourceReadMetadata {
136+
func OrganizationScopedResourceReadMetadata(in metav1.Object, tags unikornv1.TagList) openapi.OrganizationScopedResourceReadMetadata {
99137
labels := in.GetLabels()
100138

101-
temp := ResourceReadMetadata(in, tags, status)
139+
temp := ResourceReadMetadata(in, tags)
102140

103141
out := openapi.OrganizationScopedResourceReadMetadata{
104142
Id: temp.Id,
@@ -109,6 +147,7 @@ func OrganizationScopedResourceReadMetadata(in metav1.Object, tags unikornv1.Tag
109147
ModifiedBy: temp.ModifiedBy,
110148
ModifiedTime: temp.ModifiedTime,
111149
ProvisioningStatus: temp.ProvisioningStatus,
150+
HealthStatus: temp.HealthStatus,
112151
Tags: temp.Tags,
113152
OrganizationId: labels[constants.OrganizationLabel],
114153
}
@@ -118,10 +157,10 @@ func OrganizationScopedResourceReadMetadata(in metav1.Object, tags unikornv1.Tag
118157

119158
// ProjectScopedResourceReadMetadata extracts project scoped metdata from a resource for
120159
// GET APIs.
121-
func ProjectScopedResourceReadMetadata(in metav1.Object, tags unikornv1.TagList, status openapi.ResourceProvisioningStatus) openapi.ProjectScopedResourceReadMetadata {
160+
func ProjectScopedResourceReadMetadata(in metav1.Object, tags unikornv1.TagList) openapi.ProjectScopedResourceReadMetadata {
122161
labels := in.GetLabels()
123162

124-
temp := OrganizationScopedResourceReadMetadata(in, tags, status)
163+
temp := OrganizationScopedResourceReadMetadata(in, tags)
125164

126165
out := openapi.ProjectScopedResourceReadMetadata{
127166
Id: temp.Id,
@@ -132,6 +171,7 @@ func ProjectScopedResourceReadMetadata(in metav1.Object, tags unikornv1.TagList,
132171
ModifiedBy: temp.ModifiedBy,
133172
ModifiedTime: temp.ModifiedTime,
134173
ProvisioningStatus: temp.ProvisioningStatus,
174+
HealthStatus: temp.HealthStatus,
135175
Tags: temp.Tags,
136176
OrganizationId: temp.OrganizationId,
137177
ProjectId: labels[constants.ProjectLabel],

0 commit comments

Comments
 (0)