Skip to content

Cherry pick bugfixes to the 1.9 branch #3896

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

Merged
merged 5 commits into from
Jun 25, 2025
Merged
Show file tree
Hide file tree
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ v1.9.2

- Send profiles concurrently from `pyroscope.ebpf`. (@korniltsev)

- Fix the `validate` command not understanding the `livedebugging` block. (@dehaansa)

- Fix invalid class names in python profiles obtained with `pyroscope.ebpf`. (@korniltsev)

- Fixed a bug which prevented non-secret optional secrets to be passed in as `number` arguments. (@ptodev)

- For CRD-based components (`prometheus.operator.*`), retry initializing informers if the apiserver request fails. This rectifies issues where the apiserver is not reachable immediately after node restart. (@dehaansa)

v1.9.1
-----------------
Expand Down
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.24.3

require (
cloud.google.com/go/pubsub v1.45.3
connectrpc.com/connect v1.16.2
connectrpc.com/connect v1.18.1
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0
github.com/Azure/go-autorest/autorest v0.11.29
Expand Down Expand Up @@ -52,7 +52,7 @@ require (
github.com/google/cadvisor v0.47.0
github.com/google/dnsmasq_exporter v0.2.1-0.20230620100026-44b14480804a
github.com/google/go-cmp v0.7.0
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad
github.com/google/renameio/v2 v2.0.0
github.com/google/uuid v1.6.0
github.com/gorilla/mux v1.8.1
Expand All @@ -71,7 +71,7 @@ require (
github.com/grafana/loki/v3 v3.0.0-20250218135905-f078e0e3f9b6 // k217-alloy-v1.7-fork branch
github.com/grafana/pyroscope-go/godeltaprof v0.1.8
github.com/grafana/pyroscope/api v1.2.0
github.com/grafana/pyroscope/ebpf v0.4.9
github.com/grafana/pyroscope/ebpf v0.4.10
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc
github.com/grafana/snowflake-prometheus-exporter v0.0.0-20250507154309-83bcbaac6b04
github.com/grafana/tail v0.0.0-20230510142333-77b18831edf0
Expand Down Expand Up @@ -187,7 +187,7 @@ require (
github.com/prometheus/mysqld_exporter v0.17.2
github.com/prometheus/node_exporter v1.6.0
github.com/prometheus/procfs v0.16.1
github.com/prometheus/prometheus v0.300.1 // replaced by a fork of v2.54.1 further down this file
github.com/prometheus/prometheus v0.302.1 // replaced by a fork of v2.54.1 further down this file
github.com/prometheus/snmp_exporter v0.29.0 // if you update the snmp_exporter version, make sure to update the SNMP_VERSION in _index
github.com/prometheus/statsd_exporter v0.28.0
github.com/richardartoul/molecule v1.0.1-0.20240531184615-7ca0df43c0b3
Expand Down
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ cloud.google.com/go/trace v1.11.3 h1:c+I4YFjxRQjvAhRmSsmjpASUKq88chOX854ied0K/pE
cloud.google.com/go/trace v1.11.3/go.mod h1:pt7zCYiDSQjC9Y2oqCsh9jF4GStB/hmjrYLsxRR27q8=
code.cloudfoundry.org/clock v1.0.0/go.mod h1:QD9Lzhd/ux6eNQVUDVRJX/RKTigpewimNYBi7ivZKY8=
collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=
connectrpc.com/connect v1.16.2 h1:ybd6y+ls7GOlb7Bh5C8+ghA6SvCBajHwxssO2CGFjqE=
connectrpc.com/connect v1.16.2/go.mod h1:n2kgwskMHXC+lVqb18wngEpF95ldBHXjZYJussz5FRc=
connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw=
connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8=
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
Expand Down Expand Up @@ -1318,8 +1318,8 @@ github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
Expand Down Expand Up @@ -1423,8 +1423,8 @@ github.com/grafana/pyroscope-go/godeltaprof v0.1.8 h1:iwOtYXeeVSAeYefJNaxDytgjKt
github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU=
github.com/grafana/pyroscope/api v1.2.0 h1:SfHDZcEZ4Vbj/Jj3bTOSpm4IDB33wLA2xBYxROhiL4U=
github.com/grafana/pyroscope/api v1.2.0/go.mod h1:CCWrMnwvTB5O+VBZfT+jO2RAvgm0GxdG2//kAWuMDhA=
github.com/grafana/pyroscope/ebpf v0.4.9 h1:sClXWakmkfFzvSzuxt/Fr6xb22C4oiKfdcCFzvAeRd0=
github.com/grafana/pyroscope/ebpf v0.4.9/go.mod h1:e5QegCu0a5BJ1bvZS+0WNkUouS8wVYLkD/5FWTV30eY=
github.com/grafana/pyroscope/ebpf v0.4.10 h1:EnO8mcZ1uiYdi5HR8kiG0gQYFHLP5nIHQ03sNT6cquw=
github.com/grafana/pyroscope/ebpf v0.4.10/go.mod h1:QxUq39zUwWG2MSzmReS81U3Jynf6mYy2nRJpsfvCc9A=
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248=
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk=
github.com/grafana/smimesign v0.2.1-0.20220408144937-2a5adf3481d3 h1:UPkAxuhlAcRmJT3/qd34OMTl+ZU7BLLfOO2+NXBlJpY=
Expand Down
2 changes: 2 additions & 0 deletions internal/alloycli/cmd_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/grafana/alloy/internal/service/cluster"
"github.com/grafana/alloy/internal/service/http"
"github.com/grafana/alloy/internal/service/labelstore"
"github.com/grafana/alloy/internal/service/livedebugging"
"github.com/grafana/alloy/internal/service/otel"
"github.com/grafana/alloy/internal/service/remotecfg"
"github.com/grafana/alloy/internal/service/ui"
Expand Down Expand Up @@ -70,6 +71,7 @@ func (v *alloyValidate) Run(configFile string) error {
&cluster.Service{},
&http.Service{},
&labelstore.Service{},
&livedebugging.Service{},
&otel.Service{},
&remotecfg.Service{},
&ui.Service{},
Expand Down
50 changes: 41 additions & 9 deletions internal/component/prometheus/operator/common/crdmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/go-kit/log"
"github.com/grafana/ckit/shard"
"github.com/grafana/dskit/backoff"
promopv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
promopv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
"github.com/prometheus/common/model"
Expand Down Expand Up @@ -162,7 +163,7 @@ func (c *crdManager) Run(ctx context.Context) error {
if err := c.runInformers(restConfig, ctx); err != nil {
return err
}
level.Info(c.logger).Log("msg", "informers started")
level.Info(c.logger).Log("msg", "informers started")

var cachedTargets map[string][]*targetgroup.Group
// Start the target discovery loop to update the scrape manager with new targets.
Expand Down Expand Up @@ -323,6 +324,23 @@ func (c *crdManager) runInformers(restConfig *rest.Config, ctx context.Context)
return nil
}

func getInformer(ctx context.Context, informers cache.Informers, prototype client.Object, timeout time.Duration) (cache.Informer, error) {
informerCtx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()

informer, err := informers.GetInformer(informerCtx, prototype)
if err != nil {
if errors.Is(informerCtx.Err(), context.DeadlineExceeded) { // Check the context to prevent GetInformer returning a fake timeout
return nil, fmt.Errorf("timeout exceeded while configuring informers. Check the connection"+
" to the Kubernetes API is stable and that Alloy has appropriate RBAC permissions for %T", prototype)
}

return nil, err
}

return informer, err
}

// configureInformers configures the informers for the CRDManager to watch for crd changes.
func (c *crdManager) configureInformers(ctx context.Context, informers cache.Informers) error {
var prototype client.Object
Expand All @@ -339,18 +357,32 @@ func (c *crdManager) configureInformers(ctx context.Context, informers cache.Inf
return fmt.Errorf("unknown kind to configure Informers: %s", c.kind)
}

informerCtx, cancel := context.WithTimeout(ctx, c.args.InformerSyncTimeout)
defer cancel()
// On node restart, the API server is not always immediately available.
// Retry with backoff to give time for the network to initialize.
var informer cache.Informer
var err error

informer, err := informers.GetInformer(informerCtx, prototype)
if err != nil {
if errors.Is(informerCtx.Err(), context.DeadlineExceeded) { // Check the context to prevent GetInformer returning a fake timeout
return fmt.Errorf("timeout exceeded while configuring informers. Check the connection"+
" to the Kubernetes API is stable and that Alloy has appropriate RBAC permissions for %v", prototype)
backoff := backoff.New(
ctx,
backoff.Config{
MinBackoff: 1 * time.Second,
MaxBackoff: 10 * time.Second,
MaxRetries: 3, // retry up to 3 times
},
)
for backoff.Ongoing() {
// Retry to get the informer in case of a timeout.
informer, err = getInformer(ctx, informers, prototype, c.args.InformerSyncTimeout)
if err == nil {
break
}

level.Warn(c.logger).Log("msg", "failed to get informer, retrying", "next backoff", backoff.NextDelay(), "err", err)
backoff.Wait()
}
if err != nil {
return err
}

const resync = 5 * time.Minute
switch c.kind {
case KindPodMonitor:
Expand Down
4 changes: 4 additions & 0 deletions internal/validator/testdata/default/valid.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ logging {
format = "logfmt"
}

livedebugging {
enabled = true
}

tracing {
sampling_fraction = 0.1

Expand Down
2 changes: 2 additions & 0 deletions internal/validator/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/grafana/alloy/internal/service/cluster"
"github.com/grafana/alloy/internal/service/http"
"github.com/grafana/alloy/internal/service/labelstore"
"github.com/grafana/alloy/internal/service/livedebugging"
"github.com/grafana/alloy/internal/service/otel"
"github.com/grafana/alloy/internal/service/remotecfg"
"github.com/grafana/alloy/internal/service/ui"
Expand Down Expand Up @@ -64,6 +65,7 @@ func testDirectory(t *testing.T, dir string, minStability featuregate.Stability,
&cluster.Service{},
&http.Service{},
&labelstore.Service{},
&livedebugging.Service{},
&otel.Service{},
&remotecfg.Service{},
&ui.Service{},
Expand Down
12 changes: 12 additions & 0 deletions syntax/internal/value/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,18 @@ func convertValue(val Value, toType Type) (Value, error) {
return Uint(parsed), nil
}
}

case TypeCapsule:
// Some capsules, such as optional secrects, may be convertible to a string.
// Try to convert them to a string and then rerun convertValue.
into := reflect.New(reflect.TypeOf(string(""))).Elem()
ok, err := tryCapsuleConvert(val, into, TypeString)
if ok && err == nil {
val, err := convertValue(Value{into, TypeString}, toType)
if err == nil {
return val, nil
}
}
}

return Null, TypeError{Value: val, Expected: toType}
Expand Down
11 changes: 10 additions & 1 deletion syntax/vm/vm_stdlib_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,11 @@ func TestVM_Stdlib_Errors(t *testing.T) {
func TestStdlibCoalesce(t *testing.T) {
t.Setenv("TEST_VAR2", "Hello!")

scope := vm.NewScope(map[string]any{
"optionalSecretStr": alloytypes.OptionalSecret{Value: "bar"},
"optionalSecretInt": alloytypes.OptionalSecret{Value: "123", IsSecret: false},
})

tt := []struct {
name string
input string
Expand All @@ -221,6 +226,10 @@ func TestStdlibCoalesce(t *testing.T) {
{"coalesce(object, true) and return true", `coalesce(encoding.from_json("{}"), true)`, true},
{"coalesce(object, false) and return false", `coalesce(encoding.from_json("{}"), false)`, false},
{"coalesce(list, nil)", `coalesce([],null)`, value.Null},
{"optional secret str first in coalesce", `coalesce(optionalSecretStr, 1)`, string("bar")},
{"optional secret str second in coalesce", `coalesce("foo", optionalSecretStr)`, string("foo")},
{"optional secret int first in coalesce", `coalesce(optionalSecretInt, 1)`, int(123)},
{"optional secret int second in coalesce", `coalesce(1, optionalSecretInt)`, int(1)},
}

for _, tc := range tt {
Expand All @@ -231,7 +240,7 @@ func TestStdlibCoalesce(t *testing.T) {
eval := vm.New(expr)

rv := reflect.New(reflect.TypeOf(tc.expect))
require.NoError(t, eval.Evaluate(nil, rv.Interface()))
require.NoError(t, eval.Evaluate(scope, rv.Interface()))
require.Equal(t, tc.expect, rv.Elem().Interface())
})
}
Expand Down
44 changes: 44 additions & 0 deletions syntax/vm/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"testing"
"unicode"

"github.com/grafana/alloy/syntax/alloytypes"
"github.com/grafana/alloy/syntax/parser"
"github.com/grafana/alloy/syntax/scanner"
"github.com/grafana/alloy/syntax/token"
Expand Down Expand Up @@ -61,6 +62,49 @@ func TestVM_Evaluate_Literals(t *testing.T) {
}
}

func TestVM_Evaluate_Secrets(t *testing.T) {
scope := vm.NewScope(map[string]any{
"secretSecret": alloytypes.Secret("foo"),
"optionalSecretStr": alloytypes.OptionalSecret{Value: "bar"},
"optionalSecretInt": alloytypes.OptionalSecret{Value: "123", IsSecret: false},
"optionalSecretNegative": alloytypes.OptionalSecret{Value: "-123", IsSecret: false},
"optionalSecretFloat": alloytypes.OptionalSecret{Value: "23.5", IsSecret: false},
})

tt := map[string]struct {
input string
expect interface{}
errMsg string
}{
"secret": {`secretSecret`, string("bar"), "secrets may not be converted into strings"},
"optional secret str": {`optionalSecretStr`, string("bar"), ""},
"optional secret int": {`optionalSecretInt`, int(123), ""},
"optional secret negative int": {`optionalSecretNegative`, int(-123), ""},
"optional secret float": {`optionalSecretFloat`, float64(23.5), ""},
}

for name, tc := range tt {
t.Run(name, func(t *testing.T) {
expr, err := parser.ParseExpression(tc.input)
require.NoError(t, err)

eval := vm.New(expr)

vPtr := reflect.New(reflect.TypeOf(tc.expect)).Interface()

err = eval.Evaluate(scope, vPtr)
if tc.errMsg == "" {
require.NoError(t, err)

actual := reflect.ValueOf(vPtr).Elem().Interface()
require.Equal(t, tc.expect, actual)
} else {
require.ErrorContains(t, err, tc.errMsg)
}
})
}
}

func TestVM_Evaluate(t *testing.T) {
// Shared scope across all tests below
scope := vm.NewScope(map[string]interface{}{
Expand Down