Skip to content

Commit 81bd394

Browse files
committed
controllers: cleanup component manager
- split component manager construction and fetching status - cleanup and describe logic - cleanup components state helpers ComponentState: "Ready" // Running, reconciliation is not required "Blocked" // Reconciliation is impossible "Pending" // Reconciliation is possible "NeedUpdate" // Running, update is required "Updating" // Update in progress ComponentManagerStatus: allReady (was !needSync) allRunning (was !needInit) allReadyOrUpdating Update state machine uses these aggregates for making decisions, and performs actions according to update plan. Signed-off-by: Konstantin Khlebnikov <[email protected]>
1 parent 5e7db5d commit 81bd394

36 files changed

+328
-300
lines changed

controllers/component_manager.go

Lines changed: 64 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,18 @@ type ComponentManager struct {
2222
}
2323

2424
type ComponentManagerStatus struct {
25-
needSync bool
26-
needInit bool
27-
needUpdate []components.Component
28-
allReadyOrUpdating bool
25+
allReady bool // All components are Ready - no reconciliations required
26+
allRunning bool // All components are Ready or NeedUpdate - can start updates
27+
allReadyOrUpdating bool // All components are Ready or Updating - no new updates
28+
29+
needUpdate []components.Component // Components in state NeedUpdate
2930
}
3031

3132
func NewComponentManager(
3233
ctx context.Context,
3334
ytsaurus *apiProxy.Ytsaurus,
3435
clusterDomain string,
3536
) (*ComponentManager, error) {
36-
logger := log.FromContext(ctx)
3737
resource := ytsaurus.GetResource()
3838

3939
if clusterDomain == "" {
@@ -164,79 +164,87 @@ func NewComponentManager(
164164
tt := components.NewTimbertruck(cfgen, ytsaurus, tnds, yc)
165165
allComponents = append(allComponents, tt)
166166

167+
return &ComponentManager{
168+
ytsaurus: ytsaurus,
169+
allComponents: allComponents,
170+
}, nil
171+
}
172+
173+
func (cm *ComponentManager) FetchStatus(ctx context.Context) error {
174+
logger := log.FromContext(ctx)
175+
resource := cm.ytsaurus.GetResource()
176+
167177
// Fetch component status.
168178
var readyComponents []string
179+
var needUpdateComponents []string
169180
var updatingComponents []string
170181
var notReadyComponents []string
171182

172-
status := ComponentManagerStatus{
173-
needInit: false,
174-
needSync: false,
175-
needUpdate: nil,
183+
cm.status = ComponentManagerStatus{
184+
allReady: true,
185+
allRunning: true,
176186
allReadyOrUpdating: true,
187+
needUpdate: nil,
177188
}
178-
for _, c := range allComponents {
179-
err := c.Fetch(ctx)
180-
if err != nil {
181-
logger.Error(err, "failed to fetch status for controller", "component", c.GetFullName())
182-
return nil, err
183-
}
184189

185-
componentStatus, err := c.Status(ctx)
190+
for _, component := range cm.allComponents {
191+
err := component.Fetch(ctx)
186192
if err != nil {
187-
return nil, fmt.Errorf("failed to get component %s status: %w", c.GetFullName(), err)
193+
return fmt.Errorf("failed to fetch component %s: %w", component.GetFullName(), err)
188194
}
189195

190-
c.SetReadyCondition(componentStatus)
191-
syncStatus := componentStatus.SyncStatus
192-
193-
if syncStatus == components.SyncStatusNeedLocalUpdate {
194-
status.needUpdate = append(status.needUpdate, c)
196+
status, err := component.Status(ctx)
197+
if err != nil {
198+
return fmt.Errorf("failed to get component %s status: %w", component.GetFullName(), err)
195199
}
196200

197-
if !components.IsRunningStatus(syncStatus) {
198-
if ytsaurus.GetClusterState() == ytv1.ClusterStateRunning {
199-
msg := fmt.Sprintf("component `%s` status is neither Ready nor NeedLocalUpdate, but `%s`, "+
200-
"needInit=true will be set, which will lead to Reconfiguration since cluster is in Running state",
201-
c.GetFullName(), syncStatus,
202-
)
203-
logger.Info(msg,
204-
"component", c.GetFullName(),
205-
"syncStatus", syncStatus,
201+
component.SetReadyCondition(status)
202+
logger.Info("Component status",
203+
"component", component.GetFullName(),
204+
"status", status.SyncStatus,
205+
"message", status.Message,
206+
)
207+
208+
switch status.SyncStatus {
209+
case components.SyncStatusReady:
210+
readyComponents = append(readyComponents, component.GetFullName())
211+
case components.SyncStatusNeedUpdate:
212+
needUpdateComponents = append(needUpdateComponents, component.GetFullName())
213+
cm.status.needUpdate = append(cm.status.needUpdate, component)
214+
cm.status.allReady = false
215+
cm.status.allReadyOrUpdating = false
216+
case components.SyncStatusUpdating:
217+
updatingComponents = append(updatingComponents, component.GetFullName())
218+
cm.status.allReady = false
219+
cm.status.allRunning = false
220+
default:
221+
notReadyComponents = append(notReadyComponents, component.GetFullName())
222+
cm.status.allReady = false
223+
cm.status.allRunning = false
224+
cm.status.allReadyOrUpdating = false
225+
if cm.ytsaurus.GetClusterState() == ytv1.ClusterStateRunning {
226+
logger.Info("Cluster needs reconfiguration because component is not running",
227+
"component", component.GetFullName(),
228+
"status", status.SyncStatus,
229+
"message", status.Message,
206230
)
207231
}
208-
status.needInit = true
209-
}
210-
211-
if syncStatus != components.SyncStatusReady && syncStatus != components.SyncStatusUpdating {
212-
status.allReadyOrUpdating = false
213-
}
214-
215-
if syncStatus != components.SyncStatusReady {
216-
logger.Info("component is not ready", "component", c.GetFullName(), "syncStatus", syncStatus, "message", componentStatus.Message)
217-
notReadyComponents = append(notReadyComponents, c.GetFullName())
218-
status.needSync = true
219-
} else {
220-
readyComponents = append(readyComponents, c.GetFullName())
221-
}
222-
223-
if syncStatus == components.SyncStatusUpdating {
224-
updatingComponents = append(updatingComponents, c.GetFullName())
225232
}
226233
}
227234

228235
logger.Info("Ytsaurus sync status",
236+
"clusterState", resource.Status.State,
237+
"updateState", resource.Status.UpdateStatus.State,
238+
"allReady", cm.status.allReady,
239+
"allRunning", cm.status.allRunning,
240+
"allReadyOrUpdating", cm.status.allReadyOrUpdating,
241+
"needUpdateComponents", needUpdateComponents,
242+
"updatingComponents", updatingComponents,
229243
"notReadyComponents", notReadyComponents,
230244
"readyComponents", readyComponents,
231-
"updatingComponents", updatingComponents,
232-
"updateState", resource.Status.UpdateStatus.State,
233-
"clusterState", resource.Status.State)
245+
)
234246

235-
return &ComponentManager{
236-
ytsaurus: ytsaurus,
237-
allComponents: allComponents,
238-
status: status,
239-
}, nil
247+
return nil
240248
}
241249

242250
func (cm *ComponentManager) Sync(ctx context.Context) (ctrl.Result, error) {
@@ -273,22 +281,6 @@ func (cm *ComponentManager) Sync(ctx context.Context) (ctrl.Result, error) {
273281
return ctrl.Result{RequeueAfter: time.Second}, nil
274282
}
275283

276-
func (cm *ComponentManager) needSync() bool {
277-
return cm.status.needSync
278-
}
279-
280-
func (cm *ComponentManager) needInit() bool {
281-
return cm.status.needInit
282-
}
283-
284-
func (cm *ComponentManager) needUpdate() []components.Component {
285-
return cm.status.needUpdate
286-
}
287-
288-
func (cm *ComponentManager) allReadyOrUpdating() bool {
289-
return cm.status.allReadyOrUpdating
290-
}
291-
292284
func (cm *ComponentManager) arePodsRemoved() bool {
293285
for _, cmp := range cm.allComponents {
294286
if cmp.GetType() == consts.YtsaurusClientType {

controllers/sync.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,13 @@ func (r *YtsaurusReconciler) Sync(ctx context.Context, resource *ytv1.Ytsaurus)
151151
ytsaurus := apiProxy.NewYtsaurus(resource, r.Client, r.Recorder, r.Scheme)
152152
componentManager, err := NewComponentManager(ctx, ytsaurus, r.ClusterDomain)
153153
if err != nil {
154+
logger.Error(err, "Cannot build component manager")
155+
return ctrl.Result{Requeue: true}, err
156+
}
157+
158+
err = componentManager.FetchStatus(ctx)
159+
if err != nil {
160+
logger.Error(err, "Cannot fetch component manager status")
154161
return ctrl.Result{Requeue: true}, err
155162
}
156163

@@ -162,14 +169,14 @@ func (r *YtsaurusReconciler) Sync(ctx context.Context, resource *ytv1.Ytsaurus)
162169

163170
case ytv1.ClusterStateInitializing:
164171
// Ytsaurus has finished initializing, and is running now.
165-
if !componentManager.needSync() {
172+
if componentManager.status.allRunning {
166173
logger.Info("Ytsaurus has synced and is running now")
167174
err := ytsaurus.SaveClusterState(ctx, ytv1.ClusterStateRunning)
168175
return ctrl.Result{Requeue: true}, err
169176
}
170177

171178
case ytv1.ClusterStateRunning:
172-
needUpdate := componentManager.needUpdate()
179+
needUpdate := componentManager.status.needUpdate
173180
canUpdate, cannotUpdate := chooseUpdatingComponents(
174181
ytsaurus.GetResource().Spec,
175182
convertToComponent(needUpdate),
@@ -186,10 +193,10 @@ func (r *YtsaurusReconciler) Sync(ctx context.Context, resource *ytv1.Ytsaurus)
186193
}
187194

188195
switch {
189-
case !componentManager.needSync():
196+
case componentManager.status.allReady:
190197
logger.Info("Ytsaurus is running and happy")
191198

192-
case componentManager.needInit():
199+
case !componentManager.status.allRunning:
193200
logger.Info("Ytsaurus needs initialization of some components")
194201
err := ytsaurus.SaveClusterState(ctx, ytv1.ClusterStateReconfiguration)
195202
return ctrl.Result{Requeue: true}, err
@@ -259,7 +266,7 @@ func (r *YtsaurusReconciler) Sync(ctx context.Context, resource *ytv1.Ytsaurus)
259266
return ctrl.Result{Requeue: true}, err
260267

261268
case ytv1.ClusterStateReconfiguration:
262-
if !componentManager.needInit() {
269+
if componentManager.status.allRunning {
263270
logger.Info("Ytsaurus has reconfigured and is running now")
264271
err := ytsaurus.SaveClusterState(ctx, ytv1.ClusterStateRunning)
265272
// Requeue once again to do final check and maybe update observed generation.

controllers/update_flow_steps.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ var flowConditions = map[ytv1.UpdateState]flowCondition{
181181
return stepResultMarkUnsatisfied
182182
},
183183
ytv1.UpdateStateImpossibleToStart: func(ctx context.Context, ytsaurus *apiProxy.Ytsaurus, componentManager *ComponentManager) stepResultMark {
184-
if !componentManager.needSync() || !ytsaurus.GetResource().Spec.EnableFullUpdate {
184+
if componentManager.status.allReady || !ytsaurus.GetResource().Spec.EnableFullUpdate {
185185
return stepResultMarkHappy
186186
}
187187
return stepResultMarkUnsatisfied
@@ -214,7 +214,7 @@ var flowConditions = map[ytv1.UpdateState]flowCondition{
214214
return stepResultMarkUnsatisfied
215215
},
216216
ytv1.UpdateStateWaitingForPodsCreation: func(ctx context.Context, ytsaurus *apiProxy.Ytsaurus, componentManager *ComponentManager) stepResultMark {
217-
if componentManager.allReadyOrUpdating() {
217+
if componentManager.status.allReadyOrUpdating {
218218
return stepResultMarkHappy
219219
}
220220
return stepResultMarkUnsatisfied

pkg/components/bundle_controller.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func (bc *BundleController) doSync(ctx context.Context, dry bool) (ComponentStat
5454
var err error
5555

5656
if ytv1.IsReadyToUpdateClusterState(bc.ytsaurus.GetClusterState()) && bc.server.needUpdate() {
57-
return SimpleStatus(SyncStatusNeedLocalUpdate), err
57+
return SimpleStatus(SyncStatusNeedUpdate), err
5858
}
5959

6060
if bc.ytsaurus.GetClusterState() == ytv1.ClusterStateUpdating {
@@ -67,11 +67,11 @@ func (bc *BundleController) doSync(ctx context.Context, dry bool) (ComponentStat
6767
if !dry {
6868
err = bc.doServerSync(ctx)
6969
}
70-
return WaitingStatus(SyncStatusPending, "components"), err
70+
return ComponentStatusWaitingFor("components"), err
7171
}
7272

7373
if !bc.server.arePodsReady(ctx) {
74-
return WaitingStatus(SyncStatusBlocked, "pods"), err
74+
return ComponentStatusBlockedBy("pods"), err
7575
}
7676

7777
return SimpleStatus(SyncStatusReady), err

pkg/components/chyt.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ func (c *Chyt) doSync(ctx context.Context, dry bool) (ComponentStatus, error) {
137137
var err error
138138

139139
if c.ytsaurus.Status.State != ytv1.ClusterStateRunning {
140-
return WaitingStatus(SyncStatusBlocked, "ytsaurus running"), err
140+
return ComponentStatusBlockedBy("ytsaurus is not running"), err
141141
}
142142

143143
// Create a user for chyt initialization.
@@ -150,7 +150,7 @@ func (c *Chyt) doSync(ctx context.Context, dry bool) (ComponentStatus, error) {
150150
err = c.secret.Sync(ctx)
151151
}
152152
c.chyt.GetResource().Status.ReleaseStatus = ytv1.ChytReleaseStatusCreatingUserSecret
153-
return WaitingStatus(SyncStatusPending, c.secret.Name()), err
153+
return ComponentStatusWaitingFor(c.secret.Name()), err
154154
}
155155

156156
if !dry {
@@ -200,7 +200,7 @@ func (c *Chyt) doSync(ctx context.Context, dry bool) (ComponentStatus, error) {
200200

201201
c.chyt.GetResource().Status.ReleaseStatus = ytv1.ChytReleaseStatusFinished
202202

203-
return SimpleStatus(SyncStatusReady), err
203+
return ComponentStatusReady(), err
204204
}
205205

206206
func (c *Chyt) Fetch(ctx context.Context) error {

pkg/components/component.go

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,30 +15,59 @@ import (
1515
type SyncStatus string
1616

1717
const (
18-
SyncStatusBlocked SyncStatus = "Blocked"
19-
SyncStatusNeedLocalUpdate SyncStatus = "NeedLocalUpdate"
20-
SyncStatusPending SyncStatus = "Pending"
21-
SyncStatusReady SyncStatus = "Ready"
22-
SyncStatusUpdating SyncStatus = "Updating"
18+
SyncStatusReady SyncStatus = "Ready" // Running, reconciliation is not required
19+
SyncStatusBlocked SyncStatus = "Blocked" // Reconciliation is impossible
20+
SyncStatusPending SyncStatus = "Pending" // Reconciliation is possible
21+
SyncStatusNeedUpdate SyncStatus = "NeedUpdate" // Running, update is required
22+
SyncStatusUpdating SyncStatus = "Updating" // Update in progress
2323
)
2424

25-
func IsRunningStatus(status SyncStatus) bool {
26-
return status == SyncStatusReady || status == SyncStatusNeedLocalUpdate
27-
}
28-
2925
type ComponentStatus struct {
3026
SyncStatus SyncStatus
3127
Message string
3228
}
3329

34-
func NewComponentStatus(status SyncStatus, message string) ComponentStatus {
35-
return ComponentStatus{status, message}
30+
func (cs ComponentStatus) IsRunning() bool {
31+
return cs.SyncStatus == SyncStatusReady || cs.SyncStatus == SyncStatusNeedUpdate
32+
}
33+
34+
func ComponentStatusReady() ComponentStatus {
35+
return ComponentStatus{SyncStatusReady, "Ready"}
36+
}
37+
38+
func ComponentStatusReadyAfter(message string) ComponentStatus {
39+
return ComponentStatus{SyncStatusReady, message}
40+
}
41+
42+
func ComponentStatusBlocked(message string) ComponentStatus {
43+
return ComponentStatus{SyncStatusBlocked, message}
44+
}
45+
46+
func ComponentStatusPending(message string) ComponentStatus {
47+
return ComponentStatus{SyncStatusPending, message}
48+
}
49+
50+
func ComponentStatusNeedUpdate(message string) ComponentStatus {
51+
return ComponentStatus{SyncStatusNeedUpdate, message}
52+
}
53+
54+
func ComponentStatusUpdating(message string) ComponentStatus {
55+
return ComponentStatus{SyncStatusUpdating, message}
56+
}
57+
58+
func ComponentStatusBlockedBy(cause string) ComponentStatus {
59+
return ComponentStatus{SyncStatusBlocked, fmt.Sprintf("Blocked by %s", cause)}
60+
}
61+
62+
func ComponentStatusWaitingFor(event string) ComponentStatus {
63+
return ComponentStatus{SyncStatusPending, fmt.Sprintf("Waiting for %s", event)}
3664
}
3765

38-
func WaitingStatus(status SyncStatus, event string) ComponentStatus {
39-
return ComponentStatus{status, fmt.Sprintf("Wait for %s", event)}
66+
func ComponentStatusUpdateStep(part string) ComponentStatus {
67+
return ComponentStatus{SyncStatusUpdating, fmt.Sprintf("Updating %s", part)}
4068
}
4169

70+
// TODO(khlebnikov): Replace this stub with status with meaningful message.
4271
func SimpleStatus(status SyncStatus) ComponentStatus {
4372
return ComponentStatus{status, string(status)}
4473
}

0 commit comments

Comments
 (0)