Skip to content

Commit f758490

Browse files
gather aggregated numbers of Pods and Netnamespaces with SDN annotations (#946)
Co-authored-by: Tomáš Remeš <[email protected]>
1 parent 82e7c86 commit f758490

5 files changed

+321
-0
lines changed

docs/gathered-data.md

+25
Original file line numberDiff line numberDiff line change
@@ -1387,6 +1387,31 @@ with 'x' strings preserving the same length.
13871387
images running on the node.
13881388

13891389

1390+
## NumberOfPodsAndNetnamespacesWithSDNAnnotations
1391+
1392+
Collects number of Pods with the annotation:
1393+
`pod.network.openshift.io/assign-macvlan`
1394+
and also collects number of Netnamespaces with the annotation:
1395+
`netnamespace.network.openshift.io/multicast-enabled: "true"`
1396+
1397+
### Sample data
1398+
- [docs/insights-archive-sample/aggregated/pods_and_netnamespaces_with_sdn_annotations.json](./insights-archive-sample/aggregated/pods_and_netnamespaces_with_sdn_annotations.json)
1399+
1400+
### Location in archive
1401+
- `aggregated/pods_and_netnamespaces_with_sdn_annotations.json`
1402+
1403+
### Config ID
1404+
`clusterconfig/pods_and_netnamespaces_with_sdn_annotations`
1405+
1406+
### Released version
1407+
- 4.17.0
1408+
1409+
### Backported versions
1410+
1411+
### Changes
1412+
None
1413+
1414+
13901415
## OLMOperators
13911416

13921417
Collects the list of installed OLM operators. Each OLM operator (in the list) contains
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"pods_with_assign-macvlan_annotation":3,"netnamespaces_with_multicast-enabled_annotation":1}

pkg/gatherers/clusterconfig/clusterconfig_gatherer.go

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ var gatheringFunctions = map[string]gathererFuncPtr{
7373
"overlapping_namespace_uids": (*Gatherer).GatherNamespacesWithOverlappingUIDs,
7474
"pdbs": (*Gatherer).GatherPodDisruptionBudgets,
7575
"pod_network_connectivity_checks": (*Gatherer).GatherPodNetworkConnectivityChecks,
76+
"number_of_pods_and_netnamespaces_with_sdn_annotations": (*Gatherer).GatherNumberOfPodsAndNetnamespacesWithSDNAnnotations,
7677
"proxies": (*Gatherer).GatherClusterProxy,
7778
"sap_config": (*Gatherer).GatherSAPConfig,
7879
"sap_datahubs": (*Gatherer).GatherSAPDatahubs,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package clusterconfig
2+
3+
import (
4+
"context"
5+
6+
networkv1client "github.com/openshift/client-go/network/clientset/versioned/typed/network/v1"
7+
"github.com/openshift/insights-operator/pkg/record"
8+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9+
"k8s.io/client-go/kubernetes"
10+
)
11+
12+
const (
13+
assignMacVlanAnn = "pod.network.openshift.io/assign-macvlan"
14+
multicastEnabledAnn = "netnamespace.network.openshift.io/multicast-enabled"
15+
)
16+
17+
// GatherNumberOfPodsAndNetnamespacesWithSDNAnnotations Collects number of Pods with the annotation:
18+
// `pod.network.openshift.io/assign-macvlan`
19+
// and also collects number of Netnamespaces with the annotation:
20+
// `netnamespace.network.openshift.io/multicast-enabled: "true"`
21+
//
22+
// ### Sample data
23+
// - docs/insights-archive-sample/aggregated/pods_and_netnamespaces_with_sdn_annotations.json
24+
//
25+
// ### Location in archive
26+
// - `aggregated/pods_and_netnamespaces_with_sdn_annotations.json`
27+
//
28+
// ### Config ID
29+
// `clusterconfig/pods_and_netnamespaces_with_sdn_annotations`
30+
//
31+
// ### Released version
32+
// - 4.17.0
33+
//
34+
// ### Backported versions
35+
//
36+
// ### Changes
37+
// None
38+
func (g *Gatherer) GatherNumberOfPodsAndNetnamespacesWithSDNAnnotations(ctx context.Context) ([]record.Record, []error) {
39+
networkClient, err := networkv1client.NewForConfig(g.gatherKubeConfig)
40+
if err != nil {
41+
return nil, []error{err}
42+
}
43+
kubeCli, err := kubernetes.NewForConfig(g.gatherProtoKubeConfig)
44+
if err != nil {
45+
return nil, []error{err}
46+
}
47+
48+
return gatherNumberOfPodsAndNetnamespacesWithSDN(ctx, networkClient, kubeCli)
49+
}
50+
51+
type dataRecord struct {
52+
NumberOfPods int `json:"pods_with_assign-macvlan_annotation"`
53+
NumberOfNetnamespaces int `json:"netnamespaces_with_multicast-enabled_annotation"`
54+
}
55+
56+
func gatherNumberOfPodsAndNetnamespacesWithSDN(ctx context.Context,
57+
networkCli networkv1client.NetworkV1Interface,
58+
kubeCli kubernetes.Interface) ([]record.Record, []error) {
59+
var errs []error
60+
61+
numberOfPods, err := getNumberOfPodsWithAnnotation(ctx, assignMacVlanAnn, kubeCli)
62+
if err != nil {
63+
errs = append(errs, err)
64+
}
65+
numberOfNetnamespaces, err := getNumberOfNetnamespacesWithAnnotation(ctx, multicastEnabledAnn, networkCli)
66+
if err != nil {
67+
errs = append(errs, err)
68+
}
69+
70+
if numberOfNetnamespaces == 0 && numberOfPods == 0 {
71+
return nil, nil
72+
}
73+
74+
return []record.Record{
75+
{
76+
Name: "aggregated/pods_and_netnamespaces_with_sdn_annotations",
77+
Item: record.JSONMarshaller{Object: dataRecord{
78+
NumberOfPods: numberOfPods,
79+
NumberOfNetnamespaces: numberOfNetnamespaces,
80+
}},
81+
},
82+
}, errs
83+
}
84+
85+
// getNumberOfPodsWithAnnotation lists all the Pods in the cluster and counts the ones with provided annotation
86+
func getNumberOfPodsWithAnnotation(ctx context.Context, annotation string, kubeCli kubernetes.Interface) (int, error) {
87+
var continueValue string
88+
var numberOfPods int
89+
for {
90+
pods, err := kubeCli.CoreV1().Pods(metav1.NamespaceAll).List(ctx, metav1.ListOptions{
91+
Limit: 500,
92+
Continue: continueValue,
93+
})
94+
if err != nil {
95+
return 0, err
96+
}
97+
98+
for i := range pods.Items {
99+
pod := pods.Items[i]
100+
if _, ok := pod.Annotations[annotation]; ok {
101+
numberOfPods++
102+
}
103+
}
104+
105+
if pods.Continue == "" {
106+
break
107+
}
108+
continueValue = pods.Continue
109+
}
110+
return numberOfPods, nil
111+
}
112+
113+
// getNumberOfNetnamespacesWithAnnotation lists all the Netnamespaces in the cluster
114+
// and counts the ones with provided annotation
115+
func getNumberOfNetnamespacesWithAnnotation(ctx context.Context,
116+
annotation string,
117+
networkCli networkv1client.NetworkV1Interface) (int, error) {
118+
var numberOfNamespaces int
119+
var continueValue string
120+
121+
for {
122+
netNamespaces, err := networkCli.NetNamespaces().List(ctx, metav1.ListOptions{
123+
Limit: 500,
124+
Continue: continueValue,
125+
})
126+
if err != nil {
127+
return 0, err
128+
}
129+
130+
for i := range netNamespaces.Items {
131+
netNamespace := netNamespaces.Items[i]
132+
if v, ok := netNamespace.Annotations[annotation]; ok {
133+
if v == "true" {
134+
numberOfNamespaces++
135+
}
136+
}
137+
}
138+
139+
if netNamespaces.Continue == "" {
140+
break
141+
}
142+
continueValue = netNamespaces.Continue
143+
}
144+
145+
return numberOfNamespaces, nil
146+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package clusterconfig
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
networkv1 "github.com/openshift/api/network/v1"
8+
networkfake "github.com/openshift/client-go/network/clientset/versioned/fake"
9+
"github.com/openshift/insights-operator/pkg/record"
10+
"github.com/stretchr/testify/assert"
11+
v1 "k8s.io/api/core/v1"
12+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
"k8s.io/apimachinery/pkg/runtime"
14+
kubefake "k8s.io/client-go/kubernetes/fake"
15+
k8Testing "k8s.io/client-go/testing"
16+
)
17+
18+
func TestGatherNumberOfPodsAndNetnamespacesWithSDN(t *testing.T) {
19+
tests := []struct {
20+
name string
21+
pods []*v1.Pod
22+
netNamespaces []*networkv1.NetNamespace
23+
expctedRecords []record.Record
24+
}{
25+
{
26+
name: "no data found",
27+
pods: []*v1.Pod{
28+
{
29+
ObjectMeta: metav1.ObjectMeta{
30+
Name: "test-pod",
31+
},
32+
},
33+
},
34+
netNamespaces: []*networkv1.NetNamespace{
35+
{
36+
ObjectMeta: metav1.ObjectMeta{
37+
Name: "test-netnamespace",
38+
},
39+
},
40+
},
41+
expctedRecords: nil,
42+
},
43+
{
44+
name: "some data found",
45+
pods: []*v1.Pod{
46+
{
47+
ObjectMeta: metav1.ObjectMeta{
48+
Name: "test-pod-1",
49+
Annotations: map[string]string{
50+
"another-annotation": "true",
51+
},
52+
},
53+
},
54+
{
55+
ObjectMeta: metav1.ObjectMeta{
56+
Name: "test-pod-2",
57+
Annotations: map[string]string{
58+
assignMacVlanAnn: "true",
59+
},
60+
},
61+
},
62+
{
63+
ObjectMeta: metav1.ObjectMeta{
64+
Name: "test-pod-3",
65+
Annotations: map[string]string{
66+
assignMacVlanAnn: "",
67+
},
68+
},
69+
},
70+
{
71+
ObjectMeta: metav1.ObjectMeta{
72+
Name: "test-pod-4",
73+
Annotations: map[string]string{
74+
assignMacVlanAnn: "false",
75+
},
76+
},
77+
},
78+
},
79+
netNamespaces: []*networkv1.NetNamespace{
80+
{
81+
ObjectMeta: metav1.ObjectMeta{
82+
Name: "test-netnamespace-1",
83+
},
84+
},
85+
{
86+
ObjectMeta: metav1.ObjectMeta{
87+
Name: "test-netnamespace-2",
88+
Annotations: map[string]string{
89+
multicastEnabledAnn: "true",
90+
},
91+
},
92+
},
93+
{
94+
ObjectMeta: metav1.ObjectMeta{
95+
Name: "test-netnamespace-3",
96+
Annotations: map[string]string{
97+
multicastEnabledAnn: "false",
98+
},
99+
},
100+
},
101+
{
102+
ObjectMeta: metav1.ObjectMeta{
103+
Name: "test-netnamespace-4",
104+
Annotations: map[string]string{
105+
"aother-annotation": "true",
106+
},
107+
},
108+
},
109+
},
110+
expctedRecords: []record.Record{
111+
{
112+
Name: "aggregated/pods_and_netnamespaces_with_sdn_annotations",
113+
Item: record.JSONMarshaller{
114+
Object: dataRecord{
115+
NumberOfPods: 3,
116+
NumberOfNetnamespaces: 1,
117+
},
118+
},
119+
},
120+
},
121+
},
122+
}
123+
124+
for _, tt := range tests {
125+
t.Run(tt.name, func(t *testing.T) {
126+
kubeCli := kubefake.NewSimpleClientset()
127+
err := addObjectsToClientSet(kubeCli, tt.pods)
128+
assert.NoError(t, err)
129+
networkCli := networkfake.NewSimpleClientset()
130+
err = addObjectsToClientSet(networkCli, tt.netNamespaces)
131+
assert.NoError(t, err)
132+
records, errs := gatherNumberOfPodsAndNetnamespacesWithSDN(context.Background(), networkCli.NetworkV1(), kubeCli)
133+
assert.Empty(t, errs)
134+
assert.Equal(t, tt.expctedRecords, records)
135+
})
136+
}
137+
}
138+
139+
func addObjectsToClientSet[C []T, T runtime.Object](cli k8Testing.FakeClient, obj C) error {
140+
for i := range obj {
141+
o := obj[i]
142+
err := cli.Tracker().Add(o)
143+
if err != nil {
144+
return err
145+
}
146+
}
147+
return nil
148+
}

0 commit comments

Comments
 (0)