forked from kubernetes/kops
/
instancegroup.go
221 lines (193 loc) · 8.24 KB
/
instancegroup.go
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
/*
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 kops
import (
"fmt"
"github.com/golang/glog"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
const LabelClusterName = "kops.k8s.io/cluster"
// NodeLabelInstanceGroup is a node label set to the name of the instance group
const NodeLabelInstanceGroup = "kops.k8s.io/instancegroup"
// Deprecated - use the new labels & taints node-role.kubernetes.io/master and node-role.kubernetes.io/node
const TaintNoScheduleMaster15 = "dedicated=master:NoSchedule"
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// InstanceGroup represents a group of instances (either nodes or masters) with the same configuration
type InstanceGroup struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec InstanceGroupSpec `json:"spec,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type InstanceGroupList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []InstanceGroup `json:"items"`
}
// InstanceGroupRole describes the roles of the nodes in this InstanceGroup (master or nodes)
type InstanceGroupRole string
const (
InstanceGroupRoleMaster InstanceGroupRole = "Master"
InstanceGroupRoleNode InstanceGroupRole = "Node"
InstanceGroupRoleBastion InstanceGroupRole = "Bastion"
)
// AllInstanceGroupRoles is a slice of all valid InstanceGroupRole values
var AllInstanceGroupRoles = []InstanceGroupRole{
InstanceGroupRoleNode,
InstanceGroupRoleMaster,
InstanceGroupRoleBastion,
}
// InstanceGroupSpec is the specification for a instanceGroup
type InstanceGroupSpec struct {
// Type determines the role of instances in this group: masters or nodes
Role InstanceGroupRole `json:"role,omitempty"`
// Image is the instance (ami etc) we should use
Image string `json:"image,omitempty"`
// MinSize is the minimum size of the pool
MinSize *int32 `json:"minSize,omitempty"`
// MaxSize is the maximum size of the pool
MaxSize *int32 `json:"maxSize,omitempty"`
// MachineType is the instance class
MachineType string `json:"machineType,omitempty"`
// RootVolumeSize is the size of the EBS root volume to use, in GB
RootVolumeSize *int32 `json:"rootVolumeSize,omitempty"`
// RootVolumeType is the type of the EBS root volume to use (e.g. gp2)
RootVolumeType *string `json:"rootVolumeType,omitempty"`
// If volume type is io1, then we need to specify the number of Iops.
RootVolumeIops *int32 `json:"rootVolumeIops,omitempty"`
// RootVolumeOptimization enables EBS optimization for an instance
RootVolumeOptimization *bool `json:"rootVolumeOptimization,omitempty"`
// Subnets is the names of the Subnets (as specified in the Cluster) where machines in this instance group should be placed
Subnets []string `json:"subnets,omitempty"`
// Zones is the names of the Zones where machines in this instance group should be placed
// This is needed for regional subnets (e.g. GCE), to restrict placement to particular zones
Zones []string `json:"zones,omitempty"`
// Hooks is a list of hooks for this instanceGroup, note: these can override the cluster wide ones if required
Hooks []HookSpec `json:"hooks,omitempty"`
// MaxPrice indicates this is a spot-pricing group, with the specified value as our max-price bid
MaxPrice *string `json:"maxPrice,omitempty"`
// AssociatePublicIP is true if we want instances to have a public IP
AssociatePublicIP *bool `json:"associatePublicIp,omitempty"`
// AdditionalSecurityGroups attaches additional security groups (e.g. i-123456)
AdditionalSecurityGroups []string `json:"additionalSecurityGroups,omitempty"`
// CloudLabels indicates the labels for instances in this group, at the AWS level
CloudLabels map[string]string `json:"cloudLabels,omitempty"`
// NodeLabels indicates the kubernetes labels for nodes in this group
NodeLabels map[string]string `json:"nodeLabels,omitempty"`
// FileAssets is a collection of file assets for this instance group
FileAssets []FileAssetSpec `json:"fileAssets,omitempty"`
// Describes the tenancy of the instance group. Can be either default or dedicated.
// Currently only applies to AWS.
Tenancy string `json:"tenancy,omitempty"`
// Kubelet overrides kubelet config from the ClusterSpec
Kubelet *KubeletConfigSpec `json:"kubelet,omitempty"`
// Taints indicates the kubernetes taints for nodes in this group
Taints []string `json:"taints,omitempty"`
// AdditionalUserData is any additional user-data to be passed to the host
AdditionalUserData []UserData `json:"additionalUserData,omitempty"`
// SuspendProcesses disables the listed Scaling Policies
SuspendProcesses []string `json:"suspendProcesses,omitempty"`
// ExternalLoadBalancers define loadbalancers that should be attached to the instancegroup
ExternalLoadBalancers []LoadBalancer `json:"externalLoadBalancers,omitempty"`
// DetailedInstanceMonitoring defines if detailed-monitoring is enabled (AWS only)
DetailedInstanceMonitoring *bool `json:"detailedInstanceMonitoring,omitempty"`
// IAMProfileSpec defines the identity of the cloud group iam profile (AWS only).
IAM *IAMProfileSpec `json:"iam,omitempty"`
// SecurityGroupOverride overrides the default security group created by Kops for this IG (AWS only).
SecurityGroupOverride *string `json:"securityGroupOverride,omitempty"`
}
// UserData defines a user-data section
type UserData struct {
// Name is the name of the user-data
Name string `json:"name,omitempty"`
// Type is the type of user-data
Type string `json:"type,omitempty"`
// Content is the user-data content
Content string `json:"content,omitempty"`
}
// IAMProfileSpec is the AWS IAM Profile to attach to instances in this instance
// group. Specify the ARN for the IAM instance profile (AWS only).
type IAMProfileSpec struct {
// Profile is the AWS IAM Profile to attach to instances in this instance group.
// Specify the ARN for the IAM instance profile. (AWS only)
Profile *string `json:"profile,omitempty"`
}
// PerformAssignmentsInstanceGroups populates InstanceGroups with default values
func PerformAssignmentsInstanceGroups(groups []*InstanceGroup) error {
names := map[string]bool{}
for _, group := range groups {
names[group.ObjectMeta.Name] = true
}
for _, group := range groups {
// We want to give them a stable Name as soon as possible
if group.ObjectMeta.Name == "" {
// Loop to find the first unassigned name like `nodes-%d`
i := 0
for {
key := fmt.Sprintf("nodes-%d", i)
if !names[key] {
group.ObjectMeta.Name = key
names[key] = true
break
}
i++
}
}
}
return nil
}
// IsMaster checks if instanceGroup is a master
func (g *InstanceGroup) IsMaster() bool {
switch g.Spec.Role {
case InstanceGroupRoleMaster:
return true
case InstanceGroupRoleNode:
return false
case InstanceGroupRoleBastion:
return false
default:
glog.Fatalf("Role not set in group %v", g)
return false
}
}
// IsBastion checks if instanceGroup is a bastion
func (g *InstanceGroup) IsBastion() bool {
switch g.Spec.Role {
case InstanceGroupRoleMaster:
return false
case InstanceGroupRoleNode:
return false
case InstanceGroupRoleBastion:
return true
default:
glog.Fatalf("Role not set in group %v", g)
return false
}
}
func (g *InstanceGroup) AddInstanceGroupNodeLabel() {
if g.Spec.NodeLabels == nil {
nodeLabels := make(map[string]string)
nodeLabels[NodeLabelInstanceGroup] = g.Name
g.Spec.NodeLabels = nodeLabels
} else {
g.Spec.NodeLabels[NodeLabelInstanceGroup] = g.Name
}
}
// LoadBalancers defines a load balancer
type LoadBalancer struct {
// LoadBalancerName to associate with this instance group (AWS ELB)
LoadBalancerName *string `json:"loadBalancerName,omitempty"`
// TargetGroupARN to associate with this instance group (AWS ALB/NLB)
TargetGroupARN *string `json:"targetGroupArn,omitempty"`
}