diff --git a/.chloggen/confignet-add-dialertimeout.yaml b/.chloggen/confignet-add-dialertimeout.yaml new file mode 100755 index 00000000000..915be3fe66f --- /dev/null +++ b/.chloggen/confignet-add-dialertimeout.yaml @@ -0,0 +1,25 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver) +component: confignet + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add `dialer_timeout` config option. + +# One or more tracking issues or pull requests related to the change +issues: [9066] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] \ No newline at end of file diff --git a/config/confignet/README.md b/config/confignet/README.md index 579564cbff4..cd8150e6303 100644 --- a/config/confignet/README.md +++ b/config/confignet/README.md @@ -13,6 +13,7 @@ leverage network configuration to set connection and transport information. - `transport`: Known protocols are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only), "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4" (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and "unixpacket". +- `dialer_timeout`: DialerTimeout is the maximum amount of time a dial will wait for a connect to complete. The default is no timeout. Note that for TCP receivers only the `endpoint` configuration setting is required. diff --git a/config/confignet/confignet.go b/config/confignet/confignet.go index 6695b6035b8..d3adf14209d 100644 --- a/config/confignet/confignet.go +++ b/config/confignet/confignet.go @@ -5,8 +5,16 @@ package confignet // import "go.opentelemetry.io/collector/config/confignet" import ( "net" + "time" ) +// DialerConfig contains options for connecting to an address. +type DialerConfig struct { + // Timeout is the maximum amount of time a dial will wait for + // a connect to complete. The default is no timeout. + Timeout time.Duration `mapstructure:"timeout"` +} + // NetAddr represents a network endpoint address. type NetAddr struct { // Endpoint configures the address for this network connection. @@ -19,11 +27,14 @@ type NetAddr struct { // Transport to use. Known protocols are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only), "udp", "udp4" (IPv4-only), // "udp6" (IPv6-only), "ip", "ip4" (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and "unixpacket". Transport string `mapstructure:"transport"` + + // DialerConfig contains options for connecting to an address. + DialerConfig DialerConfig `mapstructure:"dialer"` } // Dial equivalent with net.Dial for this address. func (na *NetAddr) Dial() (net.Conn, error) { - return net.Dial(na.Transport, na.Endpoint) + return net.DialTimeout(na.Transport, na.Endpoint, na.DialerConfig.Timeout) } // Listen equivalent with net.Listen for this address. @@ -39,11 +50,14 @@ type TCPAddr struct { // If the host is a literal IPv6 address it must be enclosed in square brackets, as in "[2001:db8::1]:80" or // "[fe80::1%zone]:80". The zone specifies the scope of the literal IPv6 address as defined in RFC 4007. Endpoint string `mapstructure:"endpoint"` + + // DialerConfig contains options for connecting to an address. + DialerConfig DialerConfig `mapstructure:"dialer"` } // Dial equivalent with net.Dial for this address. func (na *TCPAddr) Dial() (net.Conn, error) { - return net.Dial("tcp", na.Endpoint) + return net.DialTimeout("tcp", na.Endpoint, na.DialerConfig.Timeout) } // Listen equivalent with net.Listen for this address. diff --git a/config/confignet/confignet_test.go b/config/confignet/confignet_test.go index 7ba5e442ed5..3b8c3fcbbe2 100644 --- a/config/confignet/confignet_test.go +++ b/config/confignet/confignet_test.go @@ -4,12 +4,49 @@ package confignet import ( + "errors" "net" "testing" + "time" "github.com/stretchr/testify/assert" ) +func TestNetAddrTimeout(t *testing.T) { + nac := &NetAddr{ + Endpoint: "localhost:0", + Transport: "tcp", + DialerConfig: DialerConfig{ + Timeout: -1 * time.Second, + }, + } + _, err := nac.Dial() + assert.Error(t, err) + var netErr net.Error + if errors.As(err, &netErr) { + assert.True(t, netErr.Timeout()) + } else { + assert.Fail(t, "error should be a net.Error") + } +} + +func TestTCPAddrTimeout(t *testing.T) { + nac := &TCPAddr{ + Endpoint: "localhost:0", + DialerConfig: DialerConfig{ + Timeout: -1 * time.Second, + }, + } + _, err := nac.Dial() + assert.Error(t, err) + var netErr net.Error + if errors.As(err, &netErr) { + assert.True(t, netErr.Timeout()) + } else { + assert.Fail(t, "error should be a net.Error") + } +} + func TestNetAddr(t *testing.T) { nas := &NetAddr{ Endpoint: "localhost:0", @@ -45,7 +82,7 @@ func TestNetAddr(t *testing.T) { assert.NoError(t, ln.Close()) } -func TestTcpAddr(t *testing.T) { +func TestTCPAddr(t *testing.T) { nas := &TCPAddr{ Endpoint: "localhost:0", }