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

Add OTEL config to Jaeger CR #1056

Merged
merged 7 commits into from
May 12, 2020
Merged
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions deploy/crds/jaegertracing.io_jaegers_crd.yaml
Original file line number Diff line number Diff line change
@@ -578,6 +578,8 @@ spec:
type: string
nullable: true
type: object
config:
type: object
image:
type: string
labels:
@@ -2507,6 +2509,8 @@ spec:
type: object
autoscale:
type: boolean
config:
type: object
image:
type: string
labels:
@@ -3478,6 +3482,8 @@ spec:
type: object
autoscale:
type: boolean
config:
type: object
image:
type: string
labels:
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ go 1.13
require (
github.com/Masterminds/semver v1.5.0
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32
github.com/go-openapi/spec v0.19.4
github.com/googleapis/gnostic v0.3.1
github.com/mitchellh/go-homedir v1.1.0
@@ -24,6 +25,7 @@ require (
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271
golang.org/x/tools v0.0.0-20191205225056-3393d29bb9fe // indirect
google.golang.org/grpc v1.24.0
gopkg.in/yaml.v2 v2.2.4
k8s.io/api v0.0.0
k8s.io/apimachinery v0.0.0
k8s.io/client-go v12.0.0+incompatible
9 changes: 9 additions & 0 deletions pkg/apis/jaegertracing/v1/jaeger_types.go
Original file line number Diff line number Diff line change
@@ -323,6 +323,9 @@ type JaegerCollectorSpec struct {

// +optional
JaegerCommonSpec `json:",inline,omitempty"`

// +optional
Config FreeForm `json:"config,omitempty"`
}

// JaegerIngesterSpec defines the options to be used when deploying the ingester
@@ -343,6 +346,9 @@ type JaegerIngesterSpec struct {

// +optional
JaegerCommonSpec `json:",inline,omitempty"`

// +optional
Config FreeForm `json:"config,omitempty"`
}

// JaegerAgentSpec defines the options to be used when deploying the agent
@@ -360,6 +366,9 @@ type JaegerAgentSpec struct {

// +optional
JaegerCommonSpec `json:",inline,omitempty"`

// +optional
Config FreeForm `json:"config,omitempty"`
}

// JaegerStorageSpec defines the common storage options to be used for the query and collector
3 changes: 3 additions & 0 deletions pkg/apis/jaegertracing/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 18 additions & 3 deletions pkg/apis/jaegertracing/v1/zz_generated.openapi.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

137 changes: 137 additions & 0 deletions pkg/config/otelconfig/otelconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package otelconfig

import (
"fmt"

"github.com/ghodss/yaml"
"github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

v1 "github.com/jaegertracing/jaeger-operator/pkg/apis/jaegertracing/v1"
"github.com/jaegertracing/jaeger-operator/pkg/util"
)

const (
configFileName = "config.yaml"
configFlagName = "--config="
configFileLocation = "/etc/jaeger/otel/"
configFlagWithFile = configFlagName + configFileLocation + configFileName
configMapKey = "config"
)

// ShouldCreate returns true if the OTEL config should be created.
func ShouldCreate(jaeger *v1.Jaeger, opts v1.Options, otelCfg map[string]interface{}) bool {
if _, exists := opts.Map()["config"]; exists {
jaeger.Logger().Info("OpenTelemetry config will not be created. The config is explicitly provided in the options.")
return false
}
if len(otelCfg) == 0 {
return false
}
return true

}

// Get returns a OTEL config maps for a Jaeger instance.
func Get(jaeger *v1.Jaeger) []corev1.ConfigMap {
var cms []corev1.ConfigMap
c := createIfNeeded(jaeger, "agent", jaeger.Spec.Agent.Options, jaeger.Spec.Agent.Config)
if c != nil {
cms = append(cms, *c)
}
c = createIfNeeded(jaeger, "collector", jaeger.Spec.Collector.Options, jaeger.Spec.Collector.Config)
if c != nil {
cms = append(cms, *c)
}
c = createIfNeeded(jaeger, "ingester", jaeger.Spec.Ingester.Options, jaeger.Spec.Ingester.Config)
if c != nil {
cms = append(cms, *c)
}
return cms
}

func getMap(log *logrus.Entry, otelConfig v1.FreeForm) (map[string]interface{}, error) {
m, err := otelConfig.GetMap()
if err != nil {
log.WithField("error", err).
Errorf("Could not parse OTEL config, config map will not be created")
}
return m, err
}

func createIfNeeded(jaeger *v1.Jaeger, component string, opts v1.Options, otelConfig v1.FreeForm) *corev1.ConfigMap {
m, err := getMap(jaeger.Logger().WithField("component", component), otelConfig)
if err != nil {
return nil
}
if ShouldCreate(jaeger, opts, m) {
c, err := create(jaeger, component, m)
if err != nil {
return nil
}
return c
}
return nil
}

func create(jaeger *v1.Jaeger, component string, otelConfig map[string]interface{}) (*corev1.ConfigMap, error) {
cfgYml, err := yaml.Marshal(otelConfig)
if err != nil {
jaeger.Logger().
WithField("component", component).
WithField("config", otelConfig).
WithField("err", err).
Errorf("Could not marshall collector config to yaml")
return nil, err
}
return &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "ConfigMap",
},
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-%s-otel-config", jaeger.Name, component),
Namespace: jaeger.Namespace,
Labels: util.Labels(fmt.Sprintf("%s-%s-otel-config", jaeger.Name, component), fmt.Sprintf("%s-otel-config", component), *jaeger),
OwnerReferences: []metav1.OwnerReference{
util.AsOwner(jaeger),
},
},
Data: map[string]string{
configMapKey: string(cfgYml),
},
}, nil
}

// Update injects required flags and objects to the common spec.
func Update(jaeger *v1.Jaeger, component string, commonSpec *v1.JaegerCommonSpec, args *[]string) {
volume := corev1.Volume{
Name: volumeName(jaeger, component),
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: fmt.Sprintf("%s-%s-otel-config", jaeger.Name, component),
},
Items: []corev1.KeyToPath{
{
Key: configMapKey,
Path: configFileName,
},
},
},
},
}
volumeMount := corev1.VolumeMount{
Name: volumeName(jaeger, component),
MountPath: configFileLocation,
ReadOnly: true,
}
commonSpec.Volumes = append(commonSpec.Volumes, volume)
commonSpec.VolumeMounts = append(commonSpec.VolumeMounts, volumeMount)
*args = append(*args, configFlagWithFile)
}

func volumeName(jaeger *v1.Jaeger, component string) string {
return util.DNSName(util.Truncate("%s-%s-otel-config", 63, jaeger.Name, component))
}
90 changes: 90 additions & 0 deletions pkg/config/otelconfig/otelconfig_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package otelconfig

import (
"fmt"
"testing"

"github.com/stretchr/testify/assert"

"github.com/stretchr/testify/require"
"gopkg.in/yaml.v2"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"

v1 "github.com/jaegertracing/jaeger-operator/pkg/apis/jaegertracing/v1"
)

func TestShouldCreate(t *testing.T) {
tests := []struct {
opts v1.Options
otelCfg v1.FreeForm
expected bool
}{
{
expected: false,
opts: v1.NewOptions(map[string]interface{}{"config": "/etc/config.yaml"}),
otelCfg: v1.NewFreeForm(map[string]interface{}{"foo": "bar"}),
},
{
expected: true,
otelCfg: v1.NewFreeForm(map[string]interface{}{"foo": "bar"}),
},
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another like this, but with config - and expected: false.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure what you mean. I have added some case, I think there are all the combinations now.

expected: true,
opts: v1.NewOptions(map[string]interface{}{"someflag": "val"}),
otelCfg: v1.NewFreeForm(map[string]interface{}{"foo": "bar"}),
},
{
expected: false,
opts: v1.NewOptions(map[string]interface{}{}),
},
}
for i, test := range tests {
t.Run(fmt.Sprintf("%v", i), func(t *testing.T) {
m, err := test.otelCfg.GetMap()
require.NoError(t, err)
shouldCreate := ShouldCreate(v1.NewJaeger(types.NamespacedName{}), test.opts, m)
assert.Equal(t, test.expected, shouldCreate)
})
}
}

func TestGet(t *testing.T) {
j := v1.NewJaeger(types.NamespacedName{Name: "jaeger"})
j.Spec.Agent.Config = v1.NewFreeForm(map[string]interface{}{"processors": "bar"})
j.Spec.Collector.Config = v1.NewFreeForm(map[string]interface{}{"exporters": "bar"})
j.Spec.Ingester.Config = v1.NewFreeForm(map[string]interface{}{"receivers": "bar"})
cms := Get(j)
assert.Equal(t, 3, len(cms))
assert.Equal(t, "jaeger-agent-otel-config", cms[0].Name)
assert.Equal(t, "jaeger-collector-otel-config", cms[1].Name)
assert.Equal(t, "jaeger-ingester-otel-config", cms[2].Name)

m, err := j.Spec.Agent.Config.GetMap()
require.NoError(t, err)
yamlCfg, err := yaml.Marshal(m)
require.NoError(t, err)
assert.Equal(t, string(yamlCfg), cms[0].Data["config"])
m, err = j.Spec.Collector.Config.GetMap()
require.NoError(t, err)
yamlCfg, err = yaml.Marshal(m)
require.NoError(t, err)
assert.Equal(t, string(yamlCfg), cms[1].Data["config"])
m, err = j.Spec.Ingester.Config.GetMap()
require.NoError(t, err)
yamlCfg, err = yaml.Marshal(m)
require.NoError(t, err)
assert.Equal(t, string(yamlCfg), cms[2].Data["config"])
}

func TestUpdate(t *testing.T) {
j := v1.NewJaeger(types.NamespacedName{Name: "jaeger"})
args := []string{}
commonSpec := &v1.JaegerCommonSpec{}
Update(j, "agent", commonSpec, &args)
assert.Equal(t, []string{configFlagWithFile}, args)
assert.Equal(t, "jaeger-agent-otel-config", commonSpec.Volumes[0].Name)
assert.Equal(t, "jaeger-agent-otel-config", commonSpec.VolumeMounts[0].Name)
assert.Equal(t, []corev1.KeyToPath{{Key: "config", Path: configFileName}}, commonSpec.Volumes[0].ConfigMap.Items)
assert.Equal(t, configFileLocation, commonSpec.VolumeMounts[0].MountPath)
}
Loading