Skip to content

Commit aeedd5f

Browse files
authored
Merge pull request #119 from dnorman3/dnorman3/priority-system
dnorman3/priority system
2 parents 8ea7e50 + 457dcd1 commit aeedd5f

File tree

9 files changed

+833
-42
lines changed

9 files changed

+833
-42
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION = 1.10.1
1+
VERSION = 1.10.2
22
# IMPORTANT! Update api version if a new release affects cnr
33
API_VERSION = 1.0.0
44
IMAGE = cyclops:$(VERSION)

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ See [Docs](docs/README.md)
3535

3636
## Requirements
3737

38-
- [Kubernetes](https://kubernetes.io/) version 1.13+. Cyclops has been tested and deployed on 1.13+ and newer. Older versions of Kubernetes may have bugs or issues that will prevent it from functioning properly.
39-
- [Go](https://golang.org/) version 1.13+. Newer versions of Go are highly recommended.
38+
- [Kubernetes](https://kubernetes.io/) version 1.32+. Cyclops has been tested and deployed on 1.32+ and newer. Older versions of Kubernetes may have bugs or issues that will prevent it from functioning properly.
39+
- [Go](https://golang.org/) version 1.23+. Newer versions of Go are highly recommended.
4040
- Dependencies and their locked versions can be found in `go.mod` and `go.sum`.
4141

4242
## Building

deploy/crds/atlassian.com_nodegroups_crd.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,12 @@ spec:
306306
- triggerEndpoint
307307
type: object
308308
type: array
309+
priority:
310+
description: Priority controls the ordering of CNR creation for this
311+
NodeGroup. Lower values are higher priority. -10 runs before 0;
312+
then 10, 20, ... Value range is from -2,147,483,648 to 2,147,483,647.
313+
format: int32
314+
type: integer
309315
skipInitialHealthChecks:
310316
description: SkipInitialHealthChecks is an optional flag to skip the
311317
initial set of node health checks before cycling begins This does

pkg/apis/atlassian/v1/nodegroup_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ type NodeGroupSpec struct {
3939

4040
// SkipPreTerminationChecks is an optional flag to skip pre-termination checks during cycling
4141
SkipPreTerminationChecks bool `json:"skipPreTerminationChecks,omitempty"`
42+
43+
// Priority controls the ordering of CNR creation for this NodeGroup.
44+
// Lower values are higher priority. Examples: -10 runs before 0; then 10, 20, ...
45+
Priority int32 `json:"priority,omitempty"`
4246
}
4347

4448
// NodeGroupStatus defines the observed state of NodeGroup

pkg/metrics/metrics.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package metrics
33
import (
44
"context"
55
"fmt"
6+
"strings"
67
"time"
78

89
v1 "github.com/atlassian-labs/cyclops/pkg/apis/atlassian/v1"
@@ -43,6 +44,24 @@ var (
4344
[]string{"phase"},
4445
nil,
4546
)
47+
// NodeGroupInfo provides static information about nodegroups
48+
NodeGroupInfo = prometheus.NewDesc(
49+
fmt.Sprintf("%v_node_group_info", namespace),
50+
"Static information about nodegroups in the cluster",
51+
[]string{
52+
"nodegroup_name",
53+
"nodegroups_list",
54+
"node_selector",
55+
"concurrency",
56+
"method",
57+
"max_failed_cnrs",
58+
"skip_missing_named_nodes",
59+
"skip_initial_health_checks",
60+
"skip_pre_termination_checks",
61+
"priority",
62+
},
63+
nil,
64+
)
4665
)
4766

4867
// Register registers the custom metrics with prometheus
@@ -105,6 +124,7 @@ func (c cyclopsCollector) Describe(ch chan<- *prometheus.Desc) {
105124
ch <- CycleNodeRequestsByPhase
106125
ch <- CycleNodeStatuses
107126
ch <- CycleNodeStatusesByPhase
127+
ch <- NodeGroupInfo
108128
}
109129

110130
func (c cyclopsCollector) Collect(ch chan<- prometheus.Metric) {
@@ -172,4 +192,22 @@ func (c cyclopsCollector) Collect(ch chan<- prometheus.Metric) {
172192
prometheus.GaugeValue,
173193
float64(len(c.cycleNodeStatusList.Items)),
174194
)
195+
196+
for _, nodegroup := range c.nodeGroupList.Items {
197+
ch <- prometheus.MustNewConstMetric(
198+
NodeGroupInfo,
199+
prometheus.GaugeValue,
200+
1.0,
201+
nodegroup.Spec.NodeGroupName,
202+
strings.Join(nodegroup.Spec.NodeGroupsList, ","),
203+
nodegroup.Spec.NodeSelector.String(),
204+
fmt.Sprintf("%d", nodegroup.Spec.CycleSettings.Concurrency),
205+
string(nodegroup.Spec.CycleSettings.Method),
206+
fmt.Sprintf("%d", nodegroup.Spec.MaxFailedCycleNodeRequests),
207+
fmt.Sprintf("%t", nodegroup.Spec.ValidationOptions.SkipMissingNamedNodes),
208+
fmt.Sprintf("%t", nodegroup.Spec.SkipInitialHealthChecks),
209+
fmt.Sprintf("%t", nodegroup.Spec.SkipPreTerminationChecks),
210+
fmt.Sprintf("%d", nodegroup.Spec.Priority),
211+
)
212+
}
175213
}

pkg/metrics/metrics_test.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package metrics
2+
3+
import (
4+
"testing"
5+
6+
v1 "github.com/atlassian-labs/cyclops/pkg/apis/atlassian/v1"
7+
"github.com/prometheus/client_golang/prometheus"
8+
"github.com/stretchr/testify/assert"
9+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
)
11+
12+
func TestNodeGroupInfoMetric(t *testing.T) {
13+
// Create a test NodeGroup
14+
testNodeGroup := &v1.NodeGroup{
15+
ObjectMeta: metav1.ObjectMeta{
16+
Name: "test-ng",
17+
},
18+
Spec: v1.NodeGroupSpec{
19+
NodeGroupName: "test-nodegroup",
20+
NodeGroupsList: []string{"ng1", "ng2"},
21+
NodeSelector: metav1.LabelSelector{
22+
MatchLabels: map[string]string{
23+
"role": "worker",
24+
},
25+
},
26+
CycleSettings: v1.CycleSettings{
27+
Method: "Drain",
28+
Concurrency: 2,
29+
},
30+
MaxFailedCycleNodeRequests: 3,
31+
ValidationOptions: v1.ValidationOptions{
32+
SkipMissingNamedNodes: true,
33+
},
34+
SkipInitialHealthChecks: false,
35+
SkipPreTerminationChecks: true,
36+
Priority: 10,
37+
},
38+
}
39+
40+
// Create a test NodeGroupList
41+
testNodeGroupList := &v1.NodeGroupList{
42+
Items: []v1.NodeGroup{*testNodeGroup},
43+
}
44+
45+
// Create a mock collector with all required fields initialized
46+
collector := &cyclopsCollector{
47+
nodeGroupList: testNodeGroupList,
48+
cycleNodeRequestList: &v1.CycleNodeRequestList{Items: []v1.CycleNodeRequest{}},
49+
cycleNodeStatusList: &v1.CycleNodeStatusList{Items: []v1.CycleNodeStatus{}},
50+
}
51+
52+
// Test that the metric can be described
53+
t.Run("Describe", func(t *testing.T) {
54+
ch := make(chan *prometheus.Desc, 10) // Buffer size to hold all metrics
55+
go func() {
56+
collector.Describe(ch)
57+
close(ch)
58+
}()
59+
60+
// Read all descriptions
61+
descriptions := make([]*prometheus.Desc, 0)
62+
for desc := range ch {
63+
descriptions = append(descriptions, desc)
64+
}
65+
66+
// Verify we got descriptions and one contains our metric
67+
assert.Greater(t, len(descriptions), 0)
68+
found := false
69+
for _, desc := range descriptions {
70+
if desc.String() == NodeGroupInfo.String() {
71+
found = true
72+
break
73+
}
74+
}
75+
assert.True(t, found, "NodeGroupInfo metric should be described")
76+
})
77+
78+
// Test that the metric can be collected
79+
t.Run("Collect", func(t *testing.T) {
80+
ch := make(chan prometheus.Metric, 10) // Buffer size to hold all metrics
81+
go func() {
82+
collector.Collect(ch)
83+
close(ch)
84+
}()
85+
86+
// Read all metrics
87+
metrics := make([]prometheus.Metric, 0)
88+
for metric := range ch {
89+
metrics = append(metrics, metric)
90+
}
91+
92+
// Verify we got metrics and one is our NodeGroupInfo
93+
assert.Greater(t, len(metrics), 0)
94+
found := false
95+
for _, metric := range metrics {
96+
desc := metric.Desc()
97+
if desc.String() == NodeGroupInfo.String() {
98+
found = true
99+
break
100+
}
101+
}
102+
assert.True(t, found, "NodeGroupInfo metric should be collected")
103+
})
104+
}
105+
106+
func TestNodeGroupInfoLabels(t *testing.T) {
107+
// Test that the metric definition has the correct number of labels
108+
expectedLabels := []string{
109+
"nodegroup_name",
110+
"nodegroups_list",
111+
"node_selector",
112+
"concurrency",
113+
"method",
114+
"max_failed_cnrs",
115+
"skip_missing_named_nodes",
116+
"skip_initial_health_checks",
117+
"skip_pre_termination_checks",
118+
"priority",
119+
}
120+
121+
// Verify we have the expected number of labels
122+
assert.Equal(t, 10, len(expectedLabels))
123+
124+
assert.Contains(t, NodeGroupInfo.String(), "cyclops_node_group_info")
125+
126+
// Test that the metric is properly registered
127+
assert.NotNil(t, NodeGroupInfo)
128+
}

0 commit comments

Comments
 (0)