2019-10-09 20:49:40 +03:00
|
|
|
package labelsync
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/Azure/go-autorest/autorest/to"
|
|
|
|
"github.com/go-logr/logr"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
|
|
"k8s.io/apimachinery/pkg/types"
|
|
|
|
"k8s.io/client-go/tools/record"
|
|
|
|
|
|
|
|
azrsrc "github.com/Azure/node-label-operator/azure/computeresource"
|
|
|
|
"github.com/Azure/node-label-operator/labelsync/naming"
|
|
|
|
"github.com/Azure/node-label-operator/labelsync/options"
|
|
|
|
)
|
|
|
|
|
|
|
|
// return patch with new labels, if any, otherwise return nil for no new labels or an error
|
|
|
|
func TagsToNodes(namespacedName types.NamespacedName, computeResource azrsrc.ComputeResource,
|
|
|
|
node *corev1.Node, configOptions *options.ConfigOptions, log logr.Logger, recorder record.EventRecorder) ([]byte, error) {
|
|
|
|
|
|
|
|
newLabels := map[string]*string{} // should allow for null JSON values
|
|
|
|
for tagName, tagVal := range computeResource.Tags() {
|
|
|
|
if !naming.ValidLabelName(tagName) {
|
|
|
|
log.V(0).Info("invalid label name", "tag name", tagName)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if !naming.ValidLabelVal(*tagVal) {
|
|
|
|
log.V(0).Info("invalid label value", "tag value", *tagVal)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
validLabelName := naming.ConvertTagNameToValidLabelName(tagName, configOptions.LabelPrefix)
|
|
|
|
labelVal, ok := node.Labels[validLabelName]
|
|
|
|
if !ok {
|
|
|
|
// add tag as label
|
|
|
|
log.V(1).Info("applying tags to nodes", "tag name", tagName, "tag value", *tagVal)
|
|
|
|
newLabels[validLabelName] = tagVal
|
|
|
|
} else if labelVal != *tagVal {
|
|
|
|
switch configOptions.ConflictPolicy {
|
|
|
|
case options.ARMPrecedence:
|
|
|
|
// set label anyway
|
|
|
|
log.V(1).Info("overriding existing node label with ARM tag", "tag name", tagName, "tag value", tagVal)
|
|
|
|
newLabels[validLabelName] = tagVal
|
|
|
|
case options.NodePrecedence:
|
|
|
|
// do nothing
|
|
|
|
log.V(0).Info("name->value conflict found", "node label value", labelVal, "ARM tag value", *tagVal)
|
|
|
|
case options.Ignore:
|
|
|
|
// raise k8s event
|
|
|
|
recorder.Event(node, "Warning", "ConflictingTagLabelValues",
|
|
|
|
fmt.Sprintf("ARM tag was not applied to node because a different value for '%s' already exists (%s != %s).", tagName, *tagVal, labelVal))
|
|
|
|
log.V(0).Info("name->value conflict found, leaving unchanged", "label value", labelVal, "tag value", *tagVal)
|
|
|
|
default:
|
|
|
|
return nil, errors.New("unrecognized conflict policy")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// delete labels if tag has been deleted
|
|
|
|
// if conflict policy is node precedence (which it will most likely not be), then don't delete tags if they exist on node
|
2019-10-09 21:35:53 +03:00
|
|
|
if labelDeletionAllowed(configOptions) {
|
2019-10-09 20:49:40 +03:00
|
|
|
for labelFullName, labelVal := range node.Labels {
|
|
|
|
if naming.HasLabelPrefix(labelFullName, configOptions.LabelPrefix) {
|
|
|
|
// check if exists on vm/vmss
|
|
|
|
labelName := naming.LabelWithoutPrefix(labelFullName, configOptions.LabelPrefix)
|
|
|
|
_, ok := computeResource.Tags()[labelName]
|
|
|
|
if !ok { // if label doesn't exist on ARM resource, delete
|
|
|
|
log.V(1).Info("deleting label from node", "label name", labelFullName, "label value", labelVal)
|
|
|
|
delete(node.Labels, labelFullName) // for some reason this is needed
|
|
|
|
newLabels[labelFullName] = nil // this should becomes 'null' in JSON, necessary for merge patch
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(newLabels) == 0 { // to avoid unnecessary patching
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
patch, err := LabelPatchWithDelete(newLabels)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return patch, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func LabelsToAzureResource(namespacedName types.NamespacedName, computeResource azrsrc.ComputeResource,
|
|
|
|
node *corev1.Node, configOptions *options.ConfigOptions, log logr.Logger, recorder record.EventRecorder) (map[string]*string, error) {
|
|
|
|
|
|
|
|
if len(computeResource.Tags()) >= naming.MaxNumTags {
|
|
|
|
log.V(0).Info("can't add any more tags", "number of tags", len(computeResource.Tags()))
|
|
|
|
return computeResource.Tags(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
newTags := map[string]*string{}
|
|
|
|
for labelName, labelVal := range node.Labels {
|
|
|
|
if !naming.ValidTagName(labelName, configOptions.LabelPrefix) {
|
|
|
|
log.V(2).Info("invalid tag name", "label name", labelName)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if !naming.ValidTagVal(labelVal) {
|
|
|
|
log.V(2).Info("invalid tag name", "label name", labelName)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
validTagName := naming.ConvertLabelNameToValidTagName(labelName, configOptions.LabelPrefix)
|
|
|
|
tagVal, ok := computeResource.Tags()[validTagName]
|
|
|
|
if !ok {
|
|
|
|
// add label as tag
|
|
|
|
log.V(1).Info("applying labels to Azure resource", "label name", labelName, "label value", labelVal)
|
|
|
|
newTags[validTagName] = to.StringPtr(labelVal)
|
|
|
|
} else if *tagVal != labelVal {
|
|
|
|
switch configOptions.ConflictPolicy {
|
|
|
|
case options.NodePrecedence:
|
|
|
|
// set tag anyway
|
|
|
|
log.V(1).Info("overriding existing ARM tag with node label", "label name", labelName, "label value", labelVal)
|
|
|
|
newTags[validTagName] = to.StringPtr(labelVal)
|
|
|
|
case options.ARMPrecedence:
|
|
|
|
// do nothing
|
|
|
|
log.V(0).Info("name->value conflict found", "node label value", labelVal, "ARM tag value", *tagVal)
|
|
|
|
case options.Ignore:
|
|
|
|
// raise k8s event
|
|
|
|
recorder.Event(node, "Warning", "ConflictingTagLabelValues",
|
|
|
|
fmt.Sprintf("node label was not applied to Azure resource because a different value for '%s' already exists (%s != %s).", labelName, labelVal, *tagVal))
|
|
|
|
log.V(0).Info("name->value conflict found, leaving unchanged", "label value", labelVal, "tag value", *tagVal)
|
|
|
|
default:
|
|
|
|
return nil, errors.New("unrecognized conflict policy")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(newTags) == 0 { // if unchanged
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return newTags, nil
|
|
|
|
}
|