-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Separate ScaleDown logic with a new interface
- Loading branch information
Showing
5 changed files
with
290 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
/* | ||
Copyright 2016 The Kubernetes Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package legacy | ||
|
||
import ( | ||
"time" | ||
|
||
"k8s.io/autoscaler/cluster-autoscaler/core/scaledown" | ||
"k8s.io/autoscaler/cluster-autoscaler/core/scaledown/deletiontracker" | ||
"k8s.io/autoscaler/cluster-autoscaler/processors/status" | ||
"k8s.io/autoscaler/cluster-autoscaler/simulator" | ||
"k8s.io/autoscaler/cluster-autoscaler/simulator/utilization" | ||
"k8s.io/autoscaler/cluster-autoscaler/utils/errors" | ||
|
||
apiv1 "k8s.io/api/core/v1" | ||
policyv1 "k8s.io/api/policy/v1beta1" | ||
) | ||
|
||
// ScaleDownWrapper wraps legacy scaledown logic to satisfy scaledown.Planner & | ||
// scaledown.Actuator interfaces. | ||
type ScaleDownWrapper struct { | ||
sd *ScaleDown | ||
pdbs []*policyv1.PodDisruptionBudget | ||
} | ||
|
||
// NewScaleDownWrapper returns a new ScaleDownWrapper | ||
func NewScaleDownWrapper(sd *ScaleDown) *ScaleDownWrapper { | ||
return &ScaleDownWrapper{ | ||
sd: sd, | ||
} | ||
} | ||
|
||
// UpdateClusterState updates unneeded nodes in the underlying ScaleDown. | ||
func (p *ScaleDownWrapper) UpdateClusterState(podDestinations, scaleDownCandidates []*apiv1.Node, actuationStatus scaledown.ActuationStatus, pdbs []*policyv1.PodDisruptionBudget, currentTime time.Time) errors.AutoscalerError { | ||
p.sd.CleanUp(currentTime) | ||
p.pdbs = pdbs | ||
return p.sd.UpdateUnneededNodes(podDestinations, scaleDownCandidates, currentTime, pdbs) | ||
} | ||
|
||
// CleanUpUnneededNodes cleans up unneeded nodes. | ||
func (p *ScaleDownWrapper) CleanUpUnneededNodes() { | ||
p.sd.CleanUpUnneededNodes() | ||
} | ||
|
||
// NodesToDelete lists nodes to delete. Current implementation is a no-op, the | ||
// wrapper leverages shared state instead. | ||
// TODO(x13n): Implement this and get rid of sharing state between planning and | ||
// actuation. | ||
func (p *ScaleDownWrapper) NodesToDelete() (empty, needDrain []*apiv1.Node) { | ||
return nil, nil | ||
} | ||
|
||
// UnneededNodes returns a list of unneeded nodes. | ||
func (p *ScaleDownWrapper) UnneededNodes() []*apiv1.Node { | ||
return p.sd.UnneededNodes() | ||
} | ||
|
||
// UnremovableNodes returns a list of nodes that cannot be removed. | ||
func (p *ScaleDownWrapper) UnremovableNodes() []*simulator.UnremovableNode { | ||
return p.sd.UnremovableNodes() | ||
} | ||
|
||
// NodeUtilizationMap returns information about utilization of individual | ||
// cluster nodes. | ||
func (p *ScaleDownWrapper) NodeUtilizationMap() map[string]utilization.Info { | ||
return p.sd.NodeUtilizationMap() | ||
} | ||
|
||
// StartDeletion triggers an actual scale down logic. | ||
func (p *ScaleDownWrapper) StartDeletion(empty, needDrain []*apiv1.Node, currentTime time.Time) (*status.ScaleDownStatus, errors.AutoscalerError) { | ||
return p.sd.TryToScaleDown(currentTime, p.pdbs) | ||
} | ||
|
||
// CheckStatus snapshots current deletion status | ||
func (p *ScaleDownWrapper) CheckStatus() scaledown.ActuationStatus { | ||
// TODO: snapshot information from the tracker instead of keeping live | ||
// updated object. | ||
return &actuationStatus{ | ||
ndt: p.sd.nodeDeletionTracker, | ||
} | ||
} | ||
|
||
// ClearResultsNotNewerThan clears old node deletion results kept by the | ||
// Actuator. | ||
func (p *ScaleDownWrapper) ClearResultsNotNewerThan(t time.Time) { | ||
// TODO: implement this once results are not cleared while being | ||
// fetched. | ||
} | ||
|
||
type actuationStatus struct { | ||
ndt *deletiontracker.NodeDeletionTracker | ||
} | ||
|
||
// DeletionsInProgress returns node names of currently deleted nodes. | ||
// Current implementation is not aware of the actual nodes names, so it returns | ||
// a fake node name instead. | ||
// TODO: Return real node names | ||
func (a *actuationStatus) DeletionsInProgress() []string { | ||
if a.ndt.IsNonEmptyNodeDeleteInProgress() { | ||
return []string{"fake-node-name"} | ||
} | ||
return nil | ||
} | ||
|
||
// DeletionsCount returns total number of ongoing deletions in a given node | ||
// group. | ||
func (a *actuationStatus) DeletionsCount(nodeGroupId string) int { | ||
return a.ndt.GetDeletionsInProgress(nodeGroupId) | ||
} | ||
|
||
// RecentEvictions should return a list of recently evicted pods. Since legacy | ||
// scale down logic only drains at most one node at a time, this safeguard is | ||
// not really needed there, so we can just return an empty list. | ||
func (a *actuationStatus) RecentEvictions() []*apiv1.Pod { | ||
return nil | ||
} | ||
|
||
// DeletionResults returns a map of recent node deletion results. | ||
func (a *actuationStatus) DeletionResults() map[string]status.NodeDeleteResult { | ||
// TODO: update nodeDeletionTracker so it doesn't get & clear in the | ||
// same step. | ||
return a.ndt.GetAndClearNodeDeleteResults() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/* | ||
Copyright 2016 The Kubernetes Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package scaledown | ||
|
||
import ( | ||
"time" | ||
|
||
"k8s.io/autoscaler/cluster-autoscaler/processors/status" | ||
"k8s.io/autoscaler/cluster-autoscaler/simulator" | ||
"k8s.io/autoscaler/cluster-autoscaler/simulator/utilization" | ||
"k8s.io/autoscaler/cluster-autoscaler/utils/errors" | ||
|
||
apiv1 "k8s.io/api/core/v1" | ||
policyv1 "k8s.io/api/policy/v1beta1" | ||
) | ||
|
||
// Planner is responsible for selecting nodes that should be removed. | ||
type Planner interface { | ||
// UpdateClusterState provides the Planner with information about the cluster. | ||
UpdateClusterState(podDestinations, scaleDownCandidates []*apiv1.Node, as ActuationStatus, pdb []*policyv1.PodDisruptionBudget, currentTime time.Time) errors.AutoscalerError | ||
// CleanUpUnneededNodes resets internal state of the Planner. | ||
CleanUpUnneededNodes() | ||
// NodesToDelete returns a list of nodes that can be deleted right now, | ||
// according to the Planner. | ||
NodesToDelete() (empty, needDrain []*apiv1.Node) | ||
// UnneededNodes returns a list of nodes that either can be deleted | ||
// right now or in a near future, assuming nothing will change in the | ||
// cluster. | ||
UnneededNodes() []*apiv1.Node | ||
// UnremovableNodes returns a list of nodes that cannot be removed. | ||
// TODO(x13n): Add a guarantee that each node is either unneeded or | ||
// unremovable. This is not guaranteed by the current implementation. | ||
UnremovableNodes() []*simulator.UnremovableNode | ||
// NodeUtilizationMap returns information about utilization of | ||
// individual cluster nodes. | ||
NodeUtilizationMap() map[string]utilization.Info | ||
} | ||
|
||
// Actuator is responsible for making changes in the cluster: draining and | ||
// deleting nodes. | ||
type Actuator interface { | ||
// StartDeletion triggers a new deletion process. Nodes passed to this | ||
// function are not guaranteed to be deleted, it is possible for the | ||
// Actuator to ignore some of them e.g. if max configured level of | ||
// parallelism is reached. | ||
StartDeletion(empty, needDrain []*apiv1.Node, currentTime time.Time) (*status.ScaleDownStatus, errors.AutoscalerError) | ||
// CheckStatus returns an immutable snapshot of ongoing deletions. | ||
CheckStatus() ActuationStatus | ||
// ClearResultsNotNewerThan removes information about deletions finished | ||
// before or exactly at the provided timestamp. | ||
ClearResultsNotNewerThan(time.Time) | ||
} | ||
|
||
// ActuationStatus is used for feeding Actuator status back into Planner | ||
type ActuationStatus interface { | ||
// DeletionsInProgress returns a list of nodes that are currently | ||
// undergoing deletion. | ||
DeletionsInProgress() (nodeNames []string) | ||
// DeletionsCount returns total number of ongoing deletions in a given | ||
// node group. | ||
DeletionsCount(nodeGroupId string) int | ||
// RecentEvictions returns a list of pods that were recently removed by | ||
// the Actuator and hence are likely to get recreated elsewhere in the | ||
// cluster. | ||
RecentEvictions() (pods []*apiv1.Pod) | ||
// DeletionResults returns a map of recent node deletion results, keyed | ||
// by the node name. Note: if node deletion was scheduled more than | ||
// once, only the latest result will be present. | ||
DeletionResults() map[string]status.NodeDeleteResult | ||
} |
Oops, something went wrong.