-
Notifications
You must be signed in to change notification settings - Fork 6
/
flag.go
204 lines (173 loc) · 7.65 KB
/
flag.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
package nodepool
import (
"fmt"
"regexp"
"github.com/giantswarm/microerror"
"github.com/spf13/cobra"
"github.com/giantswarm/kubectl-gs/internal/key"
)
const (
flagProvider = "provider"
// AWS only.
flagAWSInstanceType = "aws-instance-type"
flagMachineDeploymentSubnet = "machine-deployment-subnet"
flagOnDemandBaseCapacity = "on-demand-base-capacity"
flagOnDemandPercentageAboveBaseCapacity = "on-demand-percentage-above-base-capacity"
flagUseAlikeInstanceTypes = "use-alike-instance-types"
// Azure only.
flagAzureVMSize = "azure-vm-size"
flagAzureUseSpotVMs = "azure-spot-vms"
flagAzureSpotVMsMaxPrice = "azure-spot-vms-max-price"
// Common.
flagAvailabilityZones = "availability-zones"
flagClusterID = "cluster-id"
flagNodepoolName = "nodepool-name"
flagNodesMax = "nodes-max"
flagNodesMin = "nodes-min"
flagNodexMax = "nodex-max"
flagNodexMin = "nodex-min"
flagOutput = "output"
flagOwner = "owner"
flagRelease = "release"
)
const (
minNodes = 3
maxNodes = 10
)
type flag struct {
Provider string
// AWS only.
AWSInstanceType string
MachineDeploymentSubnet string
OnDemandBaseCapacity int
OnDemandPercentageAboveBaseCapacity int
UseAlikeInstanceTypes bool
// Azure only.
AzureVMSize string
AzureUseSpotVms bool
AzureSpotVMsMaxPrice float32
// Common.
AvailabilityZones []string
ClusterID string
NodepoolName string
NodesMax int
NodesMin int
Output string
Owner string
Release string
// Deprecated
// Can be removed in a future version around March 2021 or later.
NodexMin int
NodexMax int
}
func (f *flag) Init(cmd *cobra.Command) {
cmd.Flags().StringVar(&f.Provider, flagProvider, "", "Installation infrastructure provider.")
// AWS only.
cmd.Flags().StringVar(&f.AWSInstanceType, flagAWSInstanceType, "m5.xlarge", "EC2 instance type to use for workers, e. g. 'm5.2xlarge'.")
cmd.Flags().StringVar(&f.MachineDeploymentSubnet, flagMachineDeploymentSubnet, "", "Subnet used for the Node Pool.")
cmd.Flags().IntVar(&f.OnDemandBaseCapacity, flagOnDemandBaseCapacity, 0, "Number of base capacity for On demand instance distribution. Default is 0. Only available on AWS.")
cmd.Flags().IntVar(&f.OnDemandPercentageAboveBaseCapacity, flagOnDemandPercentageAboveBaseCapacity, 100, "Percentage above base capacity for On demand instance distribution. Default is 100. Only available on AWS.")
cmd.Flags().BoolVar(&f.UseAlikeInstanceTypes, flagUseAlikeInstanceTypes, false, "Whether to use similar instances types as a fallback. Only available on AWS.")
// Azure only.
cmd.Flags().StringVar(&f.AzureVMSize, flagAzureVMSize, "Standard_D4s_v3", "Azure VM size to use for workers, e.g. 'Standard_D4s_v3'.")
cmd.Flags().BoolVar(&f.AzureUseSpotVms, flagAzureUseSpotVMs, false, "Whether to use Spot VMs for this Node Pool. Defaults to false. Only available on Azure.")
cmd.Flags().Float32Var(&f.AzureSpotVMsMaxPrice, flagAzureSpotVMsMaxPrice, 0, "Max hourly price in USD to pay for one spot VM on Azure. If not set, the on-demand price is used as the limit.")
// Common.
cmd.Flags().StringSliceVar(&f.AvailabilityZones, flagAvailabilityZones, []string{}, "List of availability zones to use, instead of setting a number. Use comma to separate values.")
cmd.Flags().StringVar(&f.ClusterID, flagClusterID, "", "Workload cluster ID.")
cmd.Flags().StringVar(&f.NodepoolName, flagNodepoolName, "Unnamed node pool", "NodepoolName or purpose description of the node pool.")
cmd.Flags().IntVar(&f.NodesMax, flagNodesMax, maxNodes, fmt.Sprintf("Maximum number of worker nodes for the node pool. (default %d)", maxNodes))
cmd.Flags().IntVar(&f.NodesMin, flagNodesMin, minNodes, fmt.Sprintf("Minimum number of worker nodes for the node pool. (default %d)", minNodes))
cmd.Flags().StringVar(&f.Output, flagOutput, "", "File path for storing CRs. (default: stdout)")
cmd.Flags().StringVar(&f.Owner, flagOwner, "", "Workload cluster owner organization.")
cmd.Flags().StringVar(&f.Release, flagRelease, "", "Workload cluster release. If not given, this remains empty to match the workload cluster version via the Management API.")
// This can be removed in a future version around March 2021 or later.
cmd.Flags().IntVar(&f.NodexMax, flagNodexMax, 0, "")
cmd.Flags().IntVar(&f.NodexMin, flagNodexMin, 0, "")
_ = cmd.Flags().MarkDeprecated(flagNodexMax, "")
_ = cmd.Flags().MarkDeprecated(flagNodexMin, "")
}
func (f *flag) Validate() error {
if f.Provider != key.ProviderAWS && f.Provider != key.ProviderAzure {
return microerror.Maskf(invalidFlagError, "--%s must be either aws or azure", flagProvider)
}
{
// Validate machine type.
switch f.Provider {
case key.ProviderAWS:
if f.AWSInstanceType == "" {
return microerror.Maskf(invalidFlagError, "--%s must not be empty", flagAWSInstanceType)
}
case key.ProviderAzure:
if f.AzureVMSize == "" {
return microerror.Maskf(invalidFlagError, "--%s must not be empty", flagAzureVMSize)
}
}
}
if f.MachineDeploymentSubnet != "" {
matchedSubnet, err := regexp.MatchString("^20|21|22|23|24|25|26|27|28$", f.MachineDeploymentSubnet)
if err == nil && !matchedSubnet {
return microerror.Maskf(invalidFlagError, "--%s must be a valid subnet size (20, 21, 22, 23, 24,25, 26, 27 or 28)", flagMachineDeploymentSubnet)
}
}
if f.ClusterID == "" {
return microerror.Maskf(invalidFlagError, "--%s must not be empty", flagClusterID)
}
if f.NodepoolName == "" {
return microerror.Maskf(invalidFlagError, "--%s must not be empty", flagNodepoolName)
}
{
if f.NodexMin > 0 {
return microerror.Maskf(invalidFlagError, "please use --nodes-min instead of --nodex-min")
}
if f.NodexMax > 0 {
return microerror.Maskf(invalidFlagError, "please use --nodes-max instead of --nodex-max")
}
// Validate scaling.
if f.NodesMax < 0 {
return microerror.Maskf(invalidFlagError, "--%s must be >= 0", flagNodesMax)
}
if f.NodesMin < 0 {
return microerror.Maskf(invalidFlagError, "--%s must be >= 0", flagNodesMin)
}
if f.NodesMin > f.NodesMax {
return microerror.Maskf(invalidFlagError, "--%s must be <= --%s", flagNodesMin, flagNodesMax)
}
}
if f.Owner == "" {
return microerror.Maskf(invalidFlagError, "--%s must not be empty", flagOwner)
}
{
// Validate Availability Zones.
var azs []string
var numOfAZs int
{
if len(f.AvailabilityZones) > 0 {
azs = f.AvailabilityZones
numOfAZs = len(azs)
}
}
// XXX: The availability zones can be set to nil on Azure.
// https://github.com/giantswarm/giantswarm/issues/12860
if f.Provider == key.ProviderAWS && numOfAZs < 1 {
return microerror.Maskf(invalidFlagError, "--%s must be configured with at least 1 AZ", flagAvailabilityZones)
}
}
{
// Validate Spot instances.
switch f.Provider {
case key.ProviderAWS:
if f.OnDemandBaseCapacity < 0 {
return microerror.Maskf(invalidFlagError, "--%s must be greater than 0", flagOnDemandBaseCapacity)
}
if f.OnDemandPercentageAboveBaseCapacity < 0 || f.OnDemandPercentageAboveBaseCapacity > 100 {
return microerror.Maskf(invalidFlagError, "--%s must be greater than 0 and lower than 100", flagOnDemandPercentageAboveBaseCapacity)
}
case key.ProviderAzure:
if f.OnDemandBaseCapacity != 0 || f.OnDemandPercentageAboveBaseCapacity != 100 || f.UseAlikeInstanceTypes {
return microerror.Maskf(invalidFlagError, "--%s, --%s and --%s spot instances flags are not supported on Azure.", flagOnDemandBaseCapacity, flagOnDemandPercentageAboveBaseCapacity, flagUseAlikeInstanceTypes)
}
}
}
return nil
}