Skip to content

Commit

Permalink
Allow deprecated beta topology labels to be applied for those not rea…
Browse files Browse the repository at this point in the history
…dy to migrate

This reverts commit 67c2407.
It then introduces a new flag to allow users to opt-in to syncing older, beta
topology labels based on the presence of the GA topolgoy labels.
  • Loading branch information
JoelSpeed authored and k8s-infra-cherrypick-robot committed Jun 6, 2023
1 parent adad54c commit 73fcc15
Show file tree
Hide file tree
Showing 5 changed files with 369 additions and 108 deletions.
5 changes: 5 additions & 0 deletions cmd/cloud-node-manager/app/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,9 @@ type Config struct {
// WindowsService should be set to true if cloud-node-manager is running as a service on Windows.
// Its corresponding flag only gets registered in Windows builds
WindowsService bool

// EnableDeprecatedBetaTopologyLabels indicates whether the node should apply beta topology labels.
// If true, the node will apply beta topology labels.
// DEPRECATED: This flag will be removed in a future release.
EnableDeprecatedBetaTopologyLabels bool
}
3 changes: 2 additions & 1 deletion cmd/cloud-node-manager/app/nodemanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ func startControllers(ctx context.Context, c *cloudnodeconfig.Config, stopCh <-c
c.ClientBuilder.ClientOrDie("node-controller"),
nodeprovider.NewNodeProvider(ctx, c.UseInstanceMetadata, c.CloudConfigFilePath),
c.NodeStatusUpdateFrequency.Duration,
c.WaitForRoutes)
c.WaitForRoutes,
c.EnableDeprecatedBetaTopologyLabels)

go nodeController.Run(stopCh)

Expand Down
9 changes: 9 additions & 0 deletions cmd/cloud-node-manager/app/options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ type CloudNodeManagerOptions struct {
// WindowsService should be set to true if cloud-node-manager is running as a service on Windows.
// Its corresponding flag only gets registered in Windows builds
WindowsService bool

// EnableDeprecatedBetaTopologyLabels indicates whether the node should apply beta topology labels.
// If true, the node will apply beta topology labels.
// DEPRECATED: This flag will be removed in a future release.
EnableDeprecatedBetaTopologyLabels bool
}

// NewCloudNodeManagerOptions creates a new CloudNodeManagerOptions with a default config.
Expand Down Expand Up @@ -131,6 +136,7 @@ func (o *CloudNodeManagerOptions) Flags() cliflag.NamedFlagSets {
fs.BoolVar(&o.WaitForRoutes, "wait-routes", false, "Whether the nodes should wait for routes created on Azure route table. It should be set to true when using kubenet plugin.")
fs.BoolVar(&o.UseInstanceMetadata, "use-instance-metadata", true, "Should use Instance Metadata Service for fetching node information; if false will use ARM instead.")
fs.StringVar(&o.CloudConfigFilePath, "cloud-config", o.CloudConfigFilePath, "The path to the cloud config file to be used when using ARM to fetch node information.")
fs.BoolVar(&o.EnableDeprecatedBetaTopologyLabels, "enable-deprecated-beta-topology-labels", o.EnableDeprecatedBetaTopologyLabels, "DEPRECATED: This flag will be removed in a future release. If true, the node will apply beta topology labels.")
return fss
}

Expand Down Expand Up @@ -193,6 +199,9 @@ func (o *CloudNodeManagerOptions) ApplyTo(c *cloudnodeconfig.Config, userAgent s

c.WindowsService = o.WindowsService

// Allow users to choose to apply beta topology labels until they are removed by all cloud providers.
c.EnableDeprecatedBetaTopologyLabels = o.EnableDeprecatedBetaTopologyLabels

return nil
}

Expand Down
101 changes: 68 additions & 33 deletions pkg/nodemanager/nodemanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,44 @@ type NodeProvider interface {
GetPlatformSubFaultDomain() (string, error)
}

// labelReconcileInfo lists Node labels to reconcile, and how to reconcile them.
// labelReconcile holds information about a label to reconcile and how to reconcile it.
// primaryKey and secondaryKey are keys of labels to reconcile.
// - If both keys exist, but their values don't match. Use the value from the
// primaryKey as the source of truth to reconcile.
// - If ensureSecondaryExists is true, and the secondaryKey does not
// exist, secondaryKey will be added with the value of the primaryKey.
var labelReconcileInfo = []struct {
type labelReconcile struct {
primaryKey string
secondaryKey string
ensureSecondaryExists bool
}{}
}

// betaToplogyLabels lists beta topology labels that are deprecated and will
// be removed in a future release.
// For now we reconcile them optionally onto nodes.
var betaToplogyLabels = []labelReconcile{
{
// Reconcile the beta and the GA zone label using the GA label as
// the source of truth
primaryKey: v1.LabelZoneFailureDomainStable,
secondaryKey: v1.LabelZoneFailureDomain,
ensureSecondaryExists: true,
},
{
// Reconcile the beta and the stable region label using the GA label as
// the source of truth
primaryKey: v1.LabelZoneRegionStable,
secondaryKey: v1.LabelZoneRegion,
ensureSecondaryExists: true,
},
{
// Reconcile the beta and the stable instance-type label using the GA label as
// the source of truth
primaryKey: v1.LabelInstanceTypeStable,
secondaryKey: v1.LabelInstanceType,
ensureSecondaryExists: true,
},
}

// UpdateNodeSpecBackoff is the back configure for node update.
var UpdateNodeSpecBackoff = wait.Backoff{
Expand Down Expand Up @@ -103,6 +130,10 @@ type CloudNodeController struct {
recorder record.EventRecorder

nodeStatusUpdateFrequency time.Duration

labelReconcileInfo []labelReconcile

enableBetaTopologyLabels bool
}

// NewCloudNodeController creates a CloudNodeController object
Expand All @@ -112,7 +143,7 @@ func NewCloudNodeController(
kubeClient clientset.Interface,
nodeProvider NodeProvider,
nodeStatusUpdateFrequency time.Duration,
waitForRoutes bool) *CloudNodeController {
waitForRoutes, enableBetaTopologyLabels bool) *CloudNodeController {

eventBroadcaster := record.NewBroadcaster()
recorder := eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "cloud-node-controller"})
Expand All @@ -132,6 +163,12 @@ func NewCloudNodeController(
nodeProvider: nodeProvider,
waitForRoutes: waitForRoutes,
nodeStatusUpdateFrequency: nodeStatusUpdateFrequency,
enableBetaTopologyLabels: enableBetaTopologyLabels,
}

// Only reconcile the beta toplogy labels when the feature flag is enabled.
if cnc.enableBetaTopologyLabels {
cnc.labelReconcileInfo = append(cnc.labelReconcileInfo, betaToplogyLabels...)
}

// Use shared informer to listen to add/update of nodes. Note that any nodes
Expand Down Expand Up @@ -190,7 +227,7 @@ func (cnc *CloudNodeController) reconcileNodeLabels(node *v1.Node) error {
}

labelsToUpdate := map[string]string{}
for _, r := range labelReconcileInfo {
for _, r := range cnc.labelReconcileInfo {
primaryValue, primaryExists := node.Labels[r.primaryKey]
secondaryValue, secondaryExists := node.Labels[r.secondaryKey]

Expand Down Expand Up @@ -445,53 +482,51 @@ func (cnc *CloudNodeController) getNodeModifiersFromCloudProvider(ctx context.Co
if instanceType, err := cnc.getInstanceTypeByName(ctx, node); err != nil {
return nil, err
} else if instanceType != "" {
klog.V(2).Infof("Adding node label from cloud provider: %s=%s", v1.LabelInstanceTypeStable, instanceType)
nodeModifiers = append(nodeModifiers, func(n *v1.Node) {
if n.Labels == nil {
n.Labels = map[string]string{}
}
n.Labels[v1.LabelInstanceTypeStable] = instanceType
})
nodeModifiers = append(nodeModifiers, addCloudNodeLabel(v1.LabelInstanceTypeStable, instanceType))
if cnc.enableBetaTopologyLabels {
nodeModifiers = append(nodeModifiers, addCloudNodeLabel(v1.LabelInstanceType, instanceType))
}
}

zone, err := cnc.getZoneByName(ctx, node)
if err != nil {
return nil, fmt.Errorf("failed to get zone from cloud provider: %w", err)
}
if zone.FailureDomain != "" {
klog.V(2).Infof("Adding node label from cloud provider: %s=%s", v1.LabelZoneFailureDomainStable, zone.FailureDomain)
nodeModifiers = append(nodeModifiers, func(n *v1.Node) {
if n.Labels == nil {
n.Labels = map[string]string{}
}
n.Labels[v1.LabelZoneFailureDomainStable] = zone.FailureDomain
})
nodeModifiers = append(nodeModifiers, addCloudNodeLabel(v1.LabelZoneFailureDomainStable, zone.FailureDomain))
if cnc.enableBetaTopologyLabels {
nodeModifiers = append(nodeModifiers, addCloudNodeLabel(v1.LabelZoneFailureDomain, zone.FailureDomain))
}
}
if zone.Region != "" {
klog.V(2).Infof("Adding node label from cloud provider: %s=%s", v1.LabelZoneRegionStable, zone.Region)
nodeModifiers = append(nodeModifiers, func(n *v1.Node) {
if n.Labels == nil {
n.Labels = map[string]string{}
}
n.Labels[v1.LabelZoneRegionStable] = zone.Region
})
nodeModifiers = append(nodeModifiers, addCloudNodeLabel(v1.LabelZoneRegionStable, zone.Region))
if cnc.enableBetaTopologyLabels {
nodeModifiers = append(nodeModifiers, addCloudNodeLabel(v1.LabelZoneRegion, zone.Region))
}
}

platformSubFaultDomain, err := cnc.getPlatformSubFaultDomain()
if err != nil {
return nil, fmt.Errorf("failed to get platformSubFaultDomain: %w", err)
}
if platformSubFaultDomain != "" {
klog.V(2).Infof("Adding node label from cloud provider: %s=%s", consts.LabelPlatformSubFaultDomain, platformSubFaultDomain)
nodeModifiers = append(nodeModifiers, func(n *v1.Node) {
if n.Labels == nil {
n.Labels = map[string]string{}
}
n.Labels[consts.LabelPlatformSubFaultDomain] = platformSubFaultDomain
})
nodeModifiers = append(nodeModifiers, addCloudNodeLabel(consts.LabelPlatformSubFaultDomain, platformSubFaultDomain))
}

return nodeModifiers, nil
}

// addCloudNodeLabel creates a nodeModifier that adds a label to a node.
func addCloudNodeLabel(key, value string) func(*v1.Node) {
klog.V(2).Infof("Adding node label from cloud provider: %s=%s", key, value)
return func(node *v1.Node) {
if node.Labels == nil {
node.Labels = map[string]string{}
}
node.Labels[key] = value
}
}

func GetCloudTaint(taints []v1.Taint) *v1.Taint {
for _, taint := range taints {
taint := taint
Expand Down
Loading

0 comments on commit 73fcc15

Please sign in to comment.