Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 30 additions & 17 deletions internal/view/scale_extender.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,20 +109,13 @@ func (s *ScaleExtender) replicasFromReady(_ string) (string, error) {
}

func (s *ScaleExtender) replicasFromScaleSubresource(sel string) (string, error) {
res, err := dao.AccessorFor(s.App().factory, s.GVR())
if err != nil {
return "", err
}

replicasGetter, ok := res.(dao.ReplicasGetter)
if !ok {
return "", fmt.Errorf("expecting a replicasGetter resource for %q", s.GVR())
}

var scaler dao.Scaler
scaler.Init(s.App().factory, s.GVR())

ctx, cancel := context.WithTimeout(context.Background(), s.App().Conn().Config().CallTimeout())
defer cancel()

replicas, err := replicasGetter.Replicas(ctx, sel)
replicas, err := scaler.Replicas(ctx, sel)
if err != nil {
return "", err
}
Expand All @@ -131,7 +124,9 @@ func (s *ScaleExtender) replicasFromScaleSubresource(sel string) (string, error)
}

func (s *ScaleExtender) makeScaleForm(fqns []string) (*tview.Form, error) {
factor := "0"
// Use empty string as the "unknown" sentinel so a legitimate current
// replica count of 0 (e.g., paused workload) is not treated as failure.
factor := ""
if len(fqns) == 1 {
// If the CRD resource supports scaling, then first try to
// read the replicas directly from the CRD.
Expand All @@ -144,14 +139,30 @@ func (s *ScaleExtender) makeScaleForm(fqns []string) (*tview.Form, error) {

// For built-in resources or cases where we can't get the replicas from the CRD, we can
// only try to get the number of copies from the READY field.
if factor == "0" {
var readyErr error
if factor == "" {
replicas, err := s.replicasFromReady(fqns[0])
if err != nil {
return nil, err
if err == nil {
factor = replicas
} else {
readyErr = err
slog.Warn("Unable to read replicas from ready column", slogs.Error, err)
}
}

factor = replicas
// Refuse to open the dialog when we cannot determine the current
// replica count — otherwise a user hitting OK without editing would
// silently scale the workload to zero.
if factor == "" {
if readyErr != nil {
return nil, fmt.Errorf("unable to determine current replica count: %w", readyErr)
}
return nil, fmt.Errorf("unable to determine current replica count for %s", fqns[0])
}
} else {
// Bulk-scale: there is no single "current" value to pre-fill, so the
// user must explicitly enter a target. Keep the documented default.
factor = "0"
}

styles := s.App().Styles.Dialog()
Expand Down Expand Up @@ -222,7 +233,9 @@ func (s *ScaleExtender) scale(ctx context.Context, path string, replicas int32)
}
scaler, ok := res.(dao.Scalable)
if !ok {
return fmt.Errorf("expecting a scalable resource for %q", s.GVR())
var genericScaler dao.Scaler
genericScaler.Init(s.App().factory, s.GVR())
return genericScaler.Scale(ctx, path, replicas)
}

return scaler.Scale(ctx, path, replicas)
Expand Down