Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Target Allocator implementation (Part 3 - Collector Enhancement for Prometheus Config Update) #389

Merged
merged 45 commits into from
Sep 15, 2021
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
130e69d
load balancer deployment implementation & controller & e2e tests
alexperez52 Jul 8, 2021
2835c16
Load balancer crd update, reconcile logic and e2e tests
Jul 8, 2021
6f81007
Reset last commit and only uploading changes to main.go
alexperez52 Jul 8, 2021
31f97fe
Updated bundle and api with new autogenerated resources
rsvarma95 Jul 8, 2021
47c5fe8
Updated code with lint fixes
Jul 9, 2021
8ef4cde
Updated code to include minor fixes
rsvarma95 Jul 12, 2021
c73470e
Update helper.go to add header
Jul 12, 2021
7482e13
Updated comment and bundles
rsvarma95 Jul 13, 2021
729d4ea
Updated lb reconcile helper function and its invocations
rsvarma95 Jul 13, 2021
2dcf8a1
Updated naming scheme and changed CR config
rsvarma95 Jul 16, 2021
a0d3f34
Updated bundle files
rsvarma95 Jul 16, 2021
492749e
Minor changes
rsvarma95 Jul 20, 2021
6a72424
Lint and default file fixes
rsvarma95 Jul 21, 2021
8657668
Added rolebinding to automate manual setting
rsvarma95 Jul 30, 2021
0528856
Update opentelemetry-operator.clusterserviceversion.yaml
Jul 30, 2021
1a921cb
Merge branch 'main' into load-balancer-implementation
Jul 30, 2021
bf1010b
Removed role/rolebinding files & Minor changes
Aug 3, 2021
38ca88a
Minor changes
Aug 3, 2021
be56aa7
Merge branch 'main' into load-balancer-implementation
Aug 3, 2021
e339eba
Added error check in configmap reconcile & spelling correction
Aug 3, 2021
6f39c47
Updated target allocator KUTTL tests & renamed folder
rsvarma95 Aug 3, 2021
367c623
Updated folder structure to reduce code duplication between collector…
rsvarma95 Aug 4, 2021
7dd75b3
Updated kuttl tests to use namespace-scope resources
rsvarma95 Aug 4, 2021
0ef5424
Merge branch 'main' into load-balancer-implementation
rsvarma95 Aug 5, 2021
db40373
Revert part of "Updated folder structure to reduce code duplication b…
Aug 5, 2021
67af909
Removed separate controller for target allocation
Aug 6, 2021
888ae31
Added additional label for collector pod selection and removed test-step
Aug 9, 2021
11d3c87
Minor changes
Aug 9, 2021
a88da5e
Added collector enhancement for prometheus config update
Aug 9, 2021
47f2797
Update config_replace.go
Aug 10, 2021
deec3a4
Squashed commit of the following:
Aug 11, 2021
4e60755
Updated port and protocol
Aug 11, 2021
22e6013
Merge branch 'main' into collector-enhancement
Aug 11, 2021
ad0397d
Lint fixes
Aug 11, 2021
9652624
Removed unnecessary structs
Aug 11, 2021
5a68d39
Squashed commit of the following:
Aug 12, 2021
220a2e0
Updated structure to reflect new changes in first part
Aug 12, 2021
e0f12d4
Squashed commit of the following:
Aug 13, 2021
ecc9ee1
Merged with main branch
Aug 13, 2021
f5be148
Merge branch 'main' into collector-enhancement
Aug 13, 2021
53f8266
Minor changes
rsvarma95 Aug 16, 2021
f06abff
Merge branch 'main' into collector-enhancement
rsvarma95 Aug 19, 2021
bac84fc
Merge branch 'main' into collector-enhancement
rsvarma95 Aug 25, 2021
f12ef4f
Updated go.sum
rsvarma95 Aug 26, 2021
fff7219
Updated go.mod
rsvarma95 Aug 26, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ go 1.16
require (
github.com/Masterminds/semver/v3 v3.1.1
github.com/go-logr/logr v0.4.0
github.com/mitchellh/mapstructure v1.4.1
github.com/prometheus/prometheus v1.8.2-0.20210621150501-ff58416a0b02
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.7.0
gopkg.in/yaml.v2 v2.4.0
Expand Down
898 changes: 887 additions & 11 deletions go.sum

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions pkg/collector/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ func Container(cfg config.Config, logger logr.Logger, otelcol v1alpha1.OpenTelem
envVars = []corev1.EnvVar{}
}

envVars = append(envVars, corev1.EnvVar{
Name: "POD_NAME",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
FieldPath: "metadata.name",
},
},
})

return corev1.Container{
Name: naming.Container(),
Image: image,
Expand Down
7 changes: 4 additions & 3 deletions pkg/collector/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,12 @@ func TestContainerEnvVarsOverridden(t *testing.T) {
c := Container(cfg, logger, otelcol)

// verify
assert.Len(t, c.Env, 1)
assert.Len(t, c.Env, 2)
assert.Equal(t, "foo", c.Env[0].Name)
assert.Equal(t, "bar", c.Env[0].Value)
}

func TestContainerEmptyEnvVarsByDefault(t *testing.T) {
func TestContainerDefaultEnvVars(t *testing.T) {
otelcol := v1alpha1.OpenTelemetryCollector{
Spec: v1alpha1.OpenTelemetryCollectorSpec{},
}
Expand All @@ -158,7 +158,8 @@ func TestContainerEmptyEnvVarsByDefault(t *testing.T) {
c := Container(cfg, logger, otelcol)

// verify
assert.Empty(t, c.Env)
assert.Len(t, c.Env, 1)
assert.Equal(t, c.Env[0].Name, "POD_NAME")
}

func TestContainerResourceRequirements(t *testing.T) {
Expand Down
84 changes: 84 additions & 0 deletions pkg/collector/reconcile/config_replace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package reconcile

import (
"fmt"

"github.com/mitchellh/mapstructure"
promconfig "github.com/prometheus/prometheus/config"
"github.com/prometheus/prometheus/discovery"
"github.com/prometheus/prometheus/discovery/http"
_ "github.com/prometheus/prometheus/discovery/install"
"gopkg.in/yaml.v2"

"github.com/open-telemetry/opentelemetry-operator/pkg/collector/adapters"
"github.com/open-telemetry/opentelemetry-operator/pkg/naming"
ta "github.com/open-telemetry/opentelemetry-operator/pkg/targetallocator/adapters"
)

type Config struct {
PromConfig *promconfig.Config `yaml:"config"`
}

func ReplaceConfig(params Params) (string, error) {
if !params.Instance.Spec.TargetAllocator.Enabled {
return params.Instance.Spec.Config, nil
}
config, err := adapters.ConfigFromString(params.Instance.Spec.Config)
if err != nil {
return "", err
}

promCfgMap, err := ta.ConfigToPromConfig(params.Instance.Spec.Config)
if err != nil {
return "", err
}

// yaml marshaling/unsmarshaling is preferred because of the problems associated with the conversion of map to a struct using mapstructure
promCfg, err := yaml.Marshal(map[string]interface{}{
"config": promCfgMap,
})
if err != nil {
return "", err
}

var cfg Config
if err = yaml.UnmarshalStrict(promCfg, &cfg); err != nil {
return "", fmt.Errorf("error unmarshaling YAML: %w", err)
}

for i := range cfg.PromConfig.ScrapeConfigs {
cfg.PromConfig.ScrapeConfigs[i].ServiceDiscoveryConfigs = discovery.Configs{
rsvarma95 marked this conversation as resolved.
Show resolved Hide resolved
&http.SDConfig{
URL: fmt.Sprintf("http://%s:80/jobs/%s/targets?collector_id=$POD_NAME", naming.TAService(params.Instance), cfg.PromConfig.ScrapeConfigs[i].JobName),
},
}
}

updPromCfgMap := make(map[string]interface{})
if err := mapstructure.Decode(cfg, &updPromCfgMap); err != nil {
return "", err
}

// type corecion checks are handled in the ConfigToPromConfig method above
rsvarma95 marked this conversation as resolved.
Show resolved Hide resolved
config["receivers"].(map[interface{}]interface{})["prometheus"].(map[interface{}]interface{})["config"] = updPromCfgMap["PromConfig"]

out, err := yaml.Marshal(config)
if err != nil {
return "", err
}
return string(out), nil
}
98 changes: 98 additions & 0 deletions pkg/collector/reconcile/config_replace_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package reconcile

import (
"testing"

"github.com/prometheus/prometheus/discovery/http"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v2"

ta "github.com/open-telemetry/opentelemetry-operator/pkg/targetallocator/adapters"
)

func TestPrometheusParser(t *testing.T) {
param, err := newParams("test/test-img", "../testdata/http_sd_config_test.yaml")
assert.NoError(t, err)

t.Run("should update config with http_sd_config", func(t *testing.T) {
actualConfig, err := ReplaceConfig(param)
assert.NoError(t, err)

// prepare
var cfg Config
promCfgMap, err := ta.ConfigToPromConfig(actualConfig)
assert.NoError(t, err)

promCfg, err := yaml.Marshal(map[string]interface{}{
"config": promCfgMap,
})
assert.NoError(t, err)

err = yaml.UnmarshalStrict(promCfg, &cfg)
assert.NoError(t, err)

// test
expectedMap := map[string]bool{
"prometheus": false,
"service-x": false,
}
for _, scrapeConfig := range cfg.PromConfig.ScrapeConfigs {
assert.Len(t, scrapeConfig.ServiceDiscoveryConfigs, 1)
assert.Equal(t, scrapeConfig.ServiceDiscoveryConfigs[0].Name(), "http")
assert.Equal(t, scrapeConfig.ServiceDiscoveryConfigs[0].(*http.SDConfig).URL, "http://test-targetallocator:80/jobs/"+scrapeConfig.JobName+"/targets?collector_id=$POD_NAME")
expectedMap[scrapeConfig.JobName] = true
}
for k := range expectedMap {
assert.True(t, expectedMap[k], k)
}
})

t.Run("should not update config with http_sd_config", func(t *testing.T) {
param.Instance.Spec.TargetAllocator.Enabled = false
actualConfig, err := ReplaceConfig(param)
assert.NoError(t, err)

// prepare
var cfg Config
promCfgMap, err := ta.ConfigToPromConfig(actualConfig)
assert.NoError(t, err)

promCfg, err := yaml.Marshal(map[string]interface{}{
"config": promCfgMap,
})
assert.NoError(t, err)

err = yaml.UnmarshalStrict(promCfg, &cfg)
assert.NoError(t, err)

// test
expectedMap := map[string]bool{
"prometheus": false,
"service-x": false,
}
for _, scrapeConfig := range cfg.PromConfig.ScrapeConfigs {
assert.Len(t, scrapeConfig.ServiceDiscoveryConfigs, 2)
assert.Equal(t, scrapeConfig.ServiceDiscoveryConfigs[0].Name(), "file")
assert.Equal(t, scrapeConfig.ServiceDiscoveryConfigs[1].Name(), "static")
expectedMap[scrapeConfig.JobName] = true
}
for k := range expectedMap {
assert.True(t, expectedMap[k], k)
}
})

}
6 changes: 5 additions & 1 deletion pkg/collector/reconcile/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ func desiredConfigMap(_ context.Context, params Params) corev1.ConfigMap {
name := naming.ConfigMap(params.Instance)
labels := collector.Labels(params.Instance)
labels["app.kubernetes.io/name"] = name
config, err := ReplaceConfig(params)
if err != nil {
params.Log.V(2).Info("failed to parse config: ", err)
rsvarma95 marked this conversation as resolved.
Show resolved Hide resolved
}

return corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Expand All @@ -75,7 +79,7 @@ func desiredConfigMap(_ context.Context, params Params) corev1.ConfigMap {
Annotations: params.Instance.Annotations,
},
Data: map[string]string{
"collector.yaml": params.Instance.Spec.Config,
"collector.yaml": config,
},
}
}
Expand Down
54 changes: 52 additions & 2 deletions pkg/collector/reconcile/configmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ receivers:
prometheus:
config:
scrape_configs:
job_name: otel-collector
- job_name: otel-collector
scrape_interval: 10s
static_configs:
- targets: [ '0.0.0.0:8888', '0.0.0.0:9999' ]
Expand All @@ -75,14 +75,64 @@ service:

})

t.Run("should return expected collector config map with http_sd_config", func(t *testing.T) {
expectedLables["app.kubernetes.io/component"] = "opentelemetry-collector"
expectedLables["app.kubernetes.io/name"] = "test-collector"

expectedData := map[string]string{
"collector.yaml": `exporters:
logging: null
processors: null
receivers:
jaeger:
protocols:
grpc: null
prometheus:
config:
global:
scrape_interval: 1m
scrape_timeout: 10s
evaluation_interval: 1m
scrape_configs:
- job_name: otel-collector
honor_timestamps: true
scrape_interval: 10s
scrape_timeout: 10s
metrics_path: /metrics
scheme: http
follow_redirects: true
http_sd_configs:
- follow_redirects: false
url: http://test-targetallocator:80/jobs/otel-collector/targets?collector_id=$POD_NAME
service:
pipelines:
metrics:
exporters:
- logging
processors: []
receivers:
- prometheus
`,
}

param := params()
param.Instance.Spec.TargetAllocator.Enabled = true
actual := desiredConfigMap(context.Background(), param)

assert.Equal(t, "test-collector", actual.Name)
assert.Equal(t, expectedLables, actual.Labels)
assert.Equal(t, expectedData, actual.Data)

})

t.Run("should return expected target allocator config map", func(t *testing.T) {
expectedLables["app.kubernetes.io/component"] = "opentelemetry-targetallocator"
expectedLables["app.kubernetes.io/name"] = "test-targetallocator"

expectedData := map[string]string{
"targetallocator.yaml": `config:
scrape_configs:
job_name: otel-collector
- job_name: otel-collector
scrape_interval: 10s
static_configs:
- targets:
Expand Down
4 changes: 2 additions & 2 deletions pkg/collector/reconcile/deployment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func TestExpectedDeployments(t *testing.T) {
createObjectIfNotExists(t, "test-targetallocator", &expectedTADeploy)
orgUID := expectedTADeploy.OwnerReferences[0].UID

updatedParam, err := newParams("test/test-img")
updatedParam, err := newParams("test/test-img", "")
assert.NoError(t, err)
updatedDeploy := targetallocator.Deployment(updatedParam.Config, logger, param.Instance)
*updatedDeploy.Spec.Replicas = int32(3)
Expand All @@ -144,7 +144,7 @@ func TestExpectedDeployments(t *testing.T) {
createObjectIfNotExists(t, "test-targetallocator", &expectedTADeploy)
orgUID := expectedTADeploy.OwnerReferences[0].UID

updatedParam, err := newParams("test/test-img")
updatedParam, err := newParams("test/test-img", "")
assert.NoError(t, err)
updatedDeploy := targetallocator.Deployment(updatedParam.Config, logger, updatedParam.Instance)

Expand Down
13 changes: 10 additions & 3 deletions pkg/collector/reconcile/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func TestMain(m *testing.M) {

func params() Params {
replicas := int32(2)
configYAML, err := ioutil.ReadFile("test.yaml")
configYAML, err := ioutil.ReadFile("../testdata/test.yaml")
if err != nil {
fmt.Printf("Error getting yaml file: %v", err)
}
Expand Down Expand Up @@ -120,9 +120,16 @@ func params() Params {
}
}

func newParams(containerImage string) (Params, error) {
func newParams(containerImage string, file string) (Params, error) {
replicas := int32(1)
configYAML, err := ioutil.ReadFile("test.yaml")
var configYAML []byte
var err error

if file == "" {
configYAML, err = ioutil.ReadFile("../testdata/test.yaml")
} else {
configYAML, err = ioutil.ReadFile(file)
}
if err != nil {
return Params{}, fmt.Errorf("Error getting yaml file: %w", err)
}
Expand Down
Loading