Skip to content

Commit 3d8316f

Browse files
committed
cyborg: Implement CyborgAPI controller reconcile loop
Add full reconcile logic for the CyborgAPI CR: - Validate input from config secret provided by the Cyborg controller - Render WSGI/httpd and cyborg-api configuration templates - Create a StatefulSet for cyborg-api pods with TLS support - Register Keystone endpoints (public and internal) for the API - Track readiness (ReadyCount, conditions, hash, topology) - Expose IsReady and topology helpers on CyborgAPI type - Extend Cyborg controller to create CyborgAPI and check readiness upwards - Add functional tests covering the full API reconcile flow Assisted-By: Claude Signed-off-by: Alfredo Moralejo <amoralej@redhat.com>
1 parent aaa7c55 commit 3d8316f

24 files changed

Lines changed: 2982 additions & 50 deletions

api/bases/cyborg.openstack.org_cyborgapis.yaml

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,16 @@ spec:
1414
singular: cyborgapi
1515
scope: Namespaced
1616
versions:
17-
- name: v1beta1
17+
- additionalPrinterColumns:
18+
- description: Status
19+
jsonPath: .status.conditions[0].status
20+
name: Status
21+
type: string
22+
- description: Message
23+
jsonPath: .status.conditions[0].message
24+
name: Message
25+
type: string
26+
name: v1beta1
1827
schema:
1928
openAPIV3Schema:
2029
description: CyborgAPI is the Schema for the cyborgapis API.
@@ -39,10 +48,18 @@ spec:
3948
spec:
4049
description: CyborgAPISpec defines the desired state of CyborgAPI.
4150
properties:
51+
apiTimeout:
52+
default: 60
53+
description: APITimeout for Route and Apache
54+
minimum: 10
55+
type: integer
4256
configSecret:
4357
description: ConfigSecret - containing all the configuration needed
4458
provided by Cyborg object
4559
type: string
60+
containerImage:
61+
description: ContainerImage is the container image URL for cyborg-api
62+
type: string
4663
customServiceConfig:
4764
description: |-
4865
CustomServiceConfig - customize the service config using this parameter to change service defaults,
@@ -283,6 +300,9 @@ spec:
283300
More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
284301
type: object
285302
type: object
303+
serviceAccount:
304+
description: ServiceAccount used by the api pods
305+
type: string
286306
tls:
287307
description: TLS - Parameters related to the TLS
288308
properties:
@@ -332,9 +352,82 @@ spec:
332352
type: object
333353
required:
334354
- configSecret
355+
- containerImage
356+
- serviceAccount
335357
type: object
336358
status:
337359
description: CyborgAPIStatus defines the observed state of CyborgAPI.
360+
properties:
361+
conditions:
362+
description: Conditions
363+
items:
364+
description: Condition defines an observation of a API resource
365+
operational state.
366+
properties:
367+
lastTransitionTime:
368+
description: |-
369+
Last time the condition transitioned from one status to another.
370+
This should be when the underlying condition changed. If that is not known, then using the time when
371+
the API field changed is acceptable.
372+
format: date-time
373+
type: string
374+
message:
375+
description: A human readable message indicating details about
376+
the transition.
377+
type: string
378+
reason:
379+
description: The reason for the condition's last transition
380+
in CamelCase.
381+
type: string
382+
severity:
383+
description: |-
384+
Severity provides a classification of Reason code, so the current situation is immediately
385+
understandable and could act accordingly.
386+
It is meant for situations where Status=False and it should be indicated if it is just
387+
informational, warning (next reconciliation might fix it) or an error (e.g. DB create issue
388+
and no actions to automatically resolve the issue can/should be done).
389+
For conditions where Status=Unknown or Status=True the Severity should be SeverityNone.
390+
type: string
391+
status:
392+
description: Status of the condition, one of True, False, Unknown.
393+
type: string
394+
type:
395+
description: Type of condition in CamelCase.
396+
type: string
397+
required:
398+
- lastTransitionTime
399+
- status
400+
- type
401+
type: object
402+
type: array
403+
hash:
404+
additionalProperties:
405+
type: string
406+
description: Hash - Map of hashes to track config changes
407+
type: object
408+
lastAppliedTopology:
409+
description: LastAppliedTopology - the last applied Topology
410+
properties:
411+
name:
412+
description: Name - The Topology CR name that the Service references
413+
type: string
414+
namespace:
415+
description: |-
416+
Namespace - The Namespace to fetch the Topology CR referenced
417+
NOTE: Namespace currently points by default to the same namespace where
418+
the Service is deployed. Customizing the namespace is not supported and
419+
webhooks prevent editing this field to a value different from the
420+
current project
421+
type: string
422+
type: object
423+
observedGeneration:
424+
description: ObservedGeneration - the most recent generation observed
425+
format: int64
426+
type: integer
427+
readyCount:
428+
description: ReadyCount defines the number of replicas ready
429+
format: int32
430+
type: integer
338431
type: object
339432
type: object
340433
served: true

api/bases/cyborg.openstack.org_cyborgs.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,16 @@ spec:
1414
singular: cyborg
1515
scope: Namespaced
1616
versions:
17-
- name: v1beta1
17+
- additionalPrinterColumns:
18+
- description: Status
19+
jsonPath: .status.conditions[0].status
20+
name: Status
21+
type: string
22+
- description: Message
23+
jsonPath: .status.conditions[0].message
24+
name: Message
25+
type: string
26+
name: v1beta1
1827
schema:
1928
openAPIV3Schema:
2029
description: Cyborg is the Schema for the cyborgs API.

api/cyborg/v1beta1/conditions.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ const (
4747
// CyborgAPIReadyInitMessage -
4848
CyborgAPIReadyInitMessage = "CyborgAPI not started"
4949

50+
// CyborgAPIReadyErrorMessage -
51+
CyborgAPIReadyErrorMessage = "CyborgAPI error occurred %s"
52+
5053
// CyborgConductorReadyInitMessage -
5154
CyborgConductorReadyInitMessage = "CyborgConductor not started"
5255

api/cyborg/v1beta1/cyborg_types.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ package v1beta1
1919
import (
2020
rabbitmqv1 "github.com/openstack-k8s-operators/infra-operator/apis/rabbitmq/v1beta1"
2121
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
22-
condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
22+
"github.com/openstack-k8s-operators/lib-common/modules/common/condition"
2323
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2424
)
2525

@@ -141,6 +141,8 @@ type CyborgStatus struct {
141141

142142
// +kubebuilder:object:root=true
143143
// +kubebuilder:subresource:status
144+
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[0].status",description="Status"
145+
// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[0].message",description="Message"
144146

145147
// Cyborg is the Schema for the cyborgs API.
146148
type Cyborg struct {

api/cyborg/v1beta1/cyborgapi_types.go

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ package v1beta1
1818

1919
import (
2020
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
21-
service "github.com/openstack-k8s-operators/lib-common/modules/common/service"
21+
"github.com/openstack-k8s-operators/lib-common/modules/common/condition"
22+
"github.com/openstack-k8s-operators/lib-common/modules/common/service"
2223
"github.com/openstack-k8s-operators/lib-common/modules/common/tls"
2324
corev1 "k8s.io/api/core/v1"
2425
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -80,15 +81,45 @@ type CyborgAPISpec struct {
8081

8182
// +kubebuilder:validation:Required
8283
// ConfigSecret - containing all the configuration needed provided by Cyborg object
83-
ConfigSecret *string `json:"configSecret"`
84+
ConfigSecret string `json:"configSecret"`
85+
86+
// +kubebuilder:validation:Required
87+
// ContainerImage is the container image URL for cyborg-api
88+
ContainerImage string `json:"containerImage"`
89+
90+
// +kubebuilder:validation:Required
91+
// ServiceAccount used by the api pods
92+
ServiceAccount string `json:"serviceAccount"`
93+
94+
// +kubebuilder:validation:Optional
95+
// +kubebuilder:default=60
96+
// +kubebuilder:validation:Minimum=10
97+
// APITimeout for Route and Apache
98+
APITimeout *int `json:"apiTimeout"`
8499
}
85100

86101
// CyborgAPIStatus defines the observed state of CyborgAPI.
87102
type CyborgAPIStatus struct {
103+
// ReadyCount defines the number of replicas ready
104+
ReadyCount int32 `json:"readyCount,omitempty"`
105+
106+
// Conditions
107+
Conditions condition.Conditions `json:"conditions,omitempty" optional:"true"`
108+
109+
// ObservedGeneration - the most recent generation observed
110+
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
111+
112+
// Hash - Map of hashes to track config changes
113+
Hash map[string]string `json:"hash,omitempty"`
114+
115+
// LastAppliedTopology - the last applied Topology
116+
LastAppliedTopology *topologyv1.TopoRef `json:"lastAppliedTopology,omitempty"`
88117
}
89118

90119
// +kubebuilder:object:root=true
91120
// +kubebuilder:subresource:status
121+
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[0].status",description="Status"
122+
// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[0].message",description="Message"
92123

93124
// CyborgAPI is the Schema for the cyborgapis API.
94125
type CyborgAPI struct {
@@ -108,6 +139,26 @@ type CyborgAPIList struct {
108139
Items []CyborgAPI `json:"items"`
109140
}
110141

142+
// IsReady returns true if the ReadyCondition is true
143+
func (instance *CyborgAPI) IsReady() bool {
144+
return instance.Status.Conditions.IsTrue(condition.ReadyCondition)
145+
}
146+
147+
// GetSpecTopologyRef returns the TopologyRef defined in the Spec
148+
func (instance *CyborgAPI) GetSpecTopologyRef() *topologyv1.TopoRef {
149+
return instance.Spec.TopologyRef
150+
}
151+
152+
// GetLastAppliedTopology returns the LastAppliedTopology from the Status
153+
func (instance *CyborgAPI) GetLastAppliedTopology() *topologyv1.TopoRef {
154+
return instance.Status.LastAppliedTopology
155+
}
156+
157+
// SetLastAppliedTopology sets the LastAppliedTopology value in the Status
158+
func (instance *CyborgAPI) SetLastAppliedTopology(topologyRef *topologyv1.TopoRef) {
159+
instance.Status.LastAppliedTopology = topologyRef
160+
}
161+
111162
func init() {
112163
SchemeBuilder.Register(&CyborgAPI{}, &CyborgAPIList{})
113164
}

api/cyborg/v1beta1/zz_generated.deepcopy.go

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

0 commit comments

Comments
 (0)