diff --git a/pkg/collector/upgrade/v0_61_0.go b/pkg/collector/upgrade/v0_61_0.go new file mode 100644 index 0000000000..a714f75249 --- /dev/null +++ b/pkg/collector/upgrade/v0_61_0.go @@ -0,0 +1,142 @@ +// 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 upgrade + +import ( + "fmt" + "sort" + "strings" + + "gopkg.in/yaml.v2" + corev1 "k8s.io/api/core/v1" + + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/pkg/collector/adapters" +) + +func upgrade0_61_0(u VersionUpgrade, otelcol *v1alpha1.OpenTelemetryCollector) (*v1alpha1.OpenTelemetryCollector, error) { + if len(otelcol.Spec.Config) == 0 { + return otelcol, nil + } + + otelCfg, err := adapters.ConfigFromString(otelcol.Spec.Config) + if err != nil { + return otelcol, fmt.Errorf("couldn't upgrade to v0.61.0, failed to parse configuration: %w", err) + } + + // Search for removed Jaeger remote sampling settings. (https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/14163) + receiversConfig, ok := otelCfg["receivers"].(map[string]interface{}) + if !ok { + // In case there is no extensions config. + return otelcol, nil + } + + jaegerRec := make(map[string]interface{}, 0) + for k, rc := range receiversConfig { + cfg, ok := rc.(map[string]interface{}) + // check if jaeger is configured + if !ok || !strings.HasPrefix(k, "jaeger") { + continue + } + // check if remote sampling settings exit + rs, ok := cfg["remote_sampling"] + if !ok { + continue + } + jaegerRec[k] = rs + } + + if len(jaegerRec) == 0 { + // nothing to do + return otelcol, nil + } + + extensionsConfig, ok := otelCfg["extensions"].(map[string]interface{}) + if !ok { + // In case there is no extensions config. + extensionsConfig = make(map[string]interface{}) + } + + var jaegerExtenions []string + for recName, oldCfg := range jaegerRec { + extName := "jaegerremotesampling" + split := strings.Split(recName, "/") + if len(split) > 2 { + return nil, fmt.Errorf("couldn't upgrade to v0.61.0, failed to define extension name: %w", err) + } else if len(split) == 2 { + extName = fmt.Sprintf("%s/%s", extName, split[1]) + } + // Configure new Jaeger remote sampling extension. (https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/6510) + newCfg, err := upgradeRemoteSamplingConfigTo0_60_0(oldCfg) + if err != nil { + return nil, err + } + extensionsConfig[extName] = newCfg + jaegerExtenions = append(jaegerExtenions, extName) + } + + otelCfg["extensions"] = extensionsConfig + serviceConfig, ok := otelCfg["service"].(map[string]interface{}) + if !ok { + // In case there is no extensions config. + serviceConfig = make(map[string]interface{}) + } + + extensionConfig, ok := serviceConfig["extensions"].(map[string]interface{}) + if !ok { + extensionConfig = make(map[string]interface{}) + } + for _, name := range jaegerExtenions { + extensionConfig["extensions"] = name + } + otelCfg["service"] = serviceConfig + + res, err := yaml.Marshal(otelCfg) + if err != nil { + return otelcol, fmt.Errorf("couldn't upgrade to v0.61.0, failed to marshall back configuration: %w", err) + } + otelcol.Spec.Config = string(res) + keys := make([]string, 0, len(jaegerRec)) + for k := range jaegerRec { + keys = append(keys, k) + } + sort.Strings(keys) + existing := &corev1.ConfigMap{} + updated := existing.DeepCopy() + u.Recorder.Event(updated, "Normal", "Upgrade", + fmt.Sprintf("upgrade to v0.61.0 replaced the deprecated jaeger receiver settings with "+ + "jaegerremotesampling extension settings. Affected receivers are: %v", keys), + ) + return otelcol, nil +} + +func upgradeRemoteSamplingConfigTo0_60_0(input interface{}) (interface{}, error) { + origin, ok := input.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("couldn't upgrade to v0.61.0, failed to convert receiver: %v", origin) + } + newCfg := make(map[string]map[string]interface{}) + newCfg["source"]["remote"] = map[string]interface{}{"endpoint": origin["endpoint"]} + newCfg["source"]["tls"] = origin["tls"] + newCfg["source"]["reload_interval"] = origin["strategy_file"] + newCfg["source"]["file"] = origin["strategy_file_reload_interval"] + + delete(origin, "endpoint") + delete(origin, "tls") + delete(origin, "strategy_file") + delete(origin, "strategy_file_reload_interval") + + return origin, nil +} diff --git a/pkg/collector/upgrade/v0_61_0_test.go b/pkg/collector/upgrade/v0_61_0_test.go new file mode 100644 index 0000000000..e8aa79c38e --- /dev/null +++ b/pkg/collector/upgrade/v0_61_0_test.go @@ -0,0 +1,111 @@ +// 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 upgrade_test + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/record" + + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/internal/version" + "github.com/open-telemetry/opentelemetry-operator/pkg/collector/upgrade" +) + +func Test0_61_0Upgrade(t *testing.T) { + collectorInstance := v1alpha1.OpenTelemetryCollector{ + TypeMeta: metav1.TypeMeta{ + Kind: "OpenTelemetryCollector", + APIVersion: "v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "otel-my-instance", + Namespace: "somewhere", + }, + Spec: v1alpha1.OpenTelemetryCollectorSpec{ + Config: `--- +receivers: + jaeger: + protocols: + grpc: + remote_sampling: + endpoint: "jaeger-collector:14250" + tls: + insecure: true + strategy_file: "/etc/strategy.json" + strategy_file_reload_interval: 10s + jaeger/2: + protocols: + grpc: + remote_sampling: + endpoint: "jaeger-collector2:14250" + tls: + insecure: true + strategy_file: "/etc/strategy2.json" + strategy_file_reload_interval: 15s +service: + pipelines: + traces: + receivers: [jaeger, jaeger/2] + exporters: [nop] +`, + }, + } + + collectorInstance.Status.Version = "0.60.0" + //Test to remove port and change endpoint value. + versionUpgrade := &upgrade.VersionUpgrade{ + Log: logger, + Version: version.Get(), + Client: k8sClient, + Recorder: record.NewFakeRecorder(upgrade.RecordBufferSize), + } + + upgradedInstance, err := versionUpgrade.ManagedInstance(context.Background(), collectorInstance) + assert.NoError(t, err) + assert.Equal(t, `--- +extensions: + jaegerremotesampling: + source: + remote: + endpoint: jaeger-collector:14250 + tls: + insecure: true + reload_interval: 10s + file: /etc/strategy.json + jaegerremotesampling: + source: + remote: + endpoint: jaeger-collector2:14250 + tls: + insecure: true + reload_interval: 15s + file: /etc/strategy2.json +receivers: + jaeger/abc: + protocols: + grpc: + +service: + extensions: [jaegerremotesampling, jaegerremotesampling/2] + pipelines: + traces: + receivers: [jaeger, jaeger/2] + exporters: [nop] +`, upgradedInstance.Spec.Config) +} diff --git a/pkg/collector/upgrade/versions.go b/pkg/collector/upgrade/versions.go index a311cf2ee1..ae0870f044 100644 --- a/pkg/collector/upgrade/versions.go +++ b/pkg/collector/upgrade/versions.go @@ -81,6 +81,10 @@ var ( Version: *semver.MustParse("0.57.2"), upgrade: upgrade0_57_2, }, + { + Version: *semver.MustParse("0.61.0"), + upgrade: upgrade0_61_0, + }, } // Latest represents the latest version that we need to upgrade. This is not necessarily the latest known version.