forked from open-telemetry/opentelemetry-collector-contrib
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[receiver/gitlab] add tracing via webhook skeleton (open-telemetry#36838
) #### Description This PR adds the structure and trace skeleton for a new and already accepted Gitlabreceiver. (thanks @atoulme for sponsoring this!) The Gitlabreceiver aligns very closely with the Githubreceiver and this PR mostly mirrors the change from this PR: open-telemetry#36632 I'm working together with @adrielp on building out the Gitlabreceiver. More PRs to introduce metrics and actual tracing functionality are about to follow with subsequent PRs. #### Link to tracking issue open-telemetry#35207 #### Testing Added basic tests and built the component to test that the health check endpoint, when tracing is enabled, operates correctly. #### Documentation Docs how to configure the Gitlabreceiver via webhooks have been added. While the Gitlabreceiver can be configured after this PR, it will not actually do anything since it is under development and just the skeleton PR.
- Loading branch information
Showing
23 changed files
with
1,167 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Use this changelog template to create an entry for release notes. | ||
|
||
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' | ||
change_type: new_component | ||
|
||
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) | ||
component: gitlabreceiver | ||
|
||
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). | ||
note: Adds webhook skeleton to GitLab receiver to receive events from GitLab for tracing. | ||
|
||
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. | ||
issues: [35207] | ||
|
||
# (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: | ||
This PR adds a skeleton for the GitLab receiver to receive events from GitLab | ||
for tracing via a webhook. The trace portion of this receiver will run and | ||
respond to GET requests for the health check only. | ||
|
||
# If your change doesn't affect end users or the exported elements of any package, | ||
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. | ||
# 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: [user] |
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include ../../Makefile.Common |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# GitLab Receiver | ||
|
||
<!-- status autogenerated section --> | ||
| Status | | | ||
| ------------- |-----------| | ||
| Stability | [development]: traces | | ||
| Distributions | [] | | ||
| Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Areceiver%2Fgitlab%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Areceiver%2Fgitlab) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Areceiver%2Fgitlab%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Areceiver%2Fgitlab) | | ||
| [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@adrielp](https://www.github.com/adrielp), [@atoulme](https://www.github.com/atoulme) | | ||
|
||
[development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development | ||
<!-- end autogenerated section --> | ||
|
||
## Traces - Getting Started | ||
|
||
Workflow tracing support is actively being added to the GitLab receiver. | ||
This is accomplished through the processing of GitLab webhook | ||
events for pipelines. The [`pipeline`](https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#pipeline-events) event payloads are then constructed into `trace` | ||
telemetry. | ||
|
||
Each GitLab pipeline, along with its jobs, is converted | ||
into trace spans, allowing the observation of workflow execution times, | ||
success, and failure rates. | ||
|
||
### Configuration | ||
|
||
**IMPORTANT: At this time the tracing portion of this receiver only serves a health check endpoint.** | ||
|
||
The WebHook configuration exposes the following settings: | ||
|
||
* `endpoint`: (default = `localhost:8080`) - The address and port to bind the WebHook to. | ||
* `path`: (default = `/events`) - The path for Action events to be sent to. | ||
* `health_path`: (default = `/health`) - The path for health checks. | ||
* `secret`: (optional) - The secret used to [validate the payload](https://docs.gitlab.com/ee/user/project/integrations/webhooks.html#custom-headers). | ||
* `required_headers`: (optional) - One or more key-value pairs representing required headers for incoming requests. These headers must not conflict with the fixed default GitLab headers. See the customizable and fixed GitLab headers in [config.go](./config.go). | ||
|
||
The WebHook configuration block also accepts all the [confighttp](https://pkg.go.dev/go.opentelemetry.io/collector/config/confighttp#ServerConfig) | ||
settings. | ||
|
||
An example configuration is as follows: | ||
|
||
```yaml | ||
receivers: | ||
gitlab: | ||
webhook: | ||
endpoint: localhost:19418 | ||
path: /events | ||
health_path: /health | ||
secret: ${env:SECRET_STRING_VAR} | ||
required_headers: | ||
WAF-Header: "value" | ||
``` | ||
For tracing, all configuration is set under the `webhook` key. The full set | ||
of exposed configuration values can be found in [`config.go`](config.go). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package gitlabreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/gitlabreceiver" | ||
|
||
import ( | ||
"errors" | ||
"time" | ||
|
||
"go.opentelemetry.io/collector/component" | ||
"go.opentelemetry.io/collector/config/confighttp" | ||
"go.opentelemetry.io/collector/config/configopaque" | ||
"go.opentelemetry.io/collector/confmap" | ||
"go.uber.org/multierr" | ||
) | ||
|
||
const ( | ||
defaultReadTimeout = 500 * time.Millisecond | ||
defaultWriteTimeout = 500 * time.Millisecond | ||
|
||
defaultEndpoint = "localhost:8080" | ||
|
||
defaultPath = "/events" | ||
defaultHealthPath = "/health" | ||
|
||
// GitLab default headers: https://docs.gitlab.com/ee/user/project/integrations/webhooks.html#delivery-headers | ||
defaultUserAgentHeader = "User-Agent" | ||
defaultGitlabInstanceHeader = "X-Gitlab-Instance" | ||
defaultGitlabWebhookUUIDHeader = "X-Gitlab-Webhook-UUID" | ||
defaultGitlabEventHeader = "X-Gitlab-Event" | ||
defaultGitlabEventUUIDHeader = "X-Gitlab-Event-UUID" | ||
defaultIdempotencyKeyHeader = "Idempotency-Key" | ||
) | ||
|
||
var ( | ||
errReadTimeoutExceedsMaxValue = errors.New("the duration specified for read_timeout exceeds the maximum allowed value of 10s") | ||
errWriteTimeoutExceedsMaxValue = errors.New("the duration specified for write_timeout exceeds the maximum allowed value of 10s") | ||
errRequiredHeader = errors.New("both key and value are required to assign a required_header") | ||
errGitlabHeader = errors.New("gitlab default headers [X-Gitlab-Webhook-UUID, X-Gitlab-Event, X-Gitlab-Event-UUID, Idempotency-Key] cannot be configured") | ||
errConfigNotValid = errors.New("configuration is not valid for the gitlab receiver") | ||
) | ||
|
||
// Config that is exposed to this gitlab receiver through the OTEL config.yaml | ||
type Config struct { | ||
WebHook WebHook `mapstructure:"webhook"` | ||
} | ||
|
||
type WebHook struct { | ||
confighttp.ServerConfig `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct | ||
|
||
Path string `mapstructure:"path"` // path for data collection. default is /events | ||
HealthPath string `mapstructure:"health_path"` // path for health check api. default is /health_check | ||
|
||
RequiredHeaders map[string]configopaque.String `mapstructure:"required_headers"` // optional setting to set one or more required headers for all requests to have (except the health check) | ||
GitlabHeaders GitlabHeaders `mapstructure:",squash"` // GitLab headers set by default | ||
|
||
Secret string `mapstructure:"secret"` // secret for webhook | ||
} | ||
|
||
type GitlabHeaders struct { | ||
Customizable map[string]string `mapstructure:","` // can be overwritten via required_headers | ||
Fixed map[string]string `mapstructure:","` // are not allowed to be overwritten | ||
} | ||
|
||
func createDefaultConfig() component.Config { | ||
return &Config{ | ||
WebHook: WebHook{ | ||
ServerConfig: confighttp.ServerConfig{ | ||
Endpoint: defaultEndpoint, | ||
ReadTimeout: defaultReadTimeout, | ||
WriteTimeout: defaultWriteTimeout, | ||
}, | ||
GitlabHeaders: GitlabHeaders{ | ||
Customizable: map[string]string{ | ||
defaultUserAgentHeader: "", | ||
defaultGitlabInstanceHeader: "https://gitlab.com", | ||
}, | ||
Fixed: map[string]string{ | ||
defaultGitlabWebhookUUIDHeader: "", | ||
defaultGitlabEventHeader: "Pipeline Hook", | ||
defaultGitlabEventUUIDHeader: "", | ||
defaultIdempotencyKeyHeader: "", | ||
}, | ||
}, | ||
Path: defaultPath, | ||
HealthPath: defaultHealthPath, | ||
}, | ||
} | ||
} | ||
|
||
func (cfg *Config) Validate() error { | ||
var errs error | ||
|
||
maxReadWriteTimeout, _ := time.ParseDuration("10s") | ||
|
||
if cfg.WebHook.ServerConfig.ReadTimeout > maxReadWriteTimeout { | ||
errs = multierr.Append(errs, errReadTimeoutExceedsMaxValue) | ||
} | ||
|
||
if cfg.WebHook.ServerConfig.WriteTimeout > maxReadWriteTimeout { | ||
errs = multierr.Append(errs, errWriteTimeoutExceedsMaxValue) | ||
} | ||
|
||
for key, value := range cfg.WebHook.RequiredHeaders { | ||
if key == "" || value == "" { | ||
errs = multierr.Append(errs, errRequiredHeader) | ||
} | ||
|
||
if _, exists := cfg.WebHook.GitlabHeaders.Fixed[key]; exists { | ||
errs = multierr.Append(errs, errGitlabHeader) | ||
} | ||
} | ||
|
||
return errs | ||
} | ||
|
||
func (cfg *Config) Unmarshal(componentParser *confmap.Conf) error { | ||
if componentParser == nil { | ||
return nil | ||
} | ||
|
||
// load the non-dynamic config normally | ||
err := componentParser.Unmarshal(cfg, confmap.WithIgnoreUnused()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// overwrite customizable GitLab default headers if configured within the required_headers | ||
for key, header := range cfg.WebHook.RequiredHeaders { | ||
if _, exists := cfg.WebHook.GitlabHeaders.Customizable[key]; exists { | ||
cfg.WebHook.GitlabHeaders.Customizable[key] = string(header) | ||
} | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package gitlabreceiver | ||
|
||
import ( | ||
"path/filepath" | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
"go.opentelemetry.io/collector/component" | ||
"go.opentelemetry.io/collector/component/componenttest" | ||
"go.opentelemetry.io/collector/config/confighttp" | ||
"go.opentelemetry.io/collector/config/configopaque" | ||
"go.opentelemetry.io/collector/otelcol/otelcoltest" | ||
|
||
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/gitlabreceiver/internal/metadata" | ||
) | ||
|
||
func TestCreateDefaultConfig(t *testing.T) { | ||
factory := NewFactory() | ||
cfg := factory.CreateDefaultConfig() | ||
|
||
expectedConfig := &Config{ | ||
WebHook: WebHook{ | ||
ServerConfig: confighttp.ServerConfig{ | ||
Endpoint: defaultEndpoint, | ||
ReadTimeout: defaultReadTimeout, | ||
WriteTimeout: defaultWriteTimeout, | ||
}, | ||
Path: defaultPath, | ||
HealthPath: defaultHealthPath, | ||
GitlabHeaders: GitlabHeaders{ | ||
Customizable: map[string]string{ | ||
defaultUserAgentHeader: "", | ||
defaultGitlabInstanceHeader: "https://gitlab.com", | ||
}, | ||
Fixed: map[string]string{ | ||
defaultGitlabWebhookUUIDHeader: "", | ||
defaultGitlabEventHeader: "Pipeline Hook", | ||
defaultGitlabEventUUIDHeader: "", | ||
defaultIdempotencyKeyHeader: "", | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
assert.Equal(t, expectedConfig, cfg, "failed to create default config") | ||
assert.NoError(t, componenttest.CheckConfigStruct(cfg)) | ||
} | ||
|
||
func TestLoadConfig(t *testing.T) { | ||
factories, err := otelcoltest.NopFactories() | ||
require.NoError(t, err) | ||
|
||
factory := NewFactory() | ||
factories.Receivers[metadata.Type] = factory | ||
|
||
cfg, err := otelcoltest.LoadConfigAndValidate(filepath.Join("testdata", "config.yaml"), factories) | ||
|
||
require.NoError(t, err) | ||
require.NotNil(t, cfg) | ||
|
||
assert.Len(t, cfg.Receivers, 2) | ||
|
||
expectedConfig := &Config{ | ||
WebHook: WebHook{ | ||
ServerConfig: confighttp.ServerConfig{ | ||
Endpoint: "localhost:8080", | ||
ReadTimeout: 500 * time.Millisecond, | ||
WriteTimeout: 500 * time.Millisecond, | ||
}, | ||
Path: "some/path", | ||
HealthPath: "health/path", | ||
RequiredHeaders: map[string]configopaque.String{ | ||
"key1-present": "value1-present", | ||
}, | ||
GitlabHeaders: GitlabHeaders{ | ||
Customizable: map[string]string{ | ||
defaultUserAgentHeader: "", | ||
defaultGitlabInstanceHeader: "https://gitlab.com", | ||
}, | ||
Fixed: map[string]string{ | ||
defaultGitlabWebhookUUIDHeader: "", | ||
defaultGitlabEventHeader: "Pipeline Hook", | ||
defaultGitlabEventUUIDHeader: "", | ||
defaultIdempotencyKeyHeader: "", | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
r0 := cfg.Receivers[component.NewID(metadata.Type)] | ||
|
||
assert.Equal(t, expectedConfig, r0) | ||
|
||
// r1 requires multiple headers and overwrites gitlab default headers | ||
expectedConfig.WebHook.RequiredHeaders = map[string]configopaque.String{ | ||
"key1-present": "value1-present", | ||
"key2-present": "value2-present", | ||
"User-Agent": "GitLab/1.2.3-custom-version", | ||
"X-Gitlab-Instance": "https://gitlab.self-hosted.xyz", | ||
} | ||
|
||
expectedConfig.WebHook.GitlabHeaders = GitlabHeaders{ | ||
Customizable: map[string]string{ | ||
defaultUserAgentHeader: "GitLab/1.2.3-custom-version", | ||
defaultGitlabInstanceHeader: "https://gitlab.self-hosted.xyz", | ||
}, | ||
Fixed: map[string]string{ | ||
defaultGitlabWebhookUUIDHeader: "", | ||
defaultGitlabEventHeader: "Pipeline Hook", | ||
defaultGitlabEventUUIDHeader: "", | ||
defaultIdempotencyKeyHeader: "", | ||
}, | ||
} | ||
|
||
r1 := cfg.Receivers[component.NewIDWithName(metadata.Type, "customname")].(*Config) | ||
|
||
assert.Equal(t, expectedConfig, r1) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
//go:generate mdatagen metadata.yaml | ||
|
||
package gitlabreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/gitlabreceiver" |
Oops, something went wrong.