Skip to content

Commit d47bd87

Browse files
authored
Upgrade to Dotnet 1.15.0 by default (#5007)
* Upgrade to Dotnet 1.15.0 by default * Fix e2e tests
1 parent a22e88d commit d47bd87

11 files changed

Lines changed: 186 additions & 10 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
2+
change_type: breaking
3+
4+
# The name of the component, or a single word describing the area of concern, (e.g. collector, target allocator, auto-instrumentation, opamp, github action)
5+
component: auto-instrumentation
6+
7+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
8+
note: Update default .NET auto-instrumentation version from 1.2.0 to 1.15.0
9+
10+
# One or more tracking issues related to the change
11+
issues: [4996]
12+
13+
# (Optional) One or more lines of additional information to render under the primary note.
14+
# These lines will be padded with 2 spaces and then inserted directly into the document.
15+
# Use pipe (|) for multiline entries.
16+
subtext: |
17+
This update addresses security vulnerabilities in versions older than 1.15.0 (CVE-2026-40894, GHSA-g94r-2vxg-569j).
18+
This is a breaking change due to HTTP semantic convention changes between versions.
19+
Existing Instrumentation CRs using version 1.2.0 will NOT be automatically upgraded.
20+
To upgrade, manually update the image in your Instrumentation CR after reviewing the migration guide.
21+
See https://github.com/open-telemetry/opentelemetry-operator/issues/2542 for details.

internal/instrumentation/upgrade/upgrade_test.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ import (
2525
)
2626

2727
func TestUpgrade(t *testing.T) {
28+
cleanup := version.SetUnupgradableInstrumentationVersionsForTests(map[constants.InstrumentationLanguage]map[string]string{})
29+
defer cleanup()
30+
2831
nsName := strings.ToLower(t.Name())
2932
err := k8sClient.Create(context.Background(), &corev1.Namespace{
3033
ObjectMeta: metav1.ObjectMeta{
@@ -121,10 +124,11 @@ func TestUpgrade(t *testing.T) {
121124
}
122125

123126
func TestUpgradeBlockedForUnupgradableVersion(t *testing.T) {
124-
// Set up unupgradable version for testing
127+
// Set up unupgradable version for testing. The blocked version "2" sits in
128+
// (current, target] when going from "1" to "2", so the upgrade should be blocked.
125129
cleanup := version.SetUnupgradableInstrumentationVersionsForTests(map[constants.InstrumentationLanguage]map[string]string{
126130
constants.InstrumentationLanguageJava: {
127-
"1": "Breaking changes in Java agent require manual migration.",
131+
"2": "Breaking changes in Java agent require manual migration.",
128132
},
129133
})
130134
defer cleanup()
@@ -222,10 +226,10 @@ func TestUpgradeBlockedForUnupgradableVersion(t *testing.T) {
222226
// TestUpgradeClearsStaleBlockedStatus verifies that a previously-blocked instrumentation has its
223227
// status.upgradeBlockedVersions cleared once the blocking condition no longer applies.
224228
func TestUpgradeClearsStaleBlockedStatus(t *testing.T) {
225-
// Initially block "java:1" so the first reconcile populates status.
229+
// Block "2" so the first reconcile (java:1 -> java:2) hits the blocking range and populates status.
226230
cleanup := version.SetUnupgradableInstrumentationVersionsForTests(map[constants.InstrumentationLanguage]map[string]string{
227231
constants.InstrumentationLanguageJava: {
228-
"1": "Breaking changes in Java agent require manual migration.",
232+
"2": "Breaking changes in Java agent require manual migration.",
229233
},
230234
})
231235

internal/version/unupgradable.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,21 @@ import (
1111
"github.com/open-telemetry/opentelemetry-operator/pkg/constants"
1212
)
1313

14+
// Kubernetes admission warnings are transmitted in HTTP headers and MUST NOT contain control
15+
// characters like newlines, so these messages are kept on a single line.
16+
const (
17+
dotNet130WarningMessage = ".NET instrumentation 1.3.0 contains breaking HTTP semantic convention changes. " +
18+
"See https://opentelemetry.io/blog/2023/http-conventions-declared-stable/ for a general description of the changes. " +
19+
"To upgrade, manually set the image on this Instrumentation resource to 1.3.0 or higher."
20+
)
21+
1422
// unupgradableInstrumentationVersions contains instrumentation versions that cannot be automatically upgraded from.
1523
// Outer key is the language, inner key is the version tag, value is the warning message.
16-
var unupgradableInstrumentationVersions = map[constants.InstrumentationLanguage]map[string]string{}
24+
var unupgradableInstrumentationVersions = map[constants.InstrumentationLanguage]map[string]string{
25+
constants.InstrumentationLanguageDotNet: {
26+
"1.3.0": dotNet130WarningMessage,
27+
},
28+
}
1729

1830
// IsInstrumentationVersionUnupgradable checks if an instrumentation image upgrade should be blocked.
1931
// It first verifies the image is from the same repository as defaultImage — images from other repositories are never blocked.
@@ -59,8 +71,8 @@ func IsInstrumentationVersionUnupgradable(language constants.InstrumentationLang
5971
}
6072
continue
6173
}
62-
// Block if the blocked version is in range [current, target)
63-
if !blockedVer.LessThan(currentVer) && blockedVer.LessThan(targetVer) {
74+
// Block if the blocked version is in range (current, target]
75+
if blockedVer.GreaterThan(currentVer) && blockedVer.LessThanEqual(targetVer) {
6476
return true, msg
6577
}
6678
}

internal/version/unupgradable_test.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,25 @@ func TestIsInstrumentationVersionUnupgradable(t *testing.T) {
6060
defaultImage: "ghcr.io/org/java:v2.0.0",
6161
unupgradableMap: map[constants.InstrumentationLanguage]map[string]string{
6262
constants.InstrumentationLanguageJava: {
63-
"v1.0.0": "Breaking changes in Java agent.",
63+
"v2.0.0": "Breaking changes in Java agent.",
6464
},
6565
},
6666
wantBlocked: true,
6767
wantMessage: "Breaking changes in Java agent.",
6868
},
69+
{
70+
name: "unupgradable version without v prefix returns true with message",
71+
language: constants.InstrumentationLanguageDotNet,
72+
image: "ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-dotnet:1.2.0",
73+
defaultImage: "ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-dotnet:1.15.0",
74+
unupgradableMap: map[constants.InstrumentationLanguage]map[string]string{
75+
constants.InstrumentationLanguageDotNet: {
76+
"1.3.0": "Breaking changes in dotNet agent.",
77+
},
78+
},
79+
wantBlocked: true,
80+
wantMessage: "Breaking changes in dotNet agent.",
81+
},
6982
{
7083
name: "different repo skips check",
7184
language: constants.InstrumentationLanguageJava,
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
apiVersion: opentelemetry.io/v1alpha1
2+
kind: Instrumentation
3+
metadata:
4+
name: blocked-upgrade-test
5+
spec:
6+
dotnet:
7+
image: "ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-dotnet:1.2.0"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
apiVersion: opentelemetry.io/v1alpha1
2+
kind: Instrumentation
3+
metadata:
4+
name: blocked-upgrade-test
5+
spec:
6+
exporter:
7+
endpoint: http://localhost:4317
8+
sampler:
9+
type: always_on
10+
dotnet:
11+
image: "ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-dotnet:1.2.0"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
apiVersion: opentelemetry.io/v1alpha1
2+
kind: Instrumentation
3+
metadata:
4+
name: upgrade-test
5+
spec:
6+
dotnet:
7+
image: "ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-dotnet:1.2.0"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
apiVersion: opentelemetry.io/v1alpha1
2+
kind: Instrumentation
3+
metadata:
4+
name: upgrade-test
5+
spec:
6+
exporter:
7+
endpoint: http://localhost:4317
8+
sampler:
9+
type: always_on
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
apiVersion: opentelemetry.io/v1alpha1
2+
kind: Instrumentation
3+
metadata:
4+
name: upgrade-test
5+
spec:
6+
dotnet:
7+
image: "ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-dotnet:1.2.0"
8+
status:
9+
upgradeBlockedVersions:
10+
dotnet: "Automated upgrade blocked for dotnet: .NET instrumentation 1.3.0 contains breaking HTTP semantic convention changes. See https://opentelemetry.io/blog/2023/http-conventions-declared-stable/ for a general description of the changes. To upgrade, manually set the image on this Instrumentation resource to 1.3.0 or higher."
11+
---
12+
apiVersion: events.k8s.io/v1
13+
kind: Event
14+
note: "Automated upgrade blocked for dotnet: .NET instrumentation 1.3.0 contains breaking HTTP semantic convention changes. See https://opentelemetry.io/blog/2023/http-conventions-declared-stable/ for a general description of the changes. To upgrade, manually set the image on this Instrumentation resource to 1.3.0 or higher."
15+
reason: "UpgradeBlocked"
16+
regarding:
17+
apiVersion: opentelemetry.io/v1alpha1
18+
kind: Instrumentation
19+
name: upgrade-test
20+
reportingController: opentelemetry-operator
21+
type: Warning
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json
2+
apiVersion: chainsaw.kyverno.io/v1alpha1
3+
kind: Test
4+
metadata:
5+
name: instrumentation-blocked-upgrade
6+
spec:
7+
# This test modifies the operator deployment to verify upgrade blocking behavior.
8+
steps:
9+
- name: Create instrumentation with blocked dotnet version and verify webhook warning
10+
try:
11+
- script:
12+
timeout: 30s
13+
content: |
14+
kubectl apply -n $NAMESPACE -f 00-install-instrumentation-blocked.yaml 2>&1
15+
check:
16+
(contains($stdout, 'cannot be automatically upgraded')): true
17+
- assert:
18+
file: 00-assert.yaml
19+
- name: Patch operator to use old dotnet version as default
20+
try:
21+
- script:
22+
timeout: 5m
23+
shell: /bin/bash
24+
content: |
25+
#!/bin/bash
26+
set -eo pipefail
27+
NS=opentelemetry-operator-system
28+
DEPLOY=opentelemetry-operator-controller-manager
29+
OLD_IMG="ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-dotnet:1.2.0"
30+
31+
# Add the dotnet image arg to override the compiled-in default
32+
ARGS=$(kubectl get deploy -n $NS $DEPLOY -o json | jq -c '.spec.template.spec.containers[0].args')
33+
NEW_ARGS=$(echo "$ARGS" | jq -c --arg img "$OLD_IMG" \
34+
'[.[] | select(startswith("--auto-instrumentation-dotnet-image=") | not)] + ["--auto-instrumentation-dotnet-image=" + $img]')
35+
36+
kubectl patch deploy -n $NS $DEPLOY --type='json' \
37+
-p="[{\"op\":\"replace\",\"path\":\"/spec/template/spec/containers/0/args\",\"value\":$NEW_ARGS}]"
38+
39+
kubectl rollout status deploy/$DEPLOY -n $NS --timeout=120s
40+
- name: Create instrumentation that will be subject to upgrade
41+
try:
42+
- apply:
43+
file: 01-install-instrumentation-upgrade-test.yaml
44+
- assert:
45+
file: 01-assert.yaml
46+
- name: Restore operator to default dotnet version and trigger upgrade
47+
try:
48+
- script:
49+
timeout: 5m
50+
shell: /bin/bash
51+
content: |
52+
#!/bin/bash
53+
set -eo pipefail
54+
NS=opentelemetry-operator-system
55+
DEPLOY=opentelemetry-operator-controller-manager
56+
57+
# Remove the override arg so the operator uses its compiled-in default (1.15.0)
58+
ARGS=$(kubectl get deploy -n $NS $DEPLOY -o json | jq -c '.spec.template.spec.containers[0].args')
59+
NEW_ARGS=$(echo "$ARGS" | jq -c '[.[] | select(startswith("--auto-instrumentation-dotnet-image=") | not)]')
60+
61+
kubectl patch deploy -n $NS $DEPLOY --type='json' \
62+
-p="[{\"op\":\"replace\",\"path\":\"/spec/template/spec/containers/0/args\",\"value\":$NEW_ARGS}]"
63+
64+
kubectl rollout status deploy/$DEPLOY -n $NS --timeout=120s
65+
# Give the upgrade mechanism time to process existing Instrumentation CRs
66+
sleep 5
67+
- name: Assert upgrade was blocked with status and event
68+
try:
69+
# DotNet image should still be 1.2.0 (not upgraded to 1.15.0)
70+
# and the status should reflect the blocked upgrade
71+
- assert:
72+
file: 02-assert.yaml

0 commit comments

Comments
 (0)