diff --git a/.chloggen/pods-in-bridge-message.yaml b/.chloggen/pods-in-bridge-message.yaml new file mode 100755 index 0000000000..e0418cc4dd --- /dev/null +++ b/.chloggen/pods-in-bridge-message.yaml @@ -0,0 +1,16 @@ +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. operator, target allocator, github action) +component: bridge + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Sets pods in the component health map + +# One or more tracking issues related to the change +issues: [2489] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: this change adds a requirement for a new permission for the bridge to list and get pods. diff --git a/Makefile b/Makefile index 16b5a75663..0f3e4516f6 100644 --- a/Makefile +++ b/Makefile @@ -282,6 +282,10 @@ container-push: container-target-allocator-push: docker push ${TARGETALLOCATOR_IMG} +.PHONY: container-operator-opamp-bridge-push +container-operator-opamp-bridge-push: + docker push ${OPERATOROPAMPBRIDGE_IMG} + .PHONY: container-target-allocator container-target-allocator: GOOS = linux container-target-allocator: targetallocator @@ -333,7 +337,7 @@ endif .PHONY: load-image-operator-opamp-bridge -load-image-operator-opamp-bridge: +load-image-operator-opamp-bridge: container-operator-opamp-bridge kind load --name $(KIND_CLUSTER_NAME) docker-image ${OPERATOROPAMPBRIDGE_IMG} .PHONY: cert-manager diff --git a/cmd/operator-opamp-bridge/agent/agent.go b/cmd/operator-opamp-bridge/agent/agent.go index e9dc849b16..9282fd5444 100644 --- a/cmd/operator-opamp-bridge/agent/agent.go +++ b/cmd/operator-opamp-bridge/agent/agent.go @@ -18,6 +18,7 @@ import ( "bytes" "context" "fmt" + "strings" "time" "github.com/go-logr/logr" @@ -29,6 +30,7 @@ import ( "k8s.io/utils/clock" "sigs.k8s.io/yaml" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" "github.com/open-telemetry/opentelemetry-operator/cmd/operator-opamp-bridge/config" "github.com/open-telemetry/opentelemetry-operator/cmd/operator-opamp-bridge/metrics" "github.com/open-telemetry/opentelemetry-operator/cmd/operator-opamp-bridge/operator" @@ -37,7 +39,7 @@ import ( type Agent struct { logger logr.Logger - appliedKeys map[collectorKey]bool + appliedKeys map[kubeResourceKey]bool clock clock.Clock startTime uint64 lastHash []byte @@ -65,7 +67,7 @@ func NewAgent(logger logr.Logger, applier operator.ConfigApplier, config *config config: config, applier: applier, logger: logger, - appliedKeys: map[collectorKey]bool{}, + appliedKeys: map[kubeResourceKey]bool{}, instanceId: config.GetNewInstanceId(), agentDescription: config.GetDescription(), remoteConfigEnabled: config.RemoteConfigEnabled(), @@ -85,7 +87,7 @@ func NewAgent(logger logr.Logger, applier operator.ConfigApplier, config *config // getHealth is called every heartbeat interval to report health. func (agent *Agent) getHealth() *protobufs.ComponentHealth { - healthMap, err := agent.generateComponentHealthMap() + healthMap, err := agent.generateCollectorPoolHealth() if err != nil { return &protobufs.ComponentHealth{ Healthy: false, @@ -102,20 +104,70 @@ func (agent *Agent) getHealth() *protobufs.ComponentHealth { } } -// generateComponentHealthMap allows the bridge to report the status of the collector pools it owns. -// TODO: implement enhanced health messaging. -func (agent *Agent) generateComponentHealthMap() (map[string]*protobufs.ComponentHealth, error) { +// generateCollectorPoolHealth allows the bridge to report the status of the collector pools it owns. +// TODO: implement enhanced health messaging using the collector's new healthcheck extension: +// https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/26661 +func (agent *Agent) generateCollectorPoolHealth() (map[string]*protobufs.ComponentHealth, error) { cols, err := agent.applier.ListInstances() if err != nil { return nil, err } healthMap := map[string]*protobufs.ComponentHealth{} for _, col := range cols { - key := newCollectorKey(col.GetNamespace(), col.GetName()) + key := newKubeResourceKey(col.GetNamespace(), col.GetName()) + podMap, err := agent.generateCollectorHealth(agent.getCollectorSelector(col), col.GetNamespace()) + if err != nil { + return nil, err + } healthMap[key.String()] = &protobufs.ComponentHealth{ StartTimeUnixNano: uint64(col.ObjectMeta.GetCreationTimestamp().UnixNano()), StatusTimeUnixNano: uint64(agent.clock.Now().UnixNano()), Status: col.Status.Scale.StatusReplicas, + ComponentHealthMap: podMap, + } + } + return healthMap, nil +} + +// getCollectorSelector destructures the collectors scale selector if present, if uses the labelmap from the operator. +func (agent *Agent) getCollectorSelector(col v1alpha1.OpenTelemetryCollector) map[string]string { + if len(col.Status.Scale.Selector) > 0 { + selMap := map[string]string{} + for _, kvPair := range strings.Split(col.Status.Scale.Selector, ",") { + kv := strings.Split(kvPair, "=") + // skip malformed pairs + if len(kv) != 2 { + continue + } + selMap[kv[0]] = kv[1] + } + return selMap + } + return map[string]string{ + "app.kubernetes.io/managed-by": "opentelemetry-operator", + "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", col.GetNamespace(), col.GetName()), + "app.kubernetes.io/part-of": "opentelemetry", + "app.kubernetes.io/component": "opentelemetry-collector", + } +} + +func (agent *Agent) generateCollectorHealth(selectorLabels map[string]string, namespace string) (map[string]*protobufs.ComponentHealth, error) { + pods, err := agent.applier.GetCollectorPods(selectorLabels, namespace) + if err != nil { + return nil, err + } + healthMap := map[string]*protobufs.ComponentHealth{} + for _, item := range pods.Items { + key := newKubeResourceKey(item.GetNamespace(), item.GetName()) + healthy := true + if item.Status.Phase != "Running" { + healthy = false + } + healthMap[key.String()] = &protobufs.ComponentHealth{ + StartTimeUnixNano: uint64(item.Status.StartTime.UnixNano()), + StatusTimeUnixNano: uint64(agent.clock.Now().UnixNano()), + Status: string(item.Status.Phase), + Healthy: healthy, } } return healthMap, nil @@ -232,7 +284,7 @@ func (agent *Agent) getEffectiveConfig(ctx context.Context) (*protobufs.Effectiv agent.logger.Error(err, "failed to marhsal config") return nil, err } - mapKey := newCollectorKey(instance.GetNamespace(), instance.GetName()) + mapKey := newKubeResourceKey(instance.GetNamespace(), instance.GetName()) instanceMap[mapKey.String()] = &protobufs.AgentConfigFile{ Body: marshaled, ContentType: "yaml", @@ -277,7 +329,7 @@ func (agent *Agent) applyRemoteConfig(config *protobufs.AgentRemoteConfig) (*pro if len(key) == 0 || len(file.Body) == 0 { continue } - colKey, err := collectorKeyFromKey(key) + colKey, err := kubeResourceFromKey(key) if err != nil { multiErr = multierr.Append(multiErr, err) continue diff --git a/cmd/operator-opamp-bridge/agent/agent_test.go b/cmd/operator-opamp-bridge/agent/agent_test.go index b6086c79bf..c8dd542be2 100644 --- a/cmd/operator-opamp-bridge/agent/agent_test.go +++ b/cmd/operator-opamp-bridge/agent/agent_test.go @@ -31,9 +31,11 @@ import ( "github.com/spf13/pflag" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" testingclock "k8s.io/utils/clock/testing" + runtimeClient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" @@ -49,9 +51,11 @@ const ( testNamespace = "testnamespace" testCollectorName = "collector" otherCollectorName = "other" + thirdCollectorName = "third" emptyConfigHash = "" testCollectorKey = testNamespace + "/" + testCollectorName otherCollectorKey = testNamespace + "/" + otherCollectorName + thirdCollectorKey = otherCollectorName + "/" + thirdCollectorName agentTestFileName = "testdata/agent.yaml" agentTestFileHttpName = "testdata/agenthttpbasic.yaml" @@ -73,6 +77,32 @@ var ( invalidYamlConfigHash = getConfigHash(testCollectorKey, collectorInvalidFile) updatedYamlConfigHash = getConfigHash(testCollectorKey, collectorUpdatedFile) otherUpdatedYamlConfigHash = getConfigHash(otherCollectorKey, collectorUpdatedFile) + + podTime = metav1.NewTime(time.UnixMicro(1704748549000000)) + mockPodList = &v1.PodList{ + TypeMeta: metav1.TypeMeta{ + Kind: "PodList", + APIVersion: "v1", + }, + Items: []v1.Pod{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: thirdCollectorName + "-1", + Namespace: otherCollectorName, + Labels: map[string]string{ + "app.kubernetes.io/managed-by": "opentelemetry-operator", + "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", otherCollectorName, thirdCollectorName), + "app.kubernetes.io/part-of": "opentelemetry", + "app.kubernetes.io/component": "opentelemetry-collector", + }, + }, + Spec: v1.PodSpec{}, + Status: v1.PodStatus{ + StartTime: &podTime, + Phase: v1.PodRunning, + }, + }, + }} ) func getConfigHash(key, file string) string { @@ -130,16 +160,17 @@ func (m *mockOpampClient) SetPackageStatuses(_ *protobufs.PackageStatuses) error return nil } -func getFakeApplier(t *testing.T, conf *config.Config) *operator.Client { +func getFakeApplier(t *testing.T, conf *config.Config, lists ...runtimeClient.ObjectList) *operator.Client { schemeBuilder := runtime.NewSchemeBuilder(func(s *runtime.Scheme) error { s.AddKnownTypes(v1alpha1.GroupVersion, &v1alpha1.OpenTelemetryCollector{}, &v1alpha1.OpenTelemetryCollectorList{}) + s.AddKnownTypes(v1.SchemeGroupVersion, &v1.Pod{}, &v1.PodList{}) metav1.AddToGroupVersion(s, v1alpha1.GroupVersion) return nil }) scheme := runtime.NewScheme() err := schemeBuilder.AddToScheme(scheme) require.NoError(t, err, "Should be able to add custom types") - c := fake.NewClientBuilder().WithScheme(scheme) + c := fake.NewClientBuilder().WithLists(lists...).WithScheme(scheme) return operator.NewClient("test-bridge", l, c.Build(), conf.GetComponentsAllowed()) } @@ -205,6 +236,7 @@ func TestAgent_getHealth(t *testing.T) { LastError: "", Status: "", StatusTimeUnixNano: uint64(fakeClock.Now().UnixNano()), + ComponentHealthMap: map[string]*protobufs.ComponentHealth{}, }, }, }, @@ -236,6 +268,7 @@ func TestAgent_getHealth(t *testing.T) { LastError: "", Status: "", StatusTimeUnixNano: uint64(fakeClock.Now().UnixNano()), + ComponentHealthMap: map[string]*protobufs.ComponentHealth{}, }, "testnamespace/other": { Healthy: false, // we're working with mocks so the status will never be reconciled. @@ -243,6 +276,45 @@ func TestAgent_getHealth(t *testing.T) { LastError: "", Status: "", StatusTimeUnixNano: uint64(fakeClock.Now().UnixNano()), + ComponentHealthMap: map[string]*protobufs.ComponentHealth{}, + }, + }, + }, + }, + }, + { + name: "with pod health", + fields: fields{ + configFile: agentTestFileName, + }, + args: args{ + ctx: context.Background(), + configs: []map[string]string{ + { + thirdCollectorKey: collectorBasicFile, + }, + }, + }, + want: []*protobufs.ComponentHealth{ + { + Healthy: true, + StartTimeUnixNano: uint64(fakeClock.Now().UnixNano()), + StatusTimeUnixNano: uint64(fakeClock.Now().UnixNano()), + ComponentHealthMap: map[string]*protobufs.ComponentHealth{ + "other/third": { + Healthy: false, // we're working with mocks so the status will never be reconciled. + StartTimeUnixNano: collectorStartTime, + LastError: "", + Status: "", + StatusTimeUnixNano: uint64(fakeClock.Now().UnixNano()), + ComponentHealthMap: map[string]*protobufs.ComponentHealth{ + otherCollectorName + "/" + thirdCollectorName + "-1": { + Healthy: true, + Status: "Running", + StatusTimeUnixNano: uint64(fakeClock.Now().UnixNano()), + StartTimeUnixNano: uint64(podTime.UnixNano()), + }, + }, }, }, }, @@ -255,7 +327,7 @@ func TestAgent_getHealth(t *testing.T) { conf := config.NewConfig(logr.Discard()) loadErr := config.LoadFromFile(conf, tt.fields.configFile) require.NoError(t, loadErr, "should be able to load config") - applier := getFakeApplier(t, conf) + applier := getFakeApplier(t, conf, mockPodList) agent := NewAgent(l, applier, conf, mockClient) agent.clock = fakeClock err := agent.Start() diff --git a/cmd/operator-opamp-bridge/agent/collector_key.go b/cmd/operator-opamp-bridge/agent/kube_resource_key.go similarity index 70% rename from cmd/operator-opamp-bridge/agent/collector_key.go rename to cmd/operator-opamp-bridge/agent/kube_resource_key.go index d2e6c8d4f8..4d59d5e5c8 100644 --- a/cmd/operator-opamp-bridge/agent/collector_key.go +++ b/cmd/operator-opamp-bridge/agent/kube_resource_key.go @@ -20,24 +20,24 @@ import ( "strings" ) -type collectorKey struct { +type kubeResourceKey struct { name string namespace string } -func newCollectorKey(namespace string, name string) collectorKey { - return collectorKey{name: name, namespace: namespace} +func newKubeResourceKey(namespace string, name string) kubeResourceKey { + return kubeResourceKey{name: name, namespace: namespace} } -func collectorKeyFromKey(key string) (collectorKey, error) { +func kubeResourceFromKey(key string) (kubeResourceKey, error) { s := strings.Split(key, "/") // We expect map keys to be of the form name/namespace if len(s) != 2 { - return collectorKey{}, errors.New("invalid key") + return kubeResourceKey{}, errors.New("invalid key") } - return newCollectorKey(s[0], s[1]), nil + return newKubeResourceKey(s[0], s[1]), nil } -func (k collectorKey) String() string { +func (k kubeResourceKey) String() string { return fmt.Sprintf("%s/%s", k.namespace, k.name) } diff --git a/cmd/operator-opamp-bridge/agent/collector_key_test.go b/cmd/operator-opamp-bridge/agent/kube_resource_key_test.go similarity index 83% rename from cmd/operator-opamp-bridge/agent/collector_key_test.go rename to cmd/operator-opamp-bridge/agent/kube_resource_key_test.go index 7a27180f69..30385762b7 100644 --- a/cmd/operator-opamp-bridge/agent/collector_key_test.go +++ b/cmd/operator-opamp-bridge/agent/kube_resource_key_test.go @@ -28,7 +28,7 @@ func Test_collectorKeyFromKey(t *testing.T) { tests := []struct { name string args args - want collectorKey + want kubeResourceKey wantErr assert.ErrorAssertionFunc }{ { @@ -36,7 +36,7 @@ func Test_collectorKeyFromKey(t *testing.T) { args: args{ key: "namespace/good", }, - want: collectorKey{ + want: kubeResourceKey{ name: "good", namespace: "namespace", }, @@ -47,7 +47,7 @@ func Test_collectorKeyFromKey(t *testing.T) { args: args{ key: "badnamespace", }, - want: collectorKey{}, + want: kubeResourceKey{}, wantErr: assert.Error, }, { @@ -55,17 +55,17 @@ func Test_collectorKeyFromKey(t *testing.T) { args: args{ key: "too/many/slashes", }, - want: collectorKey{}, + want: kubeResourceKey{}, wantErr: assert.Error, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := collectorKeyFromKey(tt.args.key) - if !tt.wantErr(t, err, fmt.Sprintf("collectorKeyFromKey(%v)", tt.args.key)) { + got, err := kubeResourceFromKey(tt.args.key) + if !tt.wantErr(t, err, fmt.Sprintf("kubeResourceFromKey(%v)", tt.args.key)) { return } - assert.Equalf(t, tt.want, got, "collectorKeyFromKey(%v)", tt.args.key) + assert.Equalf(t, tt.want, got, "kubeResourceFromKey(%v)", tt.args.key) }) } } @@ -91,7 +91,7 @@ func Test_collectorKey_String(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - k := newCollectorKey(tt.fields.namespace, tt.fields.name) + k := newKubeResourceKey(tt.fields.namespace, tt.fields.name) assert.Equalf(t, tt.want, k.String(), "String()") }) } diff --git a/cmd/operator-opamp-bridge/config/config.go b/cmd/operator-opamp-bridge/config/config.go index 38f06d6ff9..90a1e310b0 100644 --- a/cmd/operator-opamp-bridge/config/config.go +++ b/cmd/operator-opamp-bridge/config/config.go @@ -269,7 +269,7 @@ func LoadFromFile(cfg *Config, configFile string) error { if err != nil { return err } - if err = yaml.UnmarshalStrict(yamlFile, cfg); err != nil { + if err = yaml.Unmarshal(yamlFile, cfg); err != nil { return fmt.Errorf("error unmarshaling YAML: %w", err) } return nil diff --git a/cmd/operator-opamp-bridge/config/config_test.go b/cmd/operator-opamp-bridge/config/config_test.go index e9caeb2b0c..9b9b0fdd3a 100644 --- a/cmd/operator-opamp-bridge/config/config_test.go +++ b/cmd/operator-opamp-bridge/config/config_test.go @@ -127,10 +127,7 @@ func TestLoad(t *testing.T) { args: args{ file: "./testdata/agentbadconf.yaml", }, - want: &Config{ - // We do unmarshal partially - Endpoint: "http://127.0.0.1:4320/v1/opamp", - }, + want: &Config{}, wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { return assert.ErrorContains(t, err, "error unmarshaling YAML", i...) }, diff --git a/cmd/operator-opamp-bridge/config/testdata/agentbadconf.yaml b/cmd/operator-opamp-bridge/config/testdata/agentbadconf.yaml index ba4903daf8..417db093eb 100644 --- a/cmd/operator-opamp-bridge/config/testdata/agentbadconf.yaml +++ b/cmd/operator-opamp-bridge/config/testdata/agentbadconf.yaml @@ -2,10 +2,14 @@ endpoint: http://127.0.0.1:4320/v1/opamp cawdawapabilities: AcceptsRemoteConfig: true ReportsEffectiveConfig: true - AcceptsPackages: false + AcceptsPackages: + false ReportsPackageStatuses: false - ReportsOwnTraces: true - ReportsOwnMetrics: true + Report + sOwnTraces: true + Re + + portsOwnMetrics: true ReportsOwnLogs: true AcceptsOpAMPConnectionSettings: true AcceptsOtherConnectionSettings: true diff --git a/cmd/operator-opamp-bridge/operator/client.go b/cmd/operator-opamp-bridge/operator/client.go index b892cbe177..3c11026d05 100644 --- a/cmd/operator-opamp-bridge/operator/client.go +++ b/cmd/operator-opamp-bridge/operator/client.go @@ -21,6 +21,7 @@ import ( "github.com/go-logr/logr" "github.com/open-telemetry/opamp-go/protobufs" + v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/selection" @@ -45,6 +46,9 @@ type ConfigApplier interface { // GetInstance retrieves an OpenTelemetryCollector CRD given a name and namespace. GetInstance(name string, namespace string) (*v1alpha1.OpenTelemetryCollector, error) + // GetCollectorPods retrieves all pods that match the given collector's selector labels and namespace. + GetCollectorPods(selectorLabels map[string]string, namespace string) (*v1.PodList, error) + // ListInstances retrieves all OpenTelemetryCollector CRDs created by the operator-opamp-bridge agent. ListInstances() ([]v1alpha1.OpenTelemetryCollector, error) @@ -219,6 +223,13 @@ func (c Client) GetInstance(name string, namespace string) (*v1alpha1.OpenTeleme return &result, nil } +func (c Client) GetCollectorPods(selectorLabels map[string]string, namespace string) (*v1.PodList, error) { + ctx := context.Background() + podList := &v1.PodList{} + err := c.k8sClient.List(ctx, podList, client.MatchingLabels(selectorLabels), client.InNamespace(namespace)) + return podList, err +} + func (c Client) validate(spec v1alpha1.OpenTelemetryCollectorSpec) ([]string, error) { // Do not use this feature if it's not specified if c.componentsAllowed == nil || len(c.componentsAllowed) == 0 { diff --git a/cmd/operator-opamp-bridge/operator/client_test.go b/cmd/operator-opamp-bridge/operator/client_test.go index 8db8fb1a51..22b76df92c 100644 --- a/cmd/operator-opamp-bridge/operator/client_test.go +++ b/cmd/operator-opamp-bridge/operator/client_test.go @@ -16,6 +16,7 @@ package operator import ( "context" + "fmt" "os" "testing" @@ -23,6 +24,7 @@ import ( "github.com/open-telemetry/opamp-go/protobufs" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -40,16 +42,17 @@ const ( bridgeName = "bridge-test" ) -func getFakeClient(t *testing.T) client.WithWatch { +func getFakeClient(t *testing.T, lists ...client.ObjectList) client.WithWatch { schemeBuilder := runtime.NewSchemeBuilder(func(s *runtime.Scheme) error { s.AddKnownTypes(v1alpha1.GroupVersion, &v1alpha1.OpenTelemetryCollector{}, &v1alpha1.OpenTelemetryCollectorList{}) + s.AddKnownTypes(v1.SchemeGroupVersion, &v1.Pod{}, &v1.PodList{}) metav1.AddToGroupVersion(s, v1alpha1.GroupVersion) return nil }) scheme := runtime.NewScheme() err := schemeBuilder.AddToScheme(scheme) require.NoError(t, err, "Should be able to add custom types") - c := fake.NewClientBuilder().WithScheme(scheme) + c := fake.NewClientBuilder().WithLists(lists...).WithScheme(scheme) return c.Build() } @@ -243,3 +246,86 @@ func loadConfig(file string) ([]byte, error) { } return yamlFile, nil } + +func TestClient_GetCollectorPods(t *testing.T) { + mockPodList := &v1.PodList{ + TypeMeta: metav1.TypeMeta{ + Kind: "PodList", + APIVersion: "v1", + }, + Items: []v1.Pod{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "mock-pod", + Namespace: "something", + Labels: map[string]string{ + "match1": "yes", + "match2": "1", + }, + }, + Spec: v1.PodSpec{}, + }, + }} + emptyList := &v1.PodList{ + TypeMeta: metav1.TypeMeta{ + Kind: "PodList", + APIVersion: "v1", + }, + Items: []v1.Pod{}} + type args struct { + selector map[string]string + namespace string + } + tests := []struct { + name string + args args + want *v1.PodList + wantErr assert.ErrorAssertionFunc + }{ + { + name: "base case", + args: args{ + selector: map[string]string{ + "match1": "yes", + "match2": "1", + }, + }, + want: mockPodList, + wantErr: assert.NoError, + }, + { + name: "no match", + args: args{ + selector: map[string]string{ + "match1": "yes", + "match2": "2", + }, + }, + want: emptyList, + wantErr: assert.NoError, + }, + { + name: "good selector wrong namespace", + args: args{ + selector: map[string]string{ + "match1": "yes", + "match2": "1", + }, + namespace: "nothing", + }, + want: emptyList, + wantErr: assert.NoError, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeClient := getFakeClient(t, mockPodList) + c := NewClient(bridgeName, clientLogger, fakeClient, nil) + got, err := c.GetCollectorPods(tt.args.selector, tt.args.namespace) + if !tt.wantErr(t, err, fmt.Sprintf("GetCollectorPods(%v)", tt.args.selector)) { + return + } + assert.Equalf(t, tt.want, got, "GetCollectorPods(%v)", tt.args.selector) + }) + } +} diff --git a/tests/e2e-opampbridge/opampbridge/00-install.yaml b/tests/e2e-opampbridge/opampbridge/00-install.yaml index bd4c263084..3bfbf50e88 100644 --- a/tests/e2e-opampbridge/opampbridge/00-install.yaml +++ b/tests/e2e-opampbridge/opampbridge/00-install.yaml @@ -15,6 +15,13 @@ rules: - opentelemetrycollectors verbs: - '*' +- apiGroups: + - '' + resources: + - pods + verbs: + - 'list' + - 'get' --- apiVersion: kuttl.dev/v1beta1 kind: TestStep