Skip to content

Commit

Permalink
Add upgrade for Instrumentation kind (open-telemetry#548)
Browse files Browse the repository at this point in the history
* Add upgrade procedure for Instrumentation

Signed-off-by: Pavol Loffay <[email protected]>

* Fix

Signed-off-by: Pavol Loffay <[email protected]>

* Fix

Signed-off-by: Pavol Loffay <[email protected]>
  • Loading branch information
pavolloffay authored and hero committed Dec 12, 2021
1 parent 3deab6a commit 61d9d7b
Show file tree
Hide file tree
Showing 7 changed files with 241 additions and 3 deletions.
2 changes: 1 addition & 1 deletion apis/v1alpha1/instrumentation_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (
)

const (
AnnotationDefaultAutoInstrumentationJava = "opentelemetry.io/default-auto-instrumentation-java-image"
AnnotationDefaultAutoInstrumentationJava = "instrumentation.opentelemetry.io/default-auto-instrumentation-java-image"
)

// log is for logging in this package.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ spec:
verbs:
- get
- list
- patch
- update
- watch
- apiGroups:
- opentelemetry.io
Expand Down
2 changes: 2 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ rules:
verbs:
- get
- list
- patch
- update
- watch
- apiGroups:
- opentelemetry.io
Expand Down
17 changes: 15 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ import (
"github.com/open-telemetry/opentelemetry-operator/internal/version"
"github.com/open-telemetry/opentelemetry-operator/internal/webhookhandler"
"github.com/open-telemetry/opentelemetry-operator/pkg/autodetect"
"github.com/open-telemetry/opentelemetry-operator/pkg/collector/upgrade"
collectorupgrade "github.com/open-telemetry/opentelemetry-operator/pkg/collector/upgrade"
"github.com/open-telemetry/opentelemetry-operator/pkg/instrumentation"
instrumentationupgrade "github.com/open-telemetry/opentelemetry-operator/pkg/instrumentation/upgrade"
"github.com/open-telemetry/opentelemetry-operator/pkg/sidecar"
// +kubebuilder:scaffold:imports
)
Expand Down Expand Up @@ -152,7 +153,19 @@ func main() {

// adds the upgrade mechanism to be executed once the manager is ready
err = mgr.Add(manager.RunnableFunc(func(c context.Context) error {
return upgrade.ManagedInstances(c, ctrl.Log.WithName("upgrade"), v, mgr.GetClient())
return collectorupgrade.ManagedInstances(c, ctrl.Log.WithName("collector-upgrade"), v, mgr.GetClient())
}))
if err != nil {
setupLog.Error(err, "failed to upgrade managed instances")
}
// adds the upgrade mechanism to be executed once the manager is ready
err = mgr.Add(manager.RunnableFunc(func(c context.Context) error {
u := &instrumentationupgrade.InstrumentationUpgrade{
Logger: ctrl.Log.WithName("instrumentation-upgrade"),
DefaultAutoInstrJava: autoInstrumentationJava,
Client: mgr.GetClient(),
}
return u.ManagedInstances(c)
}))
if err != nil {
setupLog.Error(err, "failed to upgrade managed instances")
Expand Down
78 changes: 78 additions & 0 deletions pkg/instrumentation/upgrade/upgrade.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// 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 (
"context"
"fmt"
"reflect"

"github.com/go-logr/logr"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1"
)

type InstrumentationUpgrade struct {
Logger logr.Logger
DefaultAutoInstrJava string
Client client.Client
}

//+kubebuilder:rbac:groups=opentelemetry.io,resources=instrumentations,verbs=get;list;watch;update;patch

// ManagedInstances upgrades managed instances by the opentelemetry-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": "opentelemetry-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 {
autoInstJava := inst.Annotations[v1alpha1.AnnotationDefaultAutoInstrumentationJava]
if autoInstJava != "" {
// upgrade the image only if the image matches the annotation
if inst.Spec.Java.Image == autoInstJava {
inst.Spec.Java.Image = u.DefaultAutoInstrJava
inst.Annotations[v1alpha1.AnnotationDefaultAutoInstrumentationJava] = u.DefaultAutoInstrJava
}
}
return inst
}
67 changes: 67 additions & 0 deletions pkg/instrumentation/upgrade/upgrade_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// 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"
"os"
"path/filepath"
"testing"

"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"

"github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1"
)

var k8sClient client.Client
var testEnv *envtest.Environment
var testScheme = scheme.Scheme

func TestMain(m *testing.M) {
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{
filepath.Join("..", "..", "..", "config", "crd", "bases"),
},
}

cfg, err := testEnv.Start()
if err != nil {
fmt.Printf("failed to start testEnv: %v", err)
os.Exit(1)
}

if err := v1alpha1.AddToScheme(testScheme); err != nil {
fmt.Printf("failed to register scheme: %v", err)
os.Exit(1)
}

k8sClient, err = client.New(cfg, client.Options{Scheme: testScheme})
if err != nil {
fmt.Printf("failed to setup a Kubernetes client: %v", err)
os.Exit(1)
}

code := m.Run()

err = testEnv.Stop()
if err != nil {
fmt.Printf("failed to stop testEnv: %v", err)
os.Exit(1)
}

os.Exit(code)
}
76 changes: 76 additions & 0 deletions pkg/instrumentation/upgrade/upgrade_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// 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 (
"context"
"strings"
"testing"

"github.com/go-logr/logr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"

"github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1"
)

func TestUpgrade(t *testing.T) {
nsName := strings.ToLower(t.Name())
err := k8sClient.Create(context.Background(), &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: nsName,
},
})
require.NoError(t, err)

inst := &v1alpha1.Instrumentation{
ObjectMeta: metav1.ObjectMeta{
Name: "my-inst",
Namespace: nsName,
Annotations: map[string]string{
v1alpha1.AnnotationDefaultAutoInstrumentationJava: "java:1",
},
},
Spec: v1alpha1.InstrumentationSpec{
Sampler: v1alpha1.Sampler{
Type: v1alpha1.ParentBasedAlwaysOff,
},
},
}
inst.Default()
assert.Equal(t, "java:1", inst.Spec.Java.Image)
err = k8sClient.Create(context.Background(), inst)
require.NoError(t, err)

up := &InstrumentationUpgrade{
Logger: logr.Discard(),
DefaultAutoInstrJava: "java:2",
Client: k8sClient,
}
err = up.ManagedInstances(context.Background())
require.NoError(t, err)

updated := v1alpha1.Instrumentation{}
err = k8sClient.Get(context.Background(), types.NamespacedName{
Namespace: nsName,
Name: "my-inst",
}, &updated)
require.NoError(t, err)
assert.Equal(t, "java:2", updated.Annotations[v1alpha1.AnnotationDefaultAutoInstrumentationJava])
assert.Equal(t, "java:2", updated.Spec.Java.Image)
}

0 comments on commit 61d9d7b

Please sign in to comment.