[node operator] node image util functions

Signed-off-by: Malte Poll <mp@edgeless.systems>
This commit is contained in:
Malte Poll 2022-06-28 11:53:10 +02:00 committed by Malte Poll
parent 3932581f2a
commit 7b6205e900
3 changed files with 219 additions and 5 deletions

View File

@ -170,6 +170,7 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/zapr v1.2.0 h1:n4JnPI1T3Qq1SFEi/F8rwLrZERp2bso19PJZDB9dayk=
@ -346,7 +347,10 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@ -401,6 +405,7 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
@ -746,6 +751,7 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -998,6 +1004,8 @@ k8s.io/component-base v0.24.0 h1:h5jieHZQoHrY/lHG+HyrSbJeyfuitheBvqvKwKHVC0g=
k8s.io/component-base v0.24.0/go.mod h1:Dgazgon0i7KYUsS8krG8muGiMVtUZxG037l1MKyXgrA=
k8s.io/component-helpers v0.24.0/go.mod h1:Q2SlLm4h6g6lPTC9GMMfzdywfLSvJT2f1hOnnjaWD8c=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
@ -1007,11 +1015,13 @@ k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc=
k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 h1:Gii5eqf+GmIEwGNKQYQClCayuJCe2/4fZUvF7VG99sU=
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk=
k8s.io/kubectl v0.24.0/go.mod h1:pdXkmCyHiRTqjYfyUJiXtbVNURhv0/Q1TyRhy2d5ic0=
k8s.io/metrics v0.24.0/go.mod h1:jrLlFGdKl3X+szubOXPG0Lf2aVxuV3QJcbsgVRAM6fI=
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc=
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=

View File

@ -1,15 +1,48 @@
package node
import corev1 "k8s.io/api/core/v1"
import (
"regexp"
updatev1alpha1 "github.com/edgelesssys/constellation/operators/constellation-node-operator/api/v1alpha1"
corev1 "k8s.io/api/core/v1"
)
var reservedHostRegex = regexp.MustCompile(`^(.+\.|)(kubernetes|k8s)\.io(/.*)?$`)
// Ready checks if a kubernetes node has the `NodeReady` condition set to true.
func Ready(node *corev1.Node) bool {
for _, cond := range node.Status.Conditions {
if cond.Type == corev1.NodeReady {
if cond.Status == corev1.ConditionTrue {
return true
}
return false
return cond.Status == corev1.ConditionTrue
}
}
return false
}
// FindPending searches for a pending node that matches a node.
// The pending node has to have the goal to join the cluster and be reported as ready be the CSP.
// if the node is not found, nil is returned.
func FindPending(pendingNodes []updatev1alpha1.PendingNode, node *corev1.Node) *updatev1alpha1.PendingNode {
if node == nil {
return nil
}
for _, pendingNode := range pendingNodes {
if pendingNode.Spec.Goal == updatev1alpha1.NodeGoalJoin && pendingNode.Spec.NodeName == node.Name && pendingNode.Status.CSPNodeState == updatev1alpha1.NodeStateReady {
return &pendingNode
}
}
return nil
}
// FilterLabels removes reserved node labels from a map of labels.
// reference: https://kubernetes.io/docs/reference/labels-annotations-taints/ .
func FilterLabels(labels map[string]string) map[string]string {
result := make(map[string]string)
for key, val := range labels {
if reservedHostRegex.MatchString(key) {
continue
}
result[key] = val
}
return result
}

View File

@ -0,0 +1,171 @@
package node
import (
"testing"
updatev1alpha1 "github.com/edgelesssys/constellation/operators/constellation-node-operator/api/v1alpha1"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestReady(t *testing.T) {
testCases := map[string]struct {
node corev1.Node
wantReady bool
}{
"node without status conditions": {},
"node with NodeReady set to false": {
node: corev1.Node{
Status: corev1.NodeStatus{
Conditions: []corev1.NodeCondition{
{Type: corev1.NodeReady, Status: corev1.ConditionFalse},
},
},
},
},
"node with NodeReady set to unknown": {
node: corev1.Node{
Status: corev1.NodeStatus{
Conditions: []corev1.NodeCondition{
{Type: corev1.NodeReady, Status: corev1.ConditionUnknown},
},
},
},
},
"node with NodeReady set to true": {
node: corev1.Node{
Status: corev1.NodeStatus{
Conditions: []corev1.NodeCondition{
{Type: corev1.NodeReady, Status: corev1.ConditionTrue},
},
},
},
wantReady: true,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)
assert.Equal(tc.wantReady, Ready(&tc.node))
})
}
}
func TestFindPending(t *testing.T) {
testCases := map[string]struct {
pendingNodes []updatev1alpha1.PendingNode
node *corev1.Node
wantPending *updatev1alpha1.PendingNode
}{
"everything nil": {},
"node nil": {
pendingNodes: pendingNodes,
},
"node is not in pending nodes list": {
pendingNodes: pendingNodes,
node: &corev1.Node{
ObjectMeta: v1.ObjectMeta{
Name: "doesnotexist",
},
},
},
"pending node is leaving": {
pendingNodes: pendingNodes,
node: &corev1.Node{
ObjectMeta: v1.ObjectMeta{
Name: "leavingnode",
},
},
},
"pending node is not ready": {
pendingNodes: pendingNodes,
node: &corev1.Node{
ObjectMeta: v1.ObjectMeta{
Name: "unreadynode",
},
},
},
"pending node is found": {
pendingNodes: pendingNodes,
node: &corev1.Node{
ObjectMeta: v1.ObjectMeta{
Name: "joiningnode",
},
},
wantPending: &pendingNodes[0],
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)
pending := FindPending(tc.pendingNodes, tc.node)
if tc.wantPending == nil {
assert.Nil(pending)
return
}
assert.Equal(*tc.wantPending, *pending)
})
}
}
func TestFilterLabels(t *testing.T) {
labels := map[string]string{
"key": "value",
"app.kubernetes.io/component": "component",
"app.kubernetes.io/created-by": "created-by",
"app.kubernetes.io/instance": "instance",
"app.kubernetes.io/managed-by": "managed-by",
"app.kubernetes.io/name": "name",
"app.kubernetes.io/part-of": "part-of",
"app.kubernetes.io/version": "version",
"kubernetes.io/arch": "arch",
"kubernetes.io/os": "os",
"beta.kubernetes.io/arch": "arch",
"beta.kubernetes.io/os": "os",
"kubernetes.io/hostname": "hostname",
"kubernetes.io/change-cause": "change-cause",
"kubernetes.io/description": "description",
"node.kubernetes.io/instance-type": "instance-type",
"failure-domain.beta.kubernetes.io/region": "region",
"failure-domain.beta.kubernetes.io/zone": "zone",
"topology.kubernetes.io/region": "region",
"topology.kubernetes.io/zone": "zone",
"node.kubernetes.io/windows-build": "windows-build",
"node-role.kubernetes.io/control-plane": "control-plane",
}
wantFiltered := map[string]string{
"key": "value",
}
assert := assert.New(t)
assert.Equal(wantFiltered, FilterLabels(labels))
}
var pendingNodes = []updatev1alpha1.PendingNode{
{
Spec: updatev1alpha1.PendingNodeSpec{
NodeName: "joiningnode",
Goal: updatev1alpha1.NodeGoalJoin,
},
Status: updatev1alpha1.PendingNodeStatus{
CSPNodeState: updatev1alpha1.NodeStateReady,
},
},
{
Spec: updatev1alpha1.PendingNodeSpec{
NodeName: "unreadynode",
Goal: updatev1alpha1.NodeGoalJoin,
},
Status: updatev1alpha1.PendingNodeStatus{
CSPNodeState: updatev1alpha1.NodeStateCreating,
},
},
{
Spec: updatev1alpha1.PendingNodeSpec{
NodeName: "leavingnode",
Goal: updatev1alpha1.NodeGoalLeave,
},
},
}