Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/pkg/operator/build_hierarchy_test.go
4094 views
1
//go:build !nonetwork && !nodocker && !race
2
3
package operator
4
5
import (
6
"context"
7
"fmt"
8
"sync"
9
"testing"
10
"time"
11
12
gragent "github.com/grafana/agent/pkg/operator/apis/monitoring/v1alpha1"
13
"github.com/grafana/agent/pkg/operator/hierarchy"
14
"github.com/grafana/agent/pkg/util"
15
"github.com/grafana/agent/pkg/util/k8s"
16
"github.com/grafana/agent/pkg/util/structwalk"
17
prom "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
18
"github.com/stretchr/testify/require"
19
v1 "k8s.io/api/core/v1"
20
"k8s.io/apimachinery/pkg/labels"
21
controller "sigs.k8s.io/controller-runtime"
22
"sigs.k8s.io/controller-runtime/pkg/client"
23
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
24
"sigs.k8s.io/controller-runtime/pkg/manager"
25
)
26
27
// Test_buildHierarchy checks that an entire resource hierarchy can be
28
// discovered.
29
func Test_buildHierarchy(t *testing.T) {
30
var wg sync.WaitGroup
31
defer wg.Wait()
32
33
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
34
defer cancel()
35
36
l := util.TestLogger(t)
37
cluster := NewTestCluster(ctx, t, l)
38
cli := newTestControllerClient(t, cluster)
39
40
resources := k8s.NewResourceSet(l, cluster)
41
defer resources.Stop()
42
require.NoError(t, resources.AddFile(ctx, "./testdata/test-resource-hierarchy.yaml"))
43
44
// Get root resource
45
var root gragent.GrafanaAgent
46
err := cli.Get(ctx, client.ObjectKey{Namespace: "default", Name: "grafana-agent-example"}, &root)
47
require.NoError(t, err)
48
49
deployment, watchers, err := buildHierarchy(ctx, l, cli, &root)
50
require.NoError(t, err)
51
52
// Check resources in hierarchy
53
{
54
expectedResources := []string{
55
"GrafanaAgent/grafana-agent-example",
56
"MetricsInstance/primary",
57
"Integration/node-exporter",
58
"LogsInstance/primary",
59
"PodMonitor/grafana-agents",
60
"PodLogs/grafana-agents",
61
}
62
var gotResources []string
63
structwalk.Walk(&resourceWalker{
64
onResource: func(c client.Object) {
65
gvk, _ := apiutil.GVKForObject(c, cli.Scheme())
66
67
key := fmt.Sprintf("%s/%s", gvk.Kind, c.GetName())
68
gotResources = append(gotResources, key)
69
},
70
}, deployment)
71
72
require.ElementsMatch(t, expectedResources, gotResources)
73
}
74
75
// Check secrets
76
{
77
expectedSecrets := []string{
78
"/secrets/default/prometheus-fake-credentials/fakeUsername",
79
"/secrets/default/prometheus-fake-credentials/fakePassword",
80
}
81
var actualSecrets []string
82
for key := range deployment.Secrets {
83
actualSecrets = append(actualSecrets, string(key))
84
}
85
86
require.ElementsMatch(t, expectedSecrets, actualSecrets)
87
}
88
89
// Check configured watchers
90
{
91
expectedWatchers := []hierarchy.Watcher{
92
{
93
Object: &gragent.MetricsInstance{},
94
Owner: client.ObjectKey{Namespace: "default", Name: "grafana-agent-example"},
95
Selector: &hierarchy.LabelsSelector{
96
NamespaceName: "default",
97
Labels: labels.SelectorFromSet(labels.Set{"agent": "grafana-agent-example"}),
98
},
99
},
100
{
101
Object: &gragent.LogsInstance{},
102
Owner: client.ObjectKey{Namespace: "default", Name: "grafana-agent-example"},
103
Selector: &hierarchy.LabelsSelector{
104
NamespaceName: "default",
105
Labels: labels.SelectorFromSet(labels.Set{"agent": "grafana-agent-example"}),
106
},
107
},
108
{
109
Object: &gragent.Integration{},
110
Owner: client.ObjectKey{Namespace: "default", Name: "grafana-agent-example"},
111
Selector: &hierarchy.LabelsSelector{
112
NamespaceName: "default",
113
Labels: labels.SelectorFromSet(labels.Set{"agent": "grafana-agent-example"}),
114
},
115
},
116
{
117
Object: &prom.ServiceMonitor{},
118
Owner: client.ObjectKey{Namespace: "default", Name: "grafana-agent-example"},
119
Selector: &hierarchy.LabelsSelector{
120
NamespaceName: "default",
121
NamespaceLabels: labels.Everything(),
122
Labels: labels.SelectorFromSet(labels.Set{"instance": "primary"}),
123
},
124
},
125
{
126
Object: &prom.PodMonitor{},
127
Owner: client.ObjectKey{Namespace: "default", Name: "grafana-agent-example"},
128
Selector: &hierarchy.LabelsSelector{
129
NamespaceName: "default",
130
NamespaceLabels: labels.Everything(),
131
Labels: labels.SelectorFromSet(labels.Set{"instance": "primary"}),
132
},
133
},
134
{
135
Object: &prom.Probe{},
136
Owner: client.ObjectKey{Namespace: "default", Name: "grafana-agent-example"},
137
Selector: &hierarchy.LabelsSelector{
138
NamespaceName: "default",
139
Labels: labels.Nothing(),
140
},
141
},
142
{
143
Object: &gragent.PodLogs{},
144
Owner: client.ObjectKey{Namespace: "default", Name: "grafana-agent-example"},
145
Selector: &hierarchy.LabelsSelector{
146
NamespaceName: "default",
147
NamespaceLabels: labels.Everything(),
148
Labels: labels.SelectorFromSet(labels.Set{"instance": "primary"}),
149
},
150
},
151
{
152
Object: &v1.Secret{},
153
Owner: client.ObjectKey{Namespace: "default", Name: "grafana-agent-example"},
154
Selector: &hierarchy.KeySelector{
155
Namespace: "default",
156
Name: "prometheus-fake-credentials",
157
},
158
},
159
}
160
require.ElementsMatch(t, expectedWatchers, watchers)
161
}
162
}
163
164
type resourceWalker struct {
165
onResource func(c client.Object)
166
}
167
168
func (w *resourceWalker) Visit(v interface{}) (next structwalk.Visitor) {
169
if v == nil {
170
return nil
171
}
172
if obj, ok := v.(client.Object); ok {
173
w.onResource(obj)
174
}
175
return w
176
}
177
178
// newTestControllerClient creates a Kubernetes client which uses a cache and
179
// index for retrieving objects. This more closely matches the behavior of the
180
// operator instead of using cluster.Client, which lacks a cache and always
181
// communicates directly with Kubernetes.
182
func newTestControllerClient(t *testing.T, cluster *k8s.Cluster) client.Client {
183
t.Helper()
184
185
ctx, cancel := context.WithCancel(context.Background())
186
t.Cleanup(cancel)
187
188
mgr, err := controller.NewManager(cluster.GetConfig(), manager.Options{
189
Scheme: cluster.Client().Scheme(),
190
})
191
require.NoError(t, err)
192
193
go func() {
194
require.NoError(t, mgr.Start(ctx))
195
}()
196
require.True(t, mgr.GetCache().WaitForCacheSync(ctx))
197
198
return mgr.GetClient()
199
}
200
201