194 строки
4.6 KiB
Go
194 строки
4.6 KiB
Go
|
package npm
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"sort"
|
||
|
"container/heap"
|
||
|
|
||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||
|
|
||
|
"github.com/Azure/azure-container-networking/log"
|
||
|
"github.com/Azure/azure-container-networking/npm/util"
|
||
|
)
|
||
|
|
||
|
// An ReqHeap is a min-heap of labelSelectorRequirements.
|
||
|
type ReqHeap []metav1.LabelSelectorRequirement
|
||
|
|
||
|
func (h ReqHeap) Len() int {
|
||
|
return len(h)
|
||
|
}
|
||
|
|
||
|
func (h ReqHeap) Less(i, j int) bool {
|
||
|
sort.Strings(h[i].Values)
|
||
|
sort.Strings(h[j].Values)
|
||
|
|
||
|
if int(h[i].Key[0]) < int(h[j].Key[0]) {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
if int(h[i].Key[0]) > int(h[j].Key[0]) {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
if len(h[i].Values) == 0 {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
if len(h[j].Values) == 0 {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
if len(h[i].Values[0]) == 0 {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
if len(h[j].Values[0]) == 0 {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
return int(h[i].Values[0][0]) < int(h[j].Values[0][0])
|
||
|
}
|
||
|
|
||
|
func (h ReqHeap) Swap(i, j int) {
|
||
|
h[i], h[j] = h[j], h[i]
|
||
|
}
|
||
|
|
||
|
func (h *ReqHeap) Push(x interface{}) {
|
||
|
sort.Strings(x.(metav1.LabelSelectorRequirement).Values)
|
||
|
*h = append(*h, x.(metav1.LabelSelectorRequirement))
|
||
|
}
|
||
|
|
||
|
func (h *ReqHeap) Pop() interface{} {
|
||
|
old := *h
|
||
|
n := len(old)
|
||
|
x := old[n -1]
|
||
|
*h = old[0 : n - 1]
|
||
|
|
||
|
return x
|
||
|
}
|
||
|
|
||
|
// ParseLabel takes a Azure-NPM processed label then returns if it's referring to complement set,
|
||
|
// and if so, returns the original set as well.
|
||
|
func ParseLabel(label string) (string, bool) {
|
||
|
//The input label is guaranteed to have a non-zero length validated by k8s.
|
||
|
//For label definition, see below parseSelector() function.
|
||
|
if label[0:1] == util.IptablesNotFlag {
|
||
|
return label[1:], true
|
||
|
}
|
||
|
return label, false
|
||
|
}
|
||
|
|
||
|
// GetOperatorAndLabel returns the operator associated with the label and the label without operator.
|
||
|
func GetOperatorAndLabel(label string) (string, string) {
|
||
|
if len(label) == 0 {
|
||
|
return "", ""
|
||
|
}
|
||
|
|
||
|
if string(label[0]) == util.IptablesNotFlag {
|
||
|
return util.IptablesNotFlag, label[1:]
|
||
|
}
|
||
|
|
||
|
return "", label
|
||
|
}
|
||
|
|
||
|
// GetOperatorsAndLabels returns the operators along with the associated labels.
|
||
|
func GetOperatorsAndLabels(labelsWithOps []string) ([]string, []string) {
|
||
|
var ops, labelsWithoutOps []string
|
||
|
for _, labelWithOp := range labelsWithOps {
|
||
|
op, labelWithoutOp := GetOperatorAndLabel(labelWithOp)
|
||
|
ops = append(ops, op)
|
||
|
labelsWithoutOps = append(labelsWithoutOps, labelWithoutOp)
|
||
|
}
|
||
|
|
||
|
return ops, labelsWithoutOps
|
||
|
}
|
||
|
|
||
|
// sortSelector sorts the member fields of the selector in an alphebatical order.
|
||
|
func sortSelector(selector *metav1.LabelSelector) {
|
||
|
_, _ = util.SortMap(&selector.MatchLabels)
|
||
|
|
||
|
reqHeap := &ReqHeap{}
|
||
|
heap.Init(reqHeap)
|
||
|
for _, req := range selector.MatchExpressions {
|
||
|
heap.Push(reqHeap, req)
|
||
|
}
|
||
|
|
||
|
var sortedReqs []metav1.LabelSelectorRequirement
|
||
|
for reqHeap.Len() > 0 {
|
||
|
sortedReqs = append(sortedReqs, heap.Pop(reqHeap).(metav1.LabelSelectorRequirement))
|
||
|
|
||
|
}
|
||
|
selector.MatchExpressions = sortedReqs
|
||
|
}
|
||
|
|
||
|
// HashSelector returns the hash value of the selector.
|
||
|
func HashSelector(selector *metav1.LabelSelector) string {
|
||
|
sortSelector(selector)
|
||
|
return util.Hash(fmt.Sprintf("%v", selector))
|
||
|
}
|
||
|
|
||
|
// parseSelector takes a LabelSelector and returns a slice of processed labels, keys and values.
|
||
|
func parseSelector(selector *metav1.LabelSelector) ([]string, []string, []string) {
|
||
|
var (
|
||
|
labels []string
|
||
|
keys []string
|
||
|
vals []string
|
||
|
)
|
||
|
|
||
|
if selector == nil {
|
||
|
return labels, keys, vals
|
||
|
}
|
||
|
|
||
|
if len(selector.MatchLabels) == 0 && len(selector.MatchExpressions) == 0 {
|
||
|
labels = append(labels, "")
|
||
|
keys = append(keys, "")
|
||
|
vals = append(vals, "")
|
||
|
|
||
|
return labels, keys, vals
|
||
|
}
|
||
|
|
||
|
sortedKeys, sortedVals := util.SortMap(&selector.MatchLabels)
|
||
|
|
||
|
for i := range sortedKeys {
|
||
|
labels = append(labels, sortedKeys[i]+":"+sortedVals[i])
|
||
|
}
|
||
|
keys = append(keys, sortedKeys...)
|
||
|
vals = append(vals, sortedVals...)
|
||
|
|
||
|
for _, req := range selector.MatchExpressions {
|
||
|
var k string
|
||
|
switch op := req.Operator; op {
|
||
|
case metav1.LabelSelectorOpIn:
|
||
|
for _, v := range req.Values {
|
||
|
k = req.Key
|
||
|
keys = append(keys, k)
|
||
|
vals = append(vals, v)
|
||
|
labels = append(labels, k+":"+v)
|
||
|
}
|
||
|
case metav1.LabelSelectorOpNotIn:
|
||
|
for _, v := range req.Values {
|
||
|
k = util.IptablesNotFlag + req.Key
|
||
|
keys = append(keys, k)
|
||
|
vals = append(vals, v)
|
||
|
labels = append(labels, k+":"+v)
|
||
|
}
|
||
|
// Exists matches pods with req.Key as key
|
||
|
case metav1.LabelSelectorOpExists:
|
||
|
k = req.Key
|
||
|
keys = append(keys, req.Key)
|
||
|
vals = append(vals, "")
|
||
|
labels = append(labels, k)
|
||
|
// DoesNotExist matches pods without req.Key as key
|
||
|
case metav1.LabelSelectorOpDoesNotExist:
|
||
|
k = util.IptablesNotFlag + req.Key
|
||
|
keys = append(keys, k)
|
||
|
vals = append(vals, "")
|
||
|
labels = append(labels, k)
|
||
|
default:
|
||
|
log.Errorf("Invalid operator [%s] for selector [%v] requirement", op, *selector)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return labels, keys, vals
|
||
|
}
|