Skip to content

[confmap] Should not marshal functions/channels by default #8627

@jefchien

Description

@jefchien

Describe the bug
mapstructure will take any exported field and attempt to decode it. This includes non-tagged fields.

When decoding to a struct, mapstructure will use the field name by default to perform the mapping. For example, if a struct has a field "Username" then mapstructure will look for a key in the source value of "username" (case insensitive).

type User struct {
   Username string
}

https://pkg.go.dev/github.com/mitchellh/mapstructure

Similarly, the mapstructure encoder will also take any exported field and attempt to encode it into a form that go-yaml can use. The encoder does not handle function or channel types. Any exported function/channel which will use the default handler, which will fall back on leaving the field as is. go-yaml cannot handle the function/channel and panics.

One example of an exported function in the configuration is the confighttp.HTTPClientSettings, which exports the CustomRoundTripper function:

// Custom Round Tripper to allow for individual components to intercept HTTP requests
CustomRoundTripper func(next http.RoundTripper) (http.RoundTripper, error)

Steps to reproduce

func TestMarshal(t *testing.T) {
    settings := confighttp.NewDefaultHTTPClientSettings()
    conf := confmap.New()
    assert.NoError(t, conf.Marshal(settings))
    out, err := yaml.Marshal(conf.ToStringMap())
    assert.NoError(t, err)
    t.Log(string(out))
}

What did you expect to see?
That the function would be skipped. customroundtripper is not present in the output YAML.

        auth: null
        compression: ""
        disable_keep_alives: false
        endpoint: ""
        headers: {}
        idle_conn_timeout: 1m30s
        max_conns_per_host: null
        max_idle_conns: 100
        max_idle_conns_per_host: null
        read_buffer_size: 0
        timeout: 0s
        tls:
            ca_file: ""
            ca_pem: '[REDACTED]'
            cert_file: ""
            cert_pem: '[REDACTED]'
            insecure: false
            insecure_skip_verify: false
            key_file: ""
            key_pem: '[REDACTED]'
            max_version: ""
            min_version: ""
            reload_interval: 0s
            server_name_override: ""
        write_buffer_size: 0

What did you see instead?

panic: cannot marshal type: func(http.RoundTripper) (http.RoundTripper, error)

panic({0x1779440, 0xc0003ef630})
	/path/to/go/src/runtime/panic.go:884 +0x213
gopkg.in/yaml%2ev3.(*encoder).marshal(0x179b500?, {0x0, 0x0}, {0x17988c0?, 0x0?, 0x10?})
	/path/to/go/pkg/mod/gopkg.in/[email protected]/encode.go:182 +0xa4b
gopkg.in/yaml%2ev3.(*encoder).marshal(0x17b13e0?, {0x0, 0x0}, {0x179b500?, 0xc0003ef620?, 0x98?})
	/path/to/go/pkg/mod/gopkg.in/[email protected]/encode.go:162 +0x85b
gopkg.in/yaml%2ev3.(*encoder).mapv.func1()
	/path/to/go/pkg/mod/gopkg.in/[email protected]/encode.go:192 +0xf4
gopkg.in/yaml%2ev3.(*encoder).mappingv(0xc0003e4400, {0x0?, 0x0}, 0xc0001e1890)
	/path/to/go/pkg/mod/gopkg.in/[email protected]/encode.go:265 +0x146
gopkg.in/yaml%2ev3.(*encoder).mapv(0x17b13e0?, {0x0?, 0xc0003d6960?}, {0x17b13e0?, 0xc0003d6960?, 0x0?})
	/path/to/go/pkg/mod/gopkg.in/[email protected]/encode.go:187 +0x5f
gopkg.in/yaml%2ev3.(*encoder).marshal(0xc0003e4400?, {0x0, 0x0}, {0x17b13e0?, 0xc0003d6960?, 0xc0001e1a60?})
	/path/to/go/pkg/mod/gopkg.in/[email protected]/encode.go:164 +0x88b
gopkg.in/yaml%2ev3.(*encoder).marshalDoc(0xc0003e4400, {0x0, 0x0}, {0x17b13e0?, 0xc0003d6960?, 0x1021445?})
	/path/to/go/pkg/mod/gopkg.in/[email protected]/encode.go:105 +0x12b
gopkg.in/yaml%2ev3.Marshal({0x17b13e0?, 0xc0003d6960})
	/path/to/go/pkg/mod/gopkg.in/[email protected]/yaml.go:222 +0x389
go.opentelemetry.io/collector/config/confighttp.TestMarshal(0xc00019d520)

What version did you use?
Version: v0.86.0

What config did you use?
Config: N/A

Environment
OS: (e.g., "Ubuntu 20.04") macOS
Compiler(if manually compiled): Go 1.20.8

Additional context
Add any other context about the problem here.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions