azure-container-networking/npm/parseSelector.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
}