Skip to content

Commit cd9ac29

Browse files
committed
feat: Flag to consider kubenurses on unschedulable nodes
1 parent c5bfacb commit cd9ac29

File tree

5 files changed

+52
-17
lines changed

5 files changed

+52
-17
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ kubenurse is configured with environment variables:
2424
- `KUBENURSE_EXTRA_CA`: Additional CA cert path for TLS connections
2525
- `KUBENURSE_NAMESPACE`: Namespace in which to look for the neighbour kubenurses
2626
- `KUBENURSE_NEIGHBOUR_FILTER`: A label selector to filter neighbour kubenurses
27+
- `KUBENURSE_ALLOW_UNSCHEDULABLE`: If this is `"true"`, path checks to neighbouring kubenurses are only made if they are running on schedulable nodes. This requires get/list/watch access to `api/v1 Node` resources
2728

2829
Following variables are injected to the Pod by Kubernetes and should not be defined manually:
2930

main.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,11 @@ func main() {
6868
Transport: transport,
6969
}
7070

71+
// If we want to consider kubenurses on unschedulable nodes
72+
allowUnschedulable := os.Getenv("KUBENURSE_ALLOW_UNSCHEDULABLE") == "true"
73+
7174
// setup checker
72-
chk, err := checker.New(ctx, client, 3*time.Second)
75+
chk, err := checker.New(ctx, client, 3*time.Second, allowUnschedulable)
7376
if err != nil {
7477
log.Fatalln(err)
7578
}

pkg/checker/checker.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,17 @@ import (
1414

1515
// New configures the checker with a httpClient and a cache timeout for check
1616
// results. Other parameters of the Checker struct need to be configured separately.
17-
func New(ctx context.Context, httpClient *http.Client, cacheTTL time.Duration) (*Checker, error) {
18-
discovery, err := kubediscovery.New(ctx)
17+
func New(ctx context.Context, httpClient *http.Client, cacheTTL time.Duration, allowUnschedulable bool) (*Checker, error) {
18+
discovery, err := kubediscovery.New(ctx, allowUnschedulable)
1919
if err != nil {
2020
return nil, fmt.Errorf("create k8s discovery client: %w", err)
2121
}
2222

2323
return &Checker{
24-
discovery: discovery,
25-
httpClient: httpClient,
26-
cacheTTL: cacheTTL,
24+
allowUnschedulable: allowUnschedulable,
25+
discovery: discovery,
26+
httpClient: httpClient,
27+
cacheTTL: cacheTTL,
2728
}, nil
2829
}
2930

@@ -110,7 +111,7 @@ func (c *Checker) MeService() (string, error) {
110111
func (c *Checker) checkNeighbours(nh []kubediscovery.Neighbour) {
111112
for _, neighbour := range nh {
112113
neighbour := neighbour // pin
113-
if neighbour.NodeSchedulable {
114+
if c.allowUnschedulable || neighbour.NodeSchedulable == kubediscovery.NodeSchedulable {
114115
check := func() (string, error) {
115116
return c.doRequest("http://" + neighbour.PodIP + ":8080/alwayshappy")
116117
}

pkg/checker/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type Checker struct {
2020
// Neighbourhood
2121
KubenurseNamespace string
2222
NeighbourFilter string
23+
allowUnschedulable bool
2324

2425
discovery *kubediscovery.Client
2526

pkg/kubediscovery/kubediscovery.go

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,35 @@ import (
1313

1414
// Client provides the kubediscovery client methods.
1515
type Client struct {
16-
k8s kubernetes.Interface
17-
nodeCache *nodeCache
16+
k8s kubernetes.Interface
17+
nodeCache *nodeCache
18+
allowUnschedulable bool
1819
}
1920

21+
// NodeSchedulability determines if the kubernetes node is in schedulable mode
22+
// or not.
23+
type NodeSchedulability string
24+
25+
const (
26+
NodeSchedulabilityUnknown NodeSchedulability = "Unknown"
27+
NodeSchedulable NodeSchedulability = "Schedulable"
28+
NodeUnschedulable NodeSchedulability = "Unschedulable"
29+
)
30+
2031
// Neighbour represents a kubenurse which should be reachable
2132
type Neighbour struct {
2233
PodName string
2334
PodIP string
2435
HostIP string
2536
NodeName string
26-
NodeSchedulable bool
37+
NodeSchedulable NodeSchedulability
2738
Phase string // Pod Phase
2839
}
2940

3041
// New creates a new kubediscovery client. The context is used to stop the k8s watchers/informers.
31-
func New(ctx context.Context) (*Client, error) {
42+
// When allowUnschedulable is true, no node watcher is created and kubenurses
43+
// on unschedulable nodes are considered as neighbours.
44+
func New(ctx context.Context, allowUnschedulable bool) (*Client, error) {
3245
// create in-cluster config
3346
config, err := rest.InClusterConfig()
3447
if err != nil {
@@ -40,14 +53,20 @@ func New(ctx context.Context) (*Client, error) {
4053
return nil, fmt.Errorf("creating clientset: %w", err)
4154
}
4255

43-
nodeCache, err := watchNodes(ctx, cliset)
44-
if err != nil {
45-
return nil, fmt.Errorf("starting node watcher: %w", err)
56+
var nc *nodeCache
57+
58+
// Watch nodes only if we consider kubenurses on unschedulable nodes
59+
if allowUnschedulable {
60+
nc, err = watchNodes(ctx, cliset)
61+
if err != nil {
62+
return nil, fmt.Errorf("starting node watcher: %w", err)
63+
}
4664
}
4765

4866
return &Client{
49-
k8s: cliset,
50-
nodeCache: nodeCache,
67+
k8s: cliset,
68+
nodeCache: nc,
69+
allowUnschedulable: allowUnschedulable,
5170
}, nil
5271
}
5372

@@ -67,13 +86,23 @@ func (c *Client) GetNeighbours(ctx context.Context, namespace, labelSelector str
6786
for idx := range pods.Items {
6887
pod := pods.Items[idx]
6988

89+
// If we allow unschedulable kubenurses, we set the schedulability
90+
// to unknown in order not to have to set up a node watcher.
91+
sched := NodeSchedulabilityUnknown
92+
if !c.allowUnschedulable {
93+
sched = NodeUnschedulable
94+
if c.nodeCache.isSchedulable(pod.Spec.NodeName) {
95+
sched = NodeSchedulable
96+
}
97+
}
98+
7099
n := Neighbour{
71100
PodName: pod.Name,
72101
PodIP: pod.Status.PodIP,
73102
HostIP: pod.Status.HostIP,
74103
Phase: string(pod.Status.Phase),
75104
NodeName: pod.Spec.NodeName,
76-
NodeSchedulable: c.nodeCache.isSchedulable(pod.Spec.NodeName),
105+
NodeSchedulable: sched,
77106
}
78107
neighbours[idx] = n
79108
}

0 commit comments

Comments
 (0)