Skip to content

Commit 4610126

Browse files
jmacdbogdandrutu
andauthored
Middleware: config struct (part 2/4) (#12844)
**Description** Adds the config struct from #12842. **Link to tracking issue** Part of #12603. **Testing** Yes. This PR introduces `extensionmiddlewaretest` helpers. **Documentation** Added. --------- Co-authored-by: Bogdan Drutu <[email protected]>
1 parent d79ffd3 commit 4610126

File tree

23 files changed

+1155
-3
lines changed

23 files changed

+1155
-3
lines changed

.chloggen/middleware-struct.yaml

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver)
7+
component: configmiddleware
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add configmiddleware struct.
11+
12+
# One or more tracking issues or pull requests related to the change
13+
issues: [12603, 9591]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# Optional: The change log or logs in which this entry should be included.
21+
# e.g. '[user]' or '[user, api]'
22+
# Include 'user' if the change is relevant to end users.
23+
# Include 'api' if there is a change to a library API.
24+
# Default: '[user]'
25+
change_logs: [user]

.github/workflows/utils/cspell.json

+2
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@
192192
"extensionauthtest",
193193
"extensioncapabilities",
194194
"extensionmiddleware",
195+
"extensionmiddlewaretest",
195196
"extensionhelper",
196197
"extensiontest",
197198
"extensionz",
@@ -269,6 +270,7 @@
269270
"lables",
270271
"lastest",
271272
"ldflags",
273+
"limitermiddleware",
272274
"localhostgate",
273275
"loggingexporter",
274276
"logstest",

config/configmiddleware/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include ../../Makefile.Common

config/configmiddleware/README.md

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# OpenTelemetry Collector Middleware Configuration
2+
3+
This package implements a configuration struct for referring to
4+
[middleware extensions](../../extension/extensionmiddleware/README.md).
5+
6+
## Overview
7+
8+
The `configmiddleware` package defines a `Config` type that
9+
allows components to configure middleware extensions, typically as
10+
an ordered list.
11+
This support is built in for push-based receivers configured through
12+
`confighttp` and `configgrpc`, as for example in the OTLP receiver:
13+
14+
```yaml
15+
receivers:
16+
otlp:
17+
protocols:
18+
http:
19+
middlewares:
20+
- id: limitermiddleware
21+
```
22+
23+
## Methods
24+
25+
The package provides four key methods to retrieve appropriate middleware handlers:
26+
27+
1. **GetHTTPClientRoundTripper**: Obtains a function to wrap an HTTP client with a middleware extension via a `http.RoundTripper`.
28+
29+
2. **GetHTTPServerHandler**: Obtains a function to wrap an HTTP server with a middleware extension via a `http.Handler`.
30+
31+
3. **GetGRPCClientOptions**: Obtains a `[]grpc.DialOption` that configure a middleware extension for gRPC clients.
32+
33+
4. **GetGRPCServerOptions**: Obtains a `[]grpc.ServerOption` that configure a middleware extension for gRPC servers.
34+
35+
These functions are typically called during Start() by a component,
36+
passing the `component.Host` extensions.
37+
An error is returned if the named extension cannot be found.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
// Package configmiddleware implements a configuration struct to
5+
// name middleware extensions.
6+
package configmiddleware // import "go.opentelemetry.io/collector/config/configmiddleware"
7+
8+
import (
9+
"context"
10+
"errors"
11+
"fmt"
12+
"net/http"
13+
14+
"google.golang.org/grpc"
15+
16+
"go.opentelemetry.io/collector/component"
17+
"go.opentelemetry.io/collector/extension/extensionmiddleware"
18+
)
19+
20+
var (
21+
errMiddlewareNotFound = errors.New("middleware not found")
22+
errNotHTTPServer = errors.New("requested extension is not an HTTP server middleware")
23+
errNotGRPCServer = errors.New("requested extension is not a gRPC server middleware")
24+
errNotHTTPClient = errors.New("requested extension is not an HTTP client middleware")
25+
errNotGRPCClient = errors.New("requested extension is not a gRPC client middleware")
26+
)
27+
28+
// Middleware defines the extension ID for a middleware component.
29+
type Config struct {
30+
// ID specifies the name of the extension to use.
31+
ID component.ID `mapstructure:"id,omitempty"`
32+
}
33+
34+
// GetHTTPClientRoundTripper attempts to select the appropriate
35+
// extensionmiddleware.HTTPClient from the map of extensions, and
36+
// returns the HTTP client wrapper function. If a middleware is not
37+
// found, an error is returned. This should only be used by HTTP
38+
// clients.
39+
func (m Config) GetHTTPClientRoundTripper(_ context.Context, extensions map[component.ID]component.Component) (func(http.RoundTripper) (http.RoundTripper, error), error) {
40+
if ext, found := extensions[m.ID]; found {
41+
if client, ok := ext.(extensionmiddleware.HTTPClient); ok {
42+
return client.GetHTTPRoundTripper, nil
43+
}
44+
return nil, errNotHTTPClient
45+
}
46+
return nil, fmt.Errorf("failed to resolve middleware %q: %w", m.ID, errMiddlewareNotFound)
47+
}
48+
49+
// GetHTTPServerHandler attempts to select the appropriate
50+
// extensionmiddleware.HTTPServer from the map of extensions, and
51+
// returns the http.Handler wrapper function. If a middleware is not
52+
// found, an error is returned. This should only be used by HTTP
53+
// servers.
54+
func (m Config) GetHTTPServerHandler(_ context.Context, extensions map[component.ID]component.Component) (func(http.Handler) (http.Handler, error), error) {
55+
if ext, found := extensions[m.ID]; found {
56+
if server, ok := ext.(extensionmiddleware.HTTPServer); ok {
57+
return server.GetHTTPHandler, nil
58+
}
59+
return nil, errNotHTTPServer
60+
}
61+
62+
return nil, fmt.Errorf("failed to resolve middleware %q: %w", m.ID, errMiddlewareNotFound)
63+
}
64+
65+
// GetGRPCClientOptions attempts to select the appropriate
66+
// extensionmiddleware.GRPCClient from the map of extensions, and
67+
// returns the gRPC dial options. If a middleware is not found, an
68+
// error is returned. This should only be used by gRPC clients.
69+
func (m Config) GetGRPCClientOptions(_ context.Context, extensions map[component.ID]component.Component) ([]grpc.DialOption, error) {
70+
if ext, found := extensions[m.ID]; found {
71+
if client, ok := ext.(extensionmiddleware.GRPCClient); ok {
72+
return client.GetGRPCClientOptions()
73+
}
74+
return nil, errNotGRPCClient
75+
}
76+
return nil, fmt.Errorf("failed to resolve middleware %q: %w", m.ID, errMiddlewareNotFound)
77+
}
78+
79+
// GetGRPCServerOptions attempts to select the appropriate
80+
// extensionmiddleware.GRPCServer from the map of extensions, and
81+
// returns the gRPC server options. If a middleware is not found, an
82+
// error is returned. This should only be used by gRPC servers.
83+
func (m Config) GetGRPCServerOptions(_ context.Context, extensions map[component.ID]component.Component) ([]grpc.ServerOption, error) {
84+
if ext, found := extensions[m.ID]; found {
85+
if server, ok := ext.(extensionmiddleware.GRPCServer); ok {
86+
return server.GetGRPCServerOptions()
87+
}
88+
return nil, errNotGRPCServer
89+
}
90+
91+
return nil, fmt.Errorf("failed to resolve middleware %q: %w", m.ID, errMiddlewareNotFound)
92+
}

0 commit comments

Comments
 (0)