Skip to content

Commit 8cfca01

Browse files
adrianrioboclaude
andcommitted
refactor(otelcol): extract otelcol-contrib into reusable integration module
Move otelcol-contrib install/config out of IBM-specific cloud-configs into pkg/integrations/otelcol. The module uses a binary tarball download instead of apt-get/dnf so it works on any Linux distro without package-manager dependency conflicts (avoids dpkg conffile prompt when config.yaml is pre-written by cloud-init write_files before the package installs). - New pkg/integrations/otelcol with types, snippet-linux.sh template, and GetSnippet/GetSnippetAsCloudInitWritableFile helpers - IBM Z and IBM Power cloud-configs simplified to write/run the otelcol install script, removing all inline otelcol YAML - Makefile ldflags consolidated to single otelcol.version override - Tests updated to match new piUserData/izUserData signatures Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent ac195f9 commit 8cfca01

7 files changed

Lines changed: 342 additions & 203 deletions

File tree

Makefile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ VERSION_VARIABLES := -X $(MODULEPATH)/pkg/manager/context.OCI=$(IMG) \
2828
-X $(MODULEPATH)/pkg/integrations/cirrus.version=$(CIRRUS_CLI) \
2929
-X $(MODULEPATH)/pkg/integrations/github.runnerVersion=$(GITHUB_RUNNER) \
3030
-X $(MODULEPATH)/pkg/integrations/gitlab.version=$(GITLAB_RUNNER) \
31-
-X $(MODULEPATH)/pkg/provider/ibmcloud/action/ibm-power.otelColVersion=$(OTELCOL_VERSION) \
32-
-X $(MODULEPATH)/pkg/provider/ibmcloud/action/ibm-z.otelColVersion=$(OTELCOL_VERSION)
31+
-X $(MODULEPATH)/pkg/integrations/otelcol.version=$(OTELCOL_VERSION)
3332
LDFLAGS := $(VERSION_VARIABLES) ${GO_EXTRA_LDFLAGS}
3433
GCFLAGS := all=-N -l
3534
GOOS := $(shell go env GOOS)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package otelcol
2+
3+
import (
4+
_ "embed"
5+
6+
cloudinit "github.com/redhat-developer/mapt/pkg/util/cloud-init"
7+
"github.com/redhat-developer/mapt/pkg/util/file"
8+
)
9+
10+
// version is overridden at build time via -ldflags.
11+
var version = "0.151.0"
12+
13+
//go:embed snippet-linux.sh
14+
var snippetLinux []byte
15+
16+
// GetSnippet renders the install script template with the provided args and
17+
// returns the shell script as a string. Returns an empty string when args is nil.
18+
func GetSnippet(args *OtelcolArgs) (*string, error) {
19+
if args == nil {
20+
empty := ""
21+
return &empty, nil
22+
}
23+
if args.ColVersion == "" {
24+
args.ColVersion = version
25+
}
26+
snippet, err := file.Template(args, string(snippetLinux))
27+
return &snippet, err
28+
}
29+
30+
// GetSnippetAsCloudInitWritableFile returns the rendered install script indented
31+
// with 6 spaces so it can be embedded directly as the content of a cloud-init
32+
// write_files entry.
33+
func GetSnippetAsCloudInitWritableFile(args *OtelcolArgs) (*string, error) {
34+
snippet, err := GetSnippet(args)
35+
if err != nil || len(*snippet) == 0 {
36+
return snippet, err
37+
}
38+
return cloudinit.IndentWriteFile(snippet)
39+
}
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
PROXY_URL=""
5+
if ! curl -sf --connect-timeout 5 --head {{.Endpoint}} > /dev/null 2>&1; then
6+
PROXY_URL="http://squid.corp.redhat.com:3128"
7+
fi
8+
9+
# Download binary tarball — works on any Linux distro, no package manager needed
10+
TAR_URL="https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v{{.ColVersion}}/otelcol-contrib_{{.ColVersion}}_linux_{{.Arch}}.tar.gz"
11+
HTTPS_PROXY="$PROXY_URL" curl -fsSL -o /tmp/otelcol-contrib.tar.gz "$TAR_URL"
12+
tar -xzf /tmp/otelcol-contrib.tar.gz -C /tmp otelcol-contrib
13+
mv /tmp/otelcol-contrib /usr/local/bin/otelcol-contrib
14+
chmod 755 /usr/local/bin/otelcol-contrib
15+
chcon -t bin_t /usr/local/bin/otelcol-contrib 2>/dev/null || restorecon -v /usr/local/bin/otelcol-contrib 2>/dev/null || true
16+
rm -f /tmp/otelcol-contrib.tar.gz
17+
18+
# Create dedicated system user (idempotent)
19+
useradd --system --no-create-home --shell /sbin/nologin otelcol-contrib 2>/dev/null || true
20+
21+
# Create config and drop-in directories
22+
mkdir -p /etc/otelcol-contrib /etc/systemd/system/otelcol-contrib.service.d
23+
24+
# Write systemd service unit
25+
cat > /etc/systemd/system/otelcol-contrib.service << 'SVCEOF'
26+
[Unit]
27+
Description=OpenTelemetry Collector Contrib
28+
After=network.target
29+
30+
[Service]
31+
User=otelcol-contrib
32+
Group=otelcol-contrib
33+
EnvironmentFile=/etc/otelcol-contrib/otelcol-contrib.conf
34+
EnvironmentFile=/etc/otelcol-contrib/auth_token
35+
ExecStart=/usr/local/bin/otelcol-contrib $OTELCOL_OPTIONS
36+
Restart=on-failure
37+
RestartSec=5s
38+
KillMode=process
39+
SyslogIdentifier=otelcol-contrib
40+
41+
[Install]
42+
WantedBy=multi-user.target
43+
SVCEOF
44+
45+
# Drop-in: grant read access to all log files and expose hostname
46+
cat > /etc/systemd/system/otelcol-contrib.service.d/capabilities.conf << 'CAPEOF'
47+
[Service]
48+
AmbientCapabilities=CAP_DAC_READ_SEARCH
49+
Environment="HOSTNAME=%H"
50+
CAPEOF
51+
52+
# Options file consumed by ExecStart
53+
printf 'OTELCOL_OPTIONS=--config /etc/otelcol-contrib/config.yaml\n' \
54+
> /etc/otelcol-contrib/otelcol-contrib.conf
55+
chmod 640 /etc/otelcol-contrib/otelcol-contrib.conf
56+
57+
# Auth token (mode 600 — readable only by otelcol-contrib user after chown)
58+
printf 'OTEL_AUTH_TOKEN={{.AuthToken}}\n' > /etc/otelcol-contrib/auth_token
59+
chmod 600 /etc/otelcol-contrib/auth_token
60+
61+
# Collector configuration
62+
cat > /etc/otelcol-contrib/config.yaml << 'OTELEOF'
63+
receivers:
64+
filelog/syslog:
65+
include:
66+
- {{.SyslogPath}}
67+
start_at: end
68+
include_file_path: true
69+
include_file_name: true
70+
exclude_older_than: 24h
71+
operators:
72+
- type: move
73+
id: move_to_source_name
74+
from: attributes["log.file.path"]
75+
to: attributes["_sourceName"]
76+
- type: remove
77+
id: remove_file_name
78+
field: attributes["log.file.name"]
79+
- type: time_parser
80+
id: parse_timestamp
81+
layout: '%b %e %H:%M:%S'
82+
parse_from: body
83+
on_error: send
84+
attributes:
85+
index: "{{.Index}}"
86+
_sourceCategory: syslog
87+
_sourceHost: ${env:HOSTNAME}
88+
filelog/secure:
89+
include:
90+
- {{.SecurePath}}
91+
start_at: end
92+
include_file_path: true
93+
include_file_name: true
94+
exclude_older_than: 24h
95+
operators:
96+
- type: move
97+
id: move_to_source_name
98+
from: attributes["log.file.path"]
99+
to: attributes["_sourceName"]
100+
- type: remove
101+
id: remove_file_name
102+
field: attributes["log.file.name"]
103+
- type: time_parser
104+
id: parse_timestamp
105+
layout: '%b %e %H:%M:%S'
106+
parse_from: body
107+
on_error: send
108+
attributes:
109+
index: "{{.Index}}"
110+
_sourceCategory: secure
111+
_sourceHost: ${env:HOSTNAME}
112+
filelog/audit:
113+
include:
114+
- /var/log/audit/audit.log
115+
start_at: end
116+
include_file_path: true
117+
include_file_name: true
118+
exclude_older_than: 24h
119+
operators:
120+
- type: move
121+
id: move_to_source_name
122+
from: attributes["log.file.path"]
123+
to: attributes["_sourceName"]
124+
- type: remove
125+
id: remove_file_name
126+
field: attributes["log.file.name"]
127+
attributes:
128+
index: "{{.Index}}"
129+
_sourceCategory: audit
130+
_sourceHost: ${env:HOSTNAME}
131+
{{- if .MonitorGitLabRunner}}
132+
filelog/gitlab-runner:
133+
include:
134+
- /var/log/gitlab-runner/runner.log
135+
start_at: end
136+
include_file_path: true
137+
include_file_name: true
138+
operators:
139+
- type: move
140+
id: move_to_source_name
141+
from: attributes["log.file.path"]
142+
to: attributes["_sourceName"]
143+
- type: remove
144+
id: remove_file_name
145+
field: attributes["log.file.name"]
146+
attributes:
147+
index: "{{.Index}}"
148+
_sourceCategory: gitlab-runner
149+
_sourceHost: ${env:HOSTNAME}
150+
{{- end}}
151+
processors:
152+
filter/drop_null_bytes:
153+
logs:
154+
log_record:
155+
- 'IsMatch(body, "^\x00+$")'
156+
batch:
157+
timeout: "1s"
158+
send_batch_size: 1024
159+
resource:
160+
attributes:
161+
- key: appcode
162+
value: "{{.AppCode}}"
163+
action: upsert
164+
- key: com.redhat.otel.auth_token
165+
value: "${env:OTEL_AUTH_TOKEN}"
166+
action: upsert
167+
- key: arch
168+
value: "{{.Arch}}"
169+
action: upsert
170+
{{- range $k, $v := .ExtraAttrs}}
171+
- key: {{$k}}
172+
value: "{{$v}}"
173+
action: upsert
174+
{{- end}}
175+
exporters:
176+
otlphttp:
177+
endpoint: "{{.Endpoint}}"
178+
tls:
179+
insecure_skip_verify: true
180+
service:
181+
telemetry:
182+
logs:
183+
level: "fatal"
184+
metrics:
185+
level: "basic"
186+
pipelines:
187+
logs:
188+
receivers: [filelog/syslog, filelog/secure, filelog/audit{{if .MonitorGitLabRunner}}, filelog/gitlab-runner{{end}}]
189+
processors: [filter/drop_null_bytes, resource, batch]
190+
exporters: [otlphttp]
191+
OTELEOF
192+
193+
# Transfer ownership to the service user
194+
chown -R otelcol-contrib:otelcol-contrib /etc/otelcol-contrib
195+
196+
# Set up proxy drop-in if direct access to the endpoint was unavailable
197+
if [ -n "$PROXY_URL" ]; then
198+
printf '[Service]\nEnvironment="HTTPS_PROXY=%s/"\nEnvironment="NO_PROXY=10.*,192.168.*,localhost,127.0.0.1"\n' "$PROXY_URL" \
199+
> /etc/systemd/system/otelcol-contrib.service.d/proxy.conf
200+
fi
201+
202+
systemctl daemon-reload
203+
systemctl enable --now otelcol-contrib

pkg/integrations/otelcol/types.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package otelcol
2+
3+
// Arch is a Linux architecture identifier used for binary download URLs.
4+
type Arch string
5+
6+
var (
7+
Ppc64le Arch = "ppc64le"
8+
S390x Arch = "s390x"
9+
Amd64 Arch = "amd64"
10+
Arm64 Arch = "arm64"
11+
)
12+
13+
// OtelcolArgs holds all parameters needed to install and configure the
14+
// otelcol-contrib filelog collector on a Linux host.
15+
type OtelcolArgs struct {
16+
AppCode string
17+
AuthToken string
18+
Index string
19+
Endpoint string
20+
ColVersion string // overridden from module var if empty
21+
Arch Arch // target linux arch (ppc64le, s390x, amd64, arm64)
22+
SyslogPath string // distro-specific syslog path
23+
SecurePath string // distro-specific auth/secure log path
24+
ExtraAttrs map[string]string // additional resource attributes
25+
26+
// MonitorGitLabRunner adds a filelog/gitlab-runner receiver that tails
27+
// /var/log/gitlab-runner/runner.log when set to true.
28+
MonitorGitLabRunner bool
29+
}

0 commit comments

Comments
 (0)