-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Expand file tree
/
Copy pathalicloud_auto_scaling_group.go
More file actions
230 lines (202 loc) · 7.53 KB
/
Copy pathalicloud_auto_scaling_group.go
File metadata and controls
230 lines (202 loc) · 7.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/*
Copyright 2018 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 alicloud
import (
"context"
"fmt"
apiv1 "k8s.io/api/core/v1"
klog "k8s.io/klog/v2"
"sigs.k8s.io/cluster-autoscaler/pkg/cloudprovider"
"sigs.k8s.io/cluster-autoscaler/pkg/config"
"sigs.k8s.io/cluster-autoscaler/pkg/simulator/framework"
)
// Asg implements NodeGroup interface.
type Asg struct {
manager *AliCloudManager
minSize int
maxSize int
regionId string
id string
}
// MaxSize returns maximum size of the node group.
func (asg *Asg) MaxSize(ctx context.Context) int {
return asg.maxSize
}
// MinSize returns minimum size of the node group.
func (asg *Asg) MinSize(ctx context.Context) int {
return asg.minSize
}
// TargetSize returns the current TARGET size of the node group. It is possible that the
// number is different from the number of nodes registered in Kubernetes.
func (asg *Asg) TargetSize(ctx context.Context) (int, error) {
size, err := asg.manager.GetAsgSize(asg)
return int(size), err
}
// IncreaseSize increases Asg size
func (asg *Asg) IncreaseSize(ctx context.Context, delta int) error {
klog.Infof("increase ASG:%s with %d nodes", asg.Id(), delta)
if delta <= 0 {
return fmt.Errorf("size increase must be positive")
}
size, err := asg.manager.GetAsgSize(asg)
if err != nil {
klog.Errorf("failed to get ASG size because of %s", err.Error())
return err
}
if int(size)+delta > asg.MaxSize(context.TODO()) {
return fmt.Errorf("size increase is too large - desired:%d max:%d", int(size)+delta, asg.MaxSize(context.TODO()))
}
return asg.manager.SetAsgSize(asg, size+int64(delta))
}
// AtomicIncreaseSize is not implemented.
func (asg *Asg) AtomicIncreaseSize(ctx context.Context, delta int) error {
return cloudprovider.ErrNotImplemented
}
// DecreaseTargetSize decreases the target size of the node group. This function
// doesn't permit to delete any existing node and can be used only to reduce the
// request for new nodes that have not been yet fulfilled. Delta should be negative.
// It is assumed that cloud provider will not delete the existing nodes if the size
// when there is an option to just decrease the target.
func (asg *Asg) DecreaseTargetSize(ctx context.Context, delta int) error {
klog.V(4).Infof("Aliyun: DecreaseTargetSize() with args: %v", delta)
if delta >= 0 {
return fmt.Errorf("size decrease size must be negative")
}
size, err := asg.manager.GetAsgSize(asg)
if err != nil {
klog.Errorf("failed to get ASG size because of %s", err.Error())
return err
}
nodes, err := asg.manager.GetAsgNodes(asg)
if err != nil {
klog.Errorf("failed to get ASG nodes because of %s", err.Error())
return err
}
if int(size)+delta < len(nodes) {
return fmt.Errorf("attempt to delete existing nodes targetSize:%d delta:%d existingNodes: %d",
size, delta, len(nodes))
}
return asg.manager.SetAsgSize(asg, size+int64(delta))
}
// Belongs returns true if the given node belongs to the NodeGroup.
func (asg *Asg) Belongs(node *apiv1.Node) (bool, error) {
instanceId, err := ecsInstanceIdFromProviderId(node.Spec.ProviderID)
if err != nil {
return false, err
}
targetAsg, err := asg.manager.GetAsgForInstance(instanceId)
if err != nil {
return false, err
}
if targetAsg == nil {
return false, fmt.Errorf("%s doesn't belong to a known Asg", node.Name)
}
if targetAsg.Id() != asg.Id() {
return false, nil
}
return true, nil
}
// DeleteNodes deletes the nodes from the group.
func (asg *Asg) DeleteNodes(ctx context.Context, nodes []*apiv1.Node) error {
size, err := asg.manager.GetAsgSize(asg)
if err != nil {
klog.Errorf("failed to get ASG size because of %s", err.Error())
return err
}
if int(size) <= asg.MinSize(context.TODO()) {
return fmt.Errorf("min size reached, nodes will not be deleted")
}
nodeIds := make([]string, 0, len(nodes))
for _, node := range nodes {
belongs, err := asg.Belongs(node)
if err != nil {
klog.Errorf("failed to check whether node:%s is belong to asg:%s", node.GetName(), asg.Id())
return err
}
if belongs != true {
return fmt.Errorf("%s belongs to a different asg than %s", node.Name, asg.Id())
}
instanceId, err := ecsInstanceIdFromProviderId(node.Spec.ProviderID)
if err != nil {
klog.Errorf("failed to find instanceId from providerId,because of %s", err.Error())
return err
}
nodeIds = append(nodeIds, instanceId)
}
return asg.manager.DeleteInstances(nodeIds)
}
// ForceDeleteNodes deletes nodes from the group regardless of constraints.
func (asg *Asg) ForceDeleteNodes(ctx context.Context, nodes []*apiv1.Node) error {
return cloudprovider.ErrNotImplemented
}
// Id returns asg id.
func (asg *Asg) Id() string {
return asg.id
}
// RegionId returns regionId of asg
func (asg *Asg) RegionId() string {
return asg.regionId
}
// Debug returns a debug string for the Asg.
func (asg *Asg) Debug(ctx context.Context) string {
return fmt.Sprintf("%s (%d:%d)", asg.Id(), asg.MinSize(context.TODO()), asg.MaxSize(context.TODO()))
}
// Nodes returns a list of all nodes that belong to this node group.
func (asg *Asg) Nodes(ctx context.Context) ([]cloudprovider.Instance, error) {
instanceNames, err := asg.manager.GetAsgNodes(asg)
if err != nil {
return nil, err
}
instances := make([]cloudprovider.Instance, 0, len(instanceNames))
for _, instanceName := range instanceNames {
instances = append(instances, cloudprovider.Instance{Id: instanceName})
}
return instances, nil
}
// TemplateNodeInfo returns a node template for this node group.
func (asg *Asg) TemplateNodeInfo(ctx context.Context) (*framework.NodeInfo, error) {
template, err := asg.manager.getAsgTemplate(asg.id)
if err != nil {
return nil, err
}
node, err := asg.manager.buildNodeFromTemplate(asg, template)
if err != nil {
klog.Errorf("failed to build instanceType:%v from template in ASG:%s,because of %s", template.InstanceType, asg.Id(), err.Error())
return nil, err
}
nodeInfo := framework.NewNodeInfo(node, nil, framework.NewPodInfo(cloudprovider.BuildKubeProxy(asg.id), nil))
return nodeInfo, nil
}
// Exist checks if the node group really exists on the cloud provider side. Allows to tell the
// theoretical node group from the real one.
func (asg *Asg) Exist(ctx context.Context) bool {
return true
}
// Create creates the node group on the cloud provider side.
func (asg *Asg) Create(ctx context.Context) (cloudprovider.NodeGroup, error) {
return nil, cloudprovider.ErrNotImplemented
}
// Autoprovisioned returns true if the node group is autoprovisioned.
func (asg *Asg) Autoprovisioned(ctx context.Context) bool {
return false
}
// Delete deletes the node group on the cloud provider side.
// This will be executed only for autoprovisioned node groups, once their size drops to 0.
func (asg *Asg) Delete(ctx context.Context) error {
return cloudprovider.ErrNotImplemented
}
// GetOptions returns NodeGroupAutoscalingOptions that should be used for this particular
// NodeGroup. Returning a nil will result in using default options.
func (asg *Asg) GetOptions(ctx context.Context, defaults config.NodeGroupAutoscalingOptions) (*config.NodeGroupAutoscalingOptions, error) {
return nil, cloudprovider.ErrNotImplemented
}