Sitelet https://github.com/kubernetes/kops/commit/a3da1780fdb64c808cadf5ea5c79d386c22f3932
Skip to content

Commit a3da178

Browse files
Merge pull request #18640 from cheftako/channelLabels
Adding dynamic channel labels
2 parents 91684c7 + 2b515b4 commit a3da178

104 files changed

Lines changed: 508 additions & 54 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎channels/pkg/cmd/apply_channel.go‎

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"net/url"
2424
"os"
2525
"os/signal"
26+
"strings"
2627
"syscall"
2728
"time"
2829

@@ -46,15 +47,24 @@ type ApplyChannelOptions struct {
4647
Yes bool
4748
Interval time.Duration
4849
NodeName string
50+
51+
// Comma delimited label,value pairs to add to the node. Eg "kops.k8s.io/cloud-controller-manager,foo=bar"
52+
NodeLabels map[string]string
4953
}
5054

5155
func NewCmdApplyChannel(f *ChannelsFactory, out io.Writer) *cobra.Command {
5256
var options ApplyChannelOptions
57+
var rawLabels string
5358

5459
cmd := &cobra.Command{
5560
Use: "channel CHANNEL...",
5661
Short: "Applies updates from the given channel(s)",
5762
RunE: func(cmd *cobra.Command, args []string) error {
63+
var err error
64+
options.NodeLabels, err = parseLabels(rawLabels)
65+
if err != nil {
66+
return err
67+
}
5868
if options.Interval > 0 {
5969
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
6070
defer cancel()
@@ -67,10 +77,27 @@ func NewCmdApplyChannel(f *ChannelsFactory, out io.Writer) *cobra.Command {
6777
cmd.Flags().BoolVar(&options.Yes, "yes", false, "Apply update")
6878
cmd.Flags().DurationVar(&options.Interval, "interval", 0, "If non-zero, re-apply the channel on this interval until interrupted (e.g. 60s)")
6979
cmd.Flags().StringVar(&options.NodeName, "node-name", "", "If set, patch the named node with the mandatory control-plane labels each iteration; typically supplied via the downward API.")
80+
cmd.Flags().StringVar(&rawLabels, "node-labels", "", "If set, patch the named node with each of the label,value pairs each iteration; typically supplied via the downward API.")
7081

7182
return cmd
7283
}
7384

85+
func parseLabels(rawLabels string) (map[string]string, error) {
86+
labels := make(map[string]string)
87+
pairs := strings.Split(rawLabels, ",")
88+
for _, rawpair := range pairs {
89+
pair := strings.Split(rawpair, "=")
90+
if len(pair) > 2 {
91+
return nil, fmt.Errorf("Error too many '=' (%d) in %s", len(pair), pair)
92+
} else if len(pair) == 2 {
93+
labels[pair[0]] = pair[1]
94+
} else {
95+
labels[rawpair] = ""
96+
}
97+
}
98+
return labels, nil
99+
}
100+
74101
// runApplyChannelIteration patches node labels (when --node-name is set) then
75102
// applies the channel. Labels go first so addons targeting the control-plane
76103
// label can schedule on the local node as soon as their manifests land.
@@ -80,7 +107,7 @@ func runApplyChannelIteration(ctx context.Context, f *ChannelsFactory, out io.Wr
80107
labelerClient, err := f.KubernetesClient()
81108
if err != nil {
82109
merr = multierr.Append(merr, fmt.Errorf("building kubernetes client for node labeler: %w", err))
83-
} else if err := nodelabeler.BootstrapControlPlaneNodeLabels(ctx, labelerClient, options.NodeName); err != nil {
110+
} else if err := nodelabeler.BootstrapControlPlaneNodeLabels(ctx, labelerClient, options.NodeName, options.NodeLabels); err != nil {
84111
merr = multierr.Append(merr, fmt.Errorf("bootstrapping node labels: %w", err))
85112
}
86113
}

‎channels/pkg/nodelabeler/labeler.go‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ type nodePatchMetadata struct {
3838

3939
// BootstrapControlPlaneNodeLabels applies labels to the current node so that it acts as a control-plane.
4040
// Safe to call repeatedly: the patch is skipped when the labels already match.
41-
func BootstrapControlPlaneNodeLabels(ctx context.Context, client kubernetes.Interface, nodeName string) error {
41+
func BootstrapControlPlaneNodeLabels(ctx context.Context, client kubernetes.Interface, nodeName string, nodeLabels map[string]string) error {
4242
if nodeName == "" {
4343
return fmt.Errorf("node name is required")
4444
}
@@ -49,7 +49,7 @@ func BootstrapControlPlaneNodeLabels(ctx context.Context, client kubernetes.Inte
4949
return fmt.Errorf("querying node %q: %w", nodeName, err)
5050
}
5151

52-
labels := nodelabels.BuildMandatoryControlPlaneLabels()
52+
labels := nodelabels.BuildMandatoryControlPlaneLabels(nodeLabels)
5353

5454
shouldPatch := false
5555
for k, v := range labels {

‎cmd/kops/create_cluster.go‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,6 @@ func NewCmdCreateCluster(f *util.Factory, out io.Writer) *cobra.Command {
305305
if featureflag.ExperimentalRoles.Enabled() {
306306
cmd.Flags().Int32Var(&options.EtcdCount, "etcd-count", options.EtcdCount, "Number of etcd nodes. Defaults to 0.")
307307
cmd.Flags().Int32Var(&options.SchedulerCount, "scheduler-count", options.SchedulerCount, "Number of scheduler nodes. Defaults to 0.")
308-
cmd.Flags().Int32Var(&options.CloudControllerManagerCount, "ccm-count", options.CloudControllerManagerCount, "Number of cloud-controller-manager nodes. Defaults to 0.")
309308
cmd.Flags().Int32Var(&options.KubeControllerManagerCount, "kcm-count", options.KubeControllerManagerCount, "Number of kube-controller-manager nodes. Defaults to 0.")
310309
}
311310

@@ -335,8 +334,6 @@ func NewCmdCreateCluster(f *util.Factory, out io.Writer) *cobra.Command {
335334
cmd.RegisterFlagCompletionFunc("etcd-size", completeMachineType)
336335
cmd.Flags().StringSliceVar(&options.SchedulerSizes, "scheduler-size", options.SchedulerSizes, "Machine type(s) for scheduler nodes")
337336
cmd.RegisterFlagCompletionFunc("scheduler-size", completeMachineType)
338-
cmd.Flags().StringSliceVar(&options.CloudControllerManagerSizes, "ccm-size", options.CloudControllerManagerSizes, "Machine type(s) for cloud-controller-manager nodes")
339-
cmd.RegisterFlagCompletionFunc("ccm-size", completeMachineType)
340337
cmd.Flags().StringSliceVar(&options.KubeControllerManagerSizes, "kcm-size", options.KubeControllerManagerSizes, "Machine type(s) for kube-controller-manager nodes")
341338
cmd.RegisterFlagCompletionFunc("kcm-size", completeMachineType)
342339
}

‎cmd/kops/create_cluster_integration_test.go‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,14 @@ func TestCreateClusterGCE(t *testing.T) {
134134
runCreateClusterIntegrationTest(t, "../../tests/integration/create_cluster/gce_byo_sa", "v1alpha2")
135135
}
136136

137+
// TestCreateClusterExperimentalRoles tests kops create cluster with ExperimentalRoles and control-plane-count=0
138+
func TestCreateClusterExperimentalRoles(t *testing.T) {
139+
featureflag.ParseFlags("+APIServerNodes,+ExperimentalRoles")
140+
defer featureflag.ParseFlags("-APIServerNodes,-ExperimentalRoles")
141+
142+
runCreateClusterIntegrationTest(t, "../../tests/integration/create_cluster/experimental-roles", "v1alpha2")
143+
}
144+
137145
// TestCreateClusterHASharedZone tests kops create cluster when the master count is bigger than the number of zones
138146
func TestCreateClusterHASharedZone(t *testing.T) {
139147
runCreateClusterIntegrationTest(t, "../../tests/integration/create_cluster/ha_shared_zone", "v1alpha2")

‎cmd/kops/create_instancegroup.go‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,7 @@ func NewCmdCreateInstanceGroup(f *util.Factory, out io.Writer) *cobra.Command {
139139
if r.HasScheduler() {
140140
continue
141141
}
142-
if r.HasCloudControllerManager() {
143-
continue
144-
}
145-
if r.HasKubControllerManager() {
142+
if r.HasKubeControllerManager() {
146143
continue
147144
}
148145
}

‎docs/cli/kops_rolling-update_cluster.md‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎docs/cli/kops_update_cluster.md‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎hack/verify-ig-role-comparisons.sh‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ files=$(find . -name "*.go" -not -path "./vendor/*" -not -path "./.build/*" -not
3434
# constant == variable
3535
# variable != constant
3636
# constant != variable
37-
REGEX='==[[:space:]]*([a-zA-Z0-9_]+\.)?InstanceGroupRole(ControlPlane|Node|Bastion|APIServer|Etcd|Scheduler|CloudControllerManager|KubeControllerManager)\b|\b([a-zA-Z0-9_]+\.)?InstanceGroupRole(ControlPlane|Node|Bastion|APIServer)[[:space:]]*==|!=[[:space:]]*([a-zA-Z0-9_]+\.)?InstanceGroupRole(ControlPlane|Node|Bastion|APIServer)\b|\b([a-zA-Z0-9_]+\.)?InstanceGroupRole(ControlPlane|Node|Bastion|APIServer)[[:space:]]*!='
37+
REGEX='==[[:space:]]*([a-zA-Z0-9_]+\.)?InstanceGroupRole(ControlPlane|Node|Bastion|APIServer|Etcd|Scheduler|KubeControllerManager)\b|\b([a-zA-Z0-9_]+\.)?InstanceGroupRole(ControlPlane|Node|Bastion|APIServer)[[:space:]]*==|!=[[:space:]]*([a-zA-Z0-9_]+\.)?InstanceGroupRole(ControlPlane|Node|Bastion|APIServer)\b|\b([a-zA-Z0-9_]+\.)?InstanceGroupRole(ControlPlane|Node|Bastion|APIServer)[[:space:]]*!='
3838

3939
for file in $files; do
4040
if grep -E "${REGEX}" "${file}" > /dev/null; then
@@ -45,7 +45,7 @@ for file in $files; do
4545
done
4646

4747
if [ "${errors}" -ne 0 ]; then
48-
echo "Error: Found ${errors} files with direct InstanceGroupRole comparisons (== or !=). Use HasControlPlane(), HasNode(), HasBastion(), HasAPIServer(), HasEtcd(), HasScheduler(), HasCloudControllerManager() or HasKubeControllerManager() instead."
48+
echo "Error: Found ${errors} files with direct InstanceGroupRole comparisons (== or !=). Use HasControlPlane(), HasNode(), HasBastion(), HasAPIServer(), HasEtcd(), HasScheduler() or HasKubeControllerManager() instead."
4949
exit 1
5050
fi
5151

‎pkg/apis/kops/instancegroup.go‎

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,8 @@ const (
6767
InstanceGroupRoleEtcd InstanceGroupRole = "Etcd"
6868
// InstanceGroupRoleScheduler is a Scheduler role.
6969
InstanceGroupRoleScheduler InstanceGroupRole = "Scheduler"
70-
// InstanceGroupRoleCloudControllerManager is a CloudControllerManager role.
71-
InstanceGroupRoleCloudControllerManager InstanceGroupRole = "CloudControllerManager"
72-
// InstanceGroupRoleKubControllerManager is a KubControllerManager role.
73-
InstanceGroupRoleKubControllerManager InstanceGroupRole = "KubControllerManager"
70+
// InstanceGroupRoleKubeControllerManager is a KubeControllerManager role.
71+
InstanceGroupRoleKubeControllerManager InstanceGroupRole = "KubeControllerManager"
7472
)
7573

7674
// AllInstanceGroupRoles is a slice of all valid InstanceGroupRole values
@@ -79,6 +77,9 @@ var AllInstanceGroupRoles = []InstanceGroupRole{
7977
InstanceGroupRoleAPIServer,
8078
InstanceGroupRoleNode,
8179
InstanceGroupRoleBastion,
80+
InstanceGroupRoleEtcd,
81+
InstanceGroupRoleScheduler,
82+
InstanceGroupRoleKubeControllerManager,
8283
}
8384

8485
func (r InstanceGroupRole) HasControlPlane() bool {
@@ -105,16 +106,12 @@ func (r InstanceGroupRole) HasScheduler() bool {
105106
return r == InstanceGroupRoleScheduler
106107
}
107108

108-
func (r InstanceGroupRole) HasCloudControllerManager() bool {
109-
return r == InstanceGroupRoleCloudControllerManager
110-
}
111-
112-
func (r InstanceGroupRole) HasKubControllerManager() bool {
113-
return r == InstanceGroupRoleKubControllerManager
109+
func (r InstanceGroupRole) HasKubeControllerManager() bool {
110+
return r == InstanceGroupRoleKubeControllerManager
114111
}
115112

116113
func (r InstanceGroupRole) IsControlPlaneType() bool {
117-
return r.HasControlPlane() || r.HasAPIServer()
114+
return r.HasControlPlane() || r.HasAPIServer() || r.HasEtcd() || r.HasScheduler() || r.HasKubeControllerManager()
118115
}
119116

120117
const (
@@ -408,10 +405,40 @@ func (g *InstanceGroup) IsAPIServerOnly() bool {
408405
}
409406

410407
// hasAPIServer checks if instanceGroup runs an API Server
411-
func (g *InstanceGroup) HasAPIServer() bool {
408+
func (g *InstanceGroup) RunsAPIServer() bool {
412409
return g.IsControlPlane() || g.IsAPIServerOnly()
413410
}
414411

412+
// IsEtcdOnly checks if instanceGroup runs only Etcd
413+
func (g *InstanceGroup) IsEtcdOnly() bool {
414+
return g.Spec.Role.HasEtcd()
415+
}
416+
417+
// HasEtcd checks if instanceGroup runs Etcd
418+
func (g *InstanceGroup) RunsEtcd() bool {
419+
return g.IsControlPlane() || g.IsEtcdOnly()
420+
}
421+
422+
// IsSchedulerOnly checks if instanceGroup runs only Scheduler
423+
func (g *InstanceGroup) IsSchedulerOnly() bool {
424+
return g.Spec.Role.HasScheduler()
425+
}
426+
427+
// HasScheduler checks if instanceGroup runs Scheduler
428+
func (g *InstanceGroup) RunsScheduler() bool {
429+
return g.IsControlPlane() || g.IsSchedulerOnly()
430+
}
431+
432+
// IsKubeControllerManagerOnly checks if instanceGroup runs only KubeControllerManager
433+
func (g *InstanceGroup) IsKubeControllerManagerOnly() bool {
434+
return g.Spec.Role.HasKubeControllerManager()
435+
}
436+
437+
// RunsKubeControllerManager checks if instanceGroup runs KubeControllerManager
438+
func (g *InstanceGroup) RunsKubeControllerManager() bool {
439+
return g.IsControlPlane() || g.IsKubeControllerManagerOnly()
440+
}
441+
415442
// HasGVisor checks if instanceGroup is a worker that has the gVisor (runsc) runtime enabled.
416443
// gVisor is only valid on workers; ValidateInstanceGroup rejects it on other roles.
417444
func (g *InstanceGroup) HasGVisor() bool {

‎pkg/apis/kops/validation/instancegroup.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ func validateKarpenterInstanceGroup(g *kops.InstanceGroup, cluster *kops.Cluster
330330
if cluster.GetCloudProvider() != kops.CloudProviderAWS {
331331
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "manager"), "Karpenter InstanceGroups are only supported on AWS"))
332332
}
333-
if g.Spec.Role != kops.InstanceGroupRoleNode {
333+
if !g.Spec.Role.HasNode() {
334334
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "role"), "Karpenter InstanceGroups must have role Node"))
335335
}
336336
if g.Spec.MaxSize != nil && *g.Spec.MaxSize <= 0 {

0 commit comments

Comments
 (0)