Skip to content

Commit

Permalink
[extension/headersetter] Rename headerssetter -> headerssettersextens…
Browse files Browse the repository at this point in the history
…ion.

Deprecate the `github.com/open-telemetry/opentelemetry-collector-contrib/extension/headerssetter` module.
  • Loading branch information
kovrus committed Sep 21, 2022
1 parent d54309a commit 25a42d4
Show file tree
Hide file tree
Showing 24 changed files with 1,418 additions and 8 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ extension/awsproxy/ @open-telemetry/collector-c
extension/basicauthextension/ @open-telemetry/collector-contrib-approvers @jpkrohling @svrakitin
extension/bearertokenauthextension/ @open-telemetry/collector-contrib-approvers @jpkrohling @pavankrish123
extension/headerssetter/ @open-telemetry/collector-contrib-approvers @jpkrohling @kovrus
extension/headerssetterextension/ @open-telemetry/collector-contrib-approvers @jpkrohling @kovrus
extension/healthcheckextension/ @open-telemetry/collector-contrib-approvers @jpkrohling
extension/jaegerremotesampling/ @open-telemetry/collector-contrib-approvers @jpkrohling
extension/oauth2clientauthextension/ @open-telemetry/collector-contrib-approvers @pavankrish123 @jpkrohling
Expand Down
4 changes: 2 additions & 2 deletions cmd/configschema/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ require (
github.com/open-telemetry/opentelemetry-collector-contrib/extension/basicauthextension v0.60.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/extension/bearertokenauthextension v0.60.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/extension/fluentbitextension v0.60.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/extension/headerssetter v0.60.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/extension/headerssetterextension v0.60.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension v0.60.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarder v0.60.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/extension/oauth2clientauthextension v0.60.0 // indirect
Expand Down Expand Up @@ -746,7 +746,7 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/extension/bear

replace github.com/open-telemetry/opentelemetry-collector-contrib/extension/fluentbitextension => ../../extension/fluentbitextension

replace github.com/open-telemetry/opentelemetry-collector-contrib/extension/headerssetter => ../../extension/headerssetter
replace github.com/open-telemetry/opentelemetry-collector-contrib/extension/headerssetterextension => ../../extension/headerssetterextension

replace github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension => ../../extension/healthcheckextension

Expand Down
3 changes: 3 additions & 0 deletions extension/headerssetter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
| Stability | [alpha] |
| Distributions | [contrib] |

*Deprecated:* module `github.com/open-telemetry/opentelemetry-collector-contrib/extension/headerssetter`
is deprecated, use `github.com/open-telemetry/opentelemetry-collector-contrib/extension/headerssetterextension` instead.

The `headers_setter` extension implements `ClientAuthenticator` and is used to
set requests headers in `gRPC` / `HTTP` exporters with values provided via
extension configurations or requests metadata (context).
Expand Down
1 change: 1 addition & 0 deletions extension/headerssetterextension/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../../Makefile.Common
81 changes: 81 additions & 0 deletions extension/headerssetterextension/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Headers Setter extension

| Status | |
|---------------|-----------|
| Stability | [alpha] |
| Distributions | [contrib] |

The `headers_setter` extension implements `ClientAuthenticator` and is used to
set requests headers in `gRPC` / `HTTP` exporters with values provided via
extension configurations or requests metadata (context).

Use cases include but are not limited to enabling multi-tenancy for observability
backends such as [Tempo], [Mimir], [Loki] and others by setting the `X-Scope-OrgID`
header to the value extracted from the context.

## Configuration

The following settings are required:

- `headers`: a list of header configuration objects that specify headers and
their value sources. Each configuration object has the following properties:
- `key`: the header name
- `value`: the header value is looked up from the `value` property of the
extension configuration
- `from_context`: the header value is looked up from the request metadata,
such as HTTP headers, using the property value as the key (likely a header name)

The `value` and `from_context` properties are mutually exclusive.


#### Configuration Example

```yaml
extensions:
headers_setter:
headers:
- key: X-Scope-OrgID
from_context: tenant_id
- key: User-ID
value: user_id

receivers:
otlp:
protocols:
http:
include_metadata: true

processors:
nop:

exporters:
loki:
labels:
resource:
container_id: ""
container_name: ""
endpoint: https://localhost:<port>/loki/api/v1/push
auth:
authenticator: headers_setter

service:
extensions: [ headers_setter ]
pipelines:
traces:
receivers: [ otlp ]
processors: [ nop ]
exporters: [ loki ]
```
## Limitations
At the moment, it is not possible to use the `from_context` option to ge the
header value if Collector's pipeline contains the batch processor. See [#4544].


[alpha]: https://github.com/open-telemetry/opentelemetry-collector#alpha
[contrib]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib
[Mimir]: https://grafana.com/oss/mimir/
[Tempo]: https://grafana.com/oss/tempo/
[Loki]: https://grafana.com/oss/loki/
[#4544]: https://github.com/open-telemetry/opentelemetry-collector/issues/4544
58 changes: 58 additions & 0 deletions extension/headerssetterextension/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package headerssetterextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/headerssetterextension"

import (
"fmt"

"go.opentelemetry.io/collector/config"
)

var (
errMissingHeader = fmt.Errorf("missing header name")
errMissingHeadersConfig = fmt.Errorf("missing headers configuration")
errMissingSource = fmt.Errorf("missing header source, must be 'from_context' or 'value'")
errConflictingSources = fmt.Errorf("invalid header source, must either 'from_context' or 'value'")
)

type Config struct {
config.ExtensionSettings `mapstructure:",squash"`
HeadersConfig []HeaderConfig `mapstructure:"headers"`
}

type HeaderConfig struct {
Key *string `mapstructure:"key"`
Value *string `mapstructure:"value"`
FromContext *string `mapstructure:"from_context"`
}

// Validate checks if the extension configuration is valid
func (cfg *Config) Validate() error {
if cfg.HeadersConfig == nil || len(cfg.HeadersConfig) == 0 {
return errMissingHeadersConfig
}
for _, header := range cfg.HeadersConfig {
if header.Key == nil || *header.Key == "" {
return errMissingHeader
}
if header.FromContext == nil && header.Value == nil {
return errMissingSource
}
if header.FromContext != nil && header.Value != nil {
return errConflictingSources
}
}
return nil
}
143 changes: 143 additions & 0 deletions extension/headerssetterextension/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package headerssetterextension

import (
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/config"
"go.opentelemetry.io/collector/confmap/confmaptest"
)

func TestLoadConfig(t *testing.T) {
t.Parallel()

tests := []struct {
id config.ComponentID
expected config.Extension
}{
{
id: config.NewComponentID(typeStr),
expected: NewFactory().CreateDefaultConfig(),
},
{
id: config.NewComponentIDWithName(typeStr, "1"),
expected: &Config{
ExtensionSettings: config.NewExtensionSettings(config.NewComponentID(typeStr)),
HeadersConfig: []HeaderConfig{
{
Key: stringp("X-Scope-OrgID"),
FromContext: stringp("tenant_id"),
Value: nil,
},
{
Key: stringp("User-ID"),
FromContext: stringp("user_id"),
Value: nil,
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.id.String(), func(t *testing.T) {
cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml"))
require.NoError(t, err)
factory := NewFactory()
cfg := factory.CreateDefaultConfig()
sub, err := cm.Sub(tt.id.String())
require.NoError(t, err)
require.NoError(t, config.UnmarshalExtension(sub, cfg))
assert.Equal(t, tt.expected, cfg)
})
}
}

func TestValidateConfig(t *testing.T) {
tests := []struct {
name string
header []HeaderConfig
expectedErr error
}{
{
"header value from config property",
[]HeaderConfig{
{
Key: stringp("name"),
Value: stringp("from config"),
},
},
nil,
},
{
"header value from context",
[]HeaderConfig{
{
Key: stringp("name"),
FromContext: stringp("from config"),
},
},
nil,
},
{
"missing header name for from value",
[]HeaderConfig{
{Value: stringp("test")},
},
errMissingHeader,
},
{
"missing header name for from context",
[]HeaderConfig{
{FromContext: stringp("test")},
},
errMissingHeader,
},
{
"header value from context and value",
[]HeaderConfig{
{
Key: stringp("name"),
Value: stringp("from config"),
FromContext: stringp("from context"),
},
},
errConflictingSources,
},
{
"header value source is missing",
[]HeaderConfig{
{
Key: stringp("name"),
},
},
errMissingSource,
},
{
"headers configuration is missing",
nil,
errMissingHeadersConfig,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cfg := Config{HeadersConfig: tt.header}
require.ErrorIs(t, cfg.Validate(), tt.expectedErr)
})
}
}
Loading

0 comments on commit 25a42d4

Please sign in to comment.