mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-12-25 07:29:38 -05:00
[node operator] node image util functions
Signed-off-by: Malte Poll <mp@edgeless.systems>
This commit is contained in:
parent
3932581f2a
commit
7b6205e900
@ -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=
|
||||
|
@ -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
|
||||
}
|
||||
|
171
operators/constellation-node-operator/internal/node/node_test.go
Normal file
171
operators/constellation-node-operator/internal/node/node_test.go
Normal 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,
|
||||
},
|
||||
},
|
||||
}
|
Loading…
Reference in New Issue
Block a user