Skip to content

Commit

Permalink
Add blocked components column to kubectl output (#459)
Browse files Browse the repository at this point in the history
* draft

* Add blocked components column
  • Loading branch information
l0kix2 authored Mar 7, 2025
1 parent f56269b commit 6628b3f
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 39 deletions.
2 changes: 2 additions & 0 deletions api/v1/ytsaurus_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,7 @@ type UpdateStatus struct {
// UpdatingComponentsSummary is used only for representation in kubectl, since it only supports
// "simple" JSONPath, and it is unclear how to force to print required data based on UpdatingComponents field.
UpdatingComponentsSummary string `json:"updatingComponentsSummary,omitempty"`
BlockedComponentsSummary string `json:"blockedComponentsSummary,omitempty"`
// Flow is an internal field that is needed to persist the chosen flow until the end of an update.
// Flow can be on of ""(unspecified), Stateless, Master, TabletNodes, Full and update cluster stage
// executes steps corresponding to that update flow.
Expand Down Expand Up @@ -854,6 +855,7 @@ type YtsaurusStatus struct {
//+kubebuilder:printcolumn:name="ClusterState",type="string",JSONPath=".status.state",description="State of Ytsaurus cluster"
//+kubebuilder:printcolumn:name="UpdateState",type="string",JSONPath=".status.updateStatus.state",description="Update state of Ytsaurus cluster"
//+kubebuilder:printcolumn:name="UpdatingComponents",type="string",JSONPath=".status.updateStatus.updatingComponentsSummary",description="Updating components"
//+kubebuilder:printcolumn:name="BlockedComponents",type="string",JSONPath=".status.updateStatus.blockedComponentsSummary",description="Blocked components"
//+kubebuilder:resource:path=ytsaurus,shortName=yt,categories=ytsaurus-all;yt-all
//+kubebuilder:subresource:status

Expand Down
6 changes: 6 additions & 0 deletions config/crd/bases/cluster.ytsaurus.tech_ytsaurus.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ spec:
jsonPath: .status.updateStatus.updatingComponentsSummary
name: UpdatingComponents
type: string
- description: Blocked components
jsonPath: .status.updateStatus.blockedComponentsSummary
name: BlockedComponents
type: string
name: v1
schema:
openAPIV3Schema:
Expand Down Expand Up @@ -42240,6 +42244,8 @@ spec:
type: string
updateStatus:
properties:
blockedComponentsSummary:
type: string
components:
description: 'Deprecated: Use updatingComponents instead.'
items:
Expand Down
55 changes: 24 additions & 31 deletions controllers/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,9 @@ func canUpdateComponent(selectors []ytv1.ComponentUpdateSelector, component ytv1
return false
}

// Considers spec and decides if operator should proceed with update or block.
// Block case is indicated with non-empty blockMsg.
// If update is not blocked, updateMeta containing a chosen flow and the component names to update returned.
func chooseUpdatingComponents(spec ytv1.YtsaurusSpec, needUpdate []ytv1.Component, allComponents []ytv1.Component) (components []ytv1.Component, blockMsg string) {
// Considers splits all the components in two groups: ones that can be updated and ones which update isblocked.
func chooseUpdatingComponents(spec ytv1.YtsaurusSpec, needUpdate []ytv1.Component, allComponents []ytv1.Component) (canUpdate []ytv1.Component, cannotUpdate []ytv1.Component) {
configuredSelectors := getEffectiveSelectors(spec)
var canUpdate []ytv1.Component
var cannotUpdate []ytv1.Component

for _, component := range needUpdate {
upd := canUpdateComponent(configuredSelectors, component)
Expand All @@ -56,21 +52,13 @@ func chooseUpdatingComponents(spec ytv1.YtsaurusSpec, needUpdate []ytv1.Componen
}

if len(canUpdate) == 0 {
if len(cannotUpdate) != 0 {
return nil, fmt.Sprintf("All components allowed by updateSelector are uptodate, update of {%v} is not allowed", cannotUpdate)
}
return nil, "All components are uptodate"
return nil, cannotUpdate
}

if hasEverythingSelector(configuredSelectors) {
if needFullUpdate(needUpdate) {
// Here we update not only components that are not up-to-date, but all cluster.
return allComponents, ""
} else {
return canUpdate, ""
}
if hasEverythingSelector(configuredSelectors) && needFullUpdate(needUpdate) {
// Here we update not only components that are not up-to-date, but all cluster.
return allComponents, nil
}
return canUpdate, ""
return canUpdate, cannotUpdate
}

func hasEverythingSelector(selectors []ytv1.ComponentUpdateSelector) bool {
Expand Down Expand Up @@ -204,20 +192,25 @@ func (r *YtsaurusReconciler) Sync(ctx context.Context, resource *ytv1.Ytsaurus)
needUpdateNames = append(needUpdateNames, c.GetFullName())
}
logger = logger.WithValues("componentsForUpdateAll", needUpdateNames)
updatingComponents, blockMsg := chooseUpdatingComponents(
canUpdate, cannotUpdate := chooseUpdatingComponents(
ytsaurus.GetResource().Spec, convertToComponent(needUpdate), convertToComponent(componentManager.allUpdatableComponents()))
if blockMsg != "" {
logger.Info(blockMsg)
return ctrl.Result{Requeue: true}, nil
}
logger.Info("Ytsaurus needs components update",
"componentsForUpdateSelected", updatingComponents)
ytsaurus.SyncObservedGeneration()
err = ytsaurus.SaveUpdatingClusterState(ctx, updatingComponents)
if err != nil {
return ctrl.Result{}, err

var logMsg string
var updStateErr error
if len(canUpdate) == 0 {
if len(cannotUpdate) != 0 {
logMsg = fmt.Sprintf("All components allowed by updateSelector are up-to-date, update of {%v} is not allowed", cannotUpdate)
} else {
logMsg = "All components are up-to-date"
}
updStateErr = ytsaurus.SaveBlockedComponentsState(ctx, cannotUpdate)
} else {
logMsg = fmt.Sprintf("Components {%v} will be updated, update of {%v} is not allowed", canUpdate, cannotUpdate)
ytsaurus.SyncObservedGeneration()
updStateErr = ytsaurus.SaveUpdatingClusterState(ctx, canUpdate, cannotUpdate)
}
return ctrl.Result{Requeue: true}, nil
logger.Info(logMsg)
return ctrl.Result{Requeue: true}, updStateErr
}

case ytv1.ClusterStateUpdating:
Expand Down
1 change: 1 addition & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2229,6 +2229,7 @@ _Appears in:_
| `components` _string array_ | Deprecated: Use updatingComponents instead. | | |
| `updatingComponents` _[Component](#component) array_ | | | |
| `updatingComponentsSummary` _string_ | UpdatingComponentsSummary is used only for representation in kubectl, since it only supports<br />"simple" JSONPath, and it is unclear how to force to print required data based on UpdatingComponents field. | | |
| `blockedComponentsSummary` _string_ | | | |
| `flow` _[UpdateFlow](#updateflow)_ | Flow is an internal field that is needed to persist the chosen flow until the end of an update.<br />Flow can be on of ""(unspecified), Stateless, Master, TabletNodes, Full and update cluster stage<br />executes steps corresponding to that update flow.<br />Deprecated: Use updatingComponents instead. | | |
| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#condition-v1-meta) array_ | | | |
| `tabletCellBundles` _[TabletCellBundleInfo](#tabletcellbundleinfo) array_ | | | |
Expand Down
38 changes: 31 additions & 7 deletions pkg/apiproxy/ytsaurus.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/log"

ytv1 "github.com/ytsaurus/ytsaurus-k8s-operator/api/v1"
"github.com/ytsaurus/ytsaurus-k8s-operator/pkg/consts"
)

type Ytsaurus struct {
Expand Down Expand Up @@ -82,11 +83,7 @@ func (c *Ytsaurus) ClearUpdateStatus(ctx context.Context) error {
}

func (c *Ytsaurus) syncUpdatingComponentsSummary() {
var componentNames []string
for _, comp := range c.ytsaurus.Status.UpdateStatus.UpdatingComponents {
componentNames = append(componentNames, comp.String())
}
c.ytsaurus.Status.UpdateStatus.UpdatingComponentsSummary = strings.Join(componentNames, ", ")
c.ytsaurus.Status.UpdateStatus.UpdatingComponentsSummary = buildComponentsSummary(c.ytsaurus.Status.UpdateStatus.UpdatingComponents)
}

func (c *Ytsaurus) LogUpdate(ctx context.Context, message string) {
Expand All @@ -95,10 +92,11 @@ func (c *Ytsaurus) LogUpdate(ctx context.Context, message string) {
logger.Info(fmt.Sprintf("Ytsaurus update: %s", message))
}

func (c *Ytsaurus) SaveUpdatingClusterState(ctx context.Context, components []ytv1.Component) error {
func (c *Ytsaurus) SaveUpdatingClusterState(ctx context.Context, canUpdate, cannotUpdate []ytv1.Component) error {
logger := log.FromContext(ctx)
c.ytsaurus.Status.State = ytv1.ClusterStateUpdating
c.ytsaurus.Status.UpdateStatus.UpdatingComponents = components
c.ytsaurus.Status.UpdateStatus.UpdatingComponents = canUpdate
c.ytsaurus.Status.UpdateStatus.BlockedComponentsSummary = buildComponentsSummary(cannotUpdate)
c.syncUpdatingComponentsSummary()

if err := c.apiProxy.UpdateStatus(ctx); err != nil {
Expand All @@ -109,6 +107,14 @@ func (c *Ytsaurus) SaveUpdatingClusterState(ctx context.Context, components []yt
return nil
}

func (c *Ytsaurus) SaveBlockedComponentsState(ctx context.Context, components []ytv1.Component) error {
c.ytsaurus.Status.UpdateStatus.BlockedComponentsSummary = buildComponentsSummary(components)
if err := c.apiProxy.UpdateStatus(ctx); err != nil {
return fmt.Errorf("unable to update Ytsaurus cluster status when setting blocked components")
}
return nil
}

func (c *Ytsaurus) SaveClusterState(ctx context.Context, clusterState ytv1.ClusterState) error {
logger := log.FromContext(ctx)
c.ytsaurus.Status.State = clusterState
Expand Down Expand Up @@ -162,3 +168,21 @@ func sortConditions(conditions []metav1.Condition) {
return a.LastTransitionTime.Compare(b.LastTransitionTime.Time)
})
}

func buildComponentsSummary(components []ytv1.Component) string {
if len(components) == 0 {
return ""
}
var componentNames []string
for _, comp := range components {
name := consts.GetShortName(comp.Type)
if name == "" {
name = strings.ToLower(string(comp.Type))
}
if comp.Name != "" {
name += fmt.Sprintf("/%s", comp.Name)
}
componentNames = append(componentNames, name)
}
return "{" + strings.Join(componentNames, " ") + "}"
}
27 changes: 26 additions & 1 deletion pkg/consts/names.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func ComponentServicePrefix(component ComponentType) string {
panic(fmt.Sprintf("No service is defined for component type: %s", component))
}

func ComponentStatefulSetPrefix(component ComponentType) string {
func GetStatefulSetPrefix(component ComponentType) string {
switch component {
case ControllerAgentType:
return "ca"
Expand Down Expand Up @@ -76,6 +76,31 @@ func ComponentStatefulSetPrefix(component ComponentType) string {
case YqlAgentType:
return "yqla"
}
return ""
}

func GetMicroservicePrefix(component ComponentType) string {
switch component {
case StrawberryControllerType:
return "strawberry"
case UIType:
return "ui"
}
return ""
}

func GetShortName(component ComponentType) string {
stsPrefix := GetStatefulSetPrefix(component)
if stsPrefix != "" {
return stsPrefix
}
return GetMicroservicePrefix(component)
}

func ComponentStatefulSetPrefix(component ComponentType) string {
shortTypeName := GetStatefulSetPrefix(component)
if shortTypeName != "" {
return shortTypeName
}
panic(fmt.Sprintf("No stateful set is defined for component type: %s", component))
}
6 changes: 6 additions & 0 deletions ytop-chart/templates/crds/ytsaurus.cluster.ytsaurus.tech.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ spec:
jsonPath: .status.updateStatus.updatingComponentsSummary
name: UpdatingComponents
type: string
- description: Blocked components
jsonPath: .status.updateStatus.blockedComponentsSummary
name: BlockedComponents
type: string
name: v1
schema:
openAPIV3Schema:
Expand Down Expand Up @@ -42251,6 +42255,8 @@ spec:
type: string
updateStatus:
properties:
blockedComponentsSummary:
type: string
components:
description: 'Deprecated: Use updatingComponents instead.'
items:
Expand Down

0 comments on commit 6628b3f

Please sign in to comment.