pkg/instrumentation/upgrade/upgrade.go (113 lines of code) (raw):

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package upgrade import ( "context" "fmt" "reflect" "github.com/go-logr/logr" featuregate2 "go.opentelemetry.io/collector/featuregate" "k8s.io/client-go/tools/record" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/aws/amazon-cloudwatch-agent-operator/apis/v1alpha1" "github.com/aws/amazon-cloudwatch-agent-operator/pkg/constants" "github.com/aws/amazon-cloudwatch-agent-operator/pkg/featuregate" ) var ( defaultAnnotationToGate = map[string]*featuregate2.Gate{ constants.AnnotationDefaultAutoInstrumentationJava: featuregate.EnableJavaAutoInstrumentationSupport, constants.AnnotationDefaultAutoInstrumentationNodeJS: featuregate.EnableNodeJSAutoInstrumentationSupport, constants.AnnotationDefaultAutoInstrumentationPython: featuregate.EnablePythonAutoInstrumentationSupport, constants.AnnotationDefaultAutoInstrumentationDotNet: featuregate.EnableDotnetAutoInstrumentationSupport, constants.AnnotationDefaultAutoInstrumentationGo: featuregate.EnableGoAutoInstrumentationSupport, constants.AnnotationDefaultAutoInstrumentationApacheHttpd: featuregate.EnableApacheHTTPAutoInstrumentationSupport, constants.AnnotationDefaultAutoInstrumentationNginx: featuregate.EnableNginxAutoInstrumentationSupport, } ) type InstrumentationUpgrade struct { Client client.Client Logger logr.Logger Recorder record.EventRecorder DefaultAutoInstJava string DefaultAutoInstNodeJS string DefaultAutoInstPython string DefaultAutoInstDotNet string DefaultAutoInstApacheHttpd string DefaultAutoInstNginx string DefaultAutoInstGo string } // +kubebuilder:rbac:groups=cloudwatch.aws.amazon.com,resources=instrumentations,verbs=get;list;watch;update;patch // ManagedInstances upgrades managed instances by the amazon-cloudwatch-agent-operator. func (u *InstrumentationUpgrade) ManagedInstances(ctx context.Context) error { u.Logger.Info("looking for managed Instrumentation instances to upgrade") opts := []client.ListOption{ client.MatchingLabels(map[string]string{ "app.kubernetes.io/managed-by": "amazon-cloudwatch-agent-operator", }), } list := &v1alpha1.InstrumentationList{} if err := u.Client.List(ctx, list, opts...); err != nil { return fmt.Errorf("failed to list: %w", err) } for i := range list.Items { toUpgrade := list.Items[i] upgraded := u.upgrade(ctx, toUpgrade) if !reflect.DeepEqual(upgraded, toUpgrade) { // use update instead of patch because the patch does not upgrade annotations if err := u.Client.Update(ctx, upgraded); err != nil { u.Logger.Error(err, "failed to apply changes to instance", "name", upgraded.Name, "namespace", upgraded.Namespace) continue } } } if len(list.Items) == 0 { u.Logger.Info("no instances to upgrade") } return nil } func (u *InstrumentationUpgrade) upgrade(_ context.Context, inst v1alpha1.Instrumentation) *v1alpha1.Instrumentation { upgraded := inst.DeepCopy() for annotation, gate := range defaultAnnotationToGate { autoInst := upgraded.Annotations[annotation] if autoInst != "" { if gate.IsEnabled() { switch annotation { case constants.AnnotationDefaultAutoInstrumentationJava: if inst.Spec.Java.Image == autoInst { upgraded.Spec.Java.Image = u.DefaultAutoInstJava upgraded.Annotations[annotation] = u.DefaultAutoInstJava } case constants.AnnotationDefaultAutoInstrumentationNodeJS: if inst.Spec.NodeJS.Image == autoInst { upgraded.Spec.NodeJS.Image = u.DefaultAutoInstNodeJS upgraded.Annotations[annotation] = u.DefaultAutoInstNodeJS } case constants.AnnotationDefaultAutoInstrumentationPython: if inst.Spec.Python.Image == autoInst { upgraded.Spec.Python.Image = u.DefaultAutoInstPython upgraded.Annotations[annotation] = u.DefaultAutoInstPython } case constants.AnnotationDefaultAutoInstrumentationDotNet: if inst.Spec.DotNet.Image == autoInst { upgraded.Spec.DotNet.Image = u.DefaultAutoInstDotNet upgraded.Annotations[annotation] = u.DefaultAutoInstDotNet } case constants.AnnotationDefaultAutoInstrumentationGo: if inst.Spec.Go.Image == autoInst { upgraded.Spec.Go.Image = u.DefaultAutoInstGo upgraded.Annotations[annotation] = u.DefaultAutoInstGo } case constants.AnnotationDefaultAutoInstrumentationApacheHttpd: if inst.Spec.ApacheHttpd.Image == autoInst { upgraded.Spec.ApacheHttpd.Image = u.DefaultAutoInstApacheHttpd upgraded.Annotations[annotation] = u.DefaultAutoInstApacheHttpd } case constants.AnnotationDefaultAutoInstrumentationNginx: if inst.Spec.Nginx.Image == autoInst { upgraded.Spec.Nginx.Image = u.DefaultAutoInstNginx upgraded.Annotations[annotation] = u.DefaultAutoInstNginx } } } else { u.Logger.Error(nil, "autoinstrumentation not enabled for this language", "flag", gate.ID()) u.Recorder.Event(upgraded, "Warning", "InstrumentationUpgradeRejected", fmt.Sprintf("support for is not enabled for %s", gate.ID())) } } } return upgraded }