-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add host.id to resource auto-detection (#3812)
* add platform specific hostIDReaders * add WithHostID option to Resource * add changelog entry * Apply suggestions from code review Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com> * linting * combine platform specific readers and tests This allows us to run tests for the BSD, Darwin, and Linux readers on all platforms. * add todo to use assert.AnError after resource.Detect error handling is updated * move HostID test utilities to host_id_test * return assert.AnError from mockHostIDProviderWithError * use assert.ErrorIs Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com> --------- Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com> Co-authored-by: Aaron Clawson <3766680+MadVikingGod@users.noreply.github.com>
- Loading branch information
1 parent
1eab60f
commit 282a47e
Showing
12 changed files
with
622 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
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,142 @@ | ||
// 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 resource // import "go.opentelemetry.io/otel/sdk/resource" | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"os" | ||
"os/exec" | ||
"strings" | ||
|
||
semconv "go.opentelemetry.io/otel/semconv/v1.17.0" | ||
) | ||
|
||
type hostIDProvider func() (string, error) | ||
|
||
var defaultHostIDProvider hostIDProvider = platformHostIDReader.read | ||
|
||
var hostID = defaultHostIDProvider | ||
|
||
type hostIDReader interface { | ||
read() (string, error) | ||
} | ||
|
||
type fileReader func(string) (string, error) | ||
|
||
type commandExecutor func(string, ...string) (string, error) | ||
|
||
func readFile(filename string) (string, error) { | ||
b, err := os.ReadFile(filename) | ||
if err != nil { | ||
return "", nil | ||
} | ||
|
||
return string(b), nil | ||
} | ||
|
||
// nolint: unused // This is used by the hostReaderBSD, gated by build tags. | ||
func execCommand(name string, arg ...string) (string, error) { | ||
cmd := exec.Command(name, arg...) | ||
b, err := cmd.Output() | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return string(b), nil | ||
} | ||
|
||
// hostIDReaderBSD implements hostIDReader. | ||
type hostIDReaderBSD struct { | ||
execCommand commandExecutor | ||
readFile fileReader | ||
} | ||
|
||
// read attempts to read the machine-id from /etc/hostid. If not found it will | ||
// execute `kenv -q smbios.system.uuid`. If neither location yields an id an | ||
// error will be returned. | ||
func (r *hostIDReaderBSD) read() (string, error) { | ||
if result, err := r.readFile("/etc/hostid"); err == nil { | ||
return strings.TrimSpace(result), nil | ||
} | ||
|
||
if result, err := r.execCommand("kenv", "-q", "smbios.system.uuid"); err == nil { | ||
return strings.TrimSpace(result), nil | ||
} | ||
|
||
return "", errors.New("host id not found in: /etc/hostid or kenv") | ||
} | ||
|
||
// hostIDReaderDarwin implements hostIDReader. | ||
type hostIDReaderDarwin struct { | ||
execCommand commandExecutor | ||
} | ||
|
||
// read executes `ioreg -rd1 -c "IOPlatformExpertDevice"` and parses host id | ||
// from the IOPlatformUUID line. If the command fails or the uuid cannot be | ||
// parsed an error will be returned. | ||
func (r *hostIDReaderDarwin) read() (string, error) { | ||
result, err := r.execCommand("ioreg", "-rd1", "-c", "IOPlatformExpertDevice") | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
lines := strings.Split(result, "\n") | ||
for _, line := range lines { | ||
if strings.Contains(line, "IOPlatformUUID") { | ||
parts := strings.Split(line, " = ") | ||
if len(parts) == 2 { | ||
return strings.Trim(parts[1], "\""), nil | ||
} | ||
break | ||
} | ||
} | ||
|
||
return "", errors.New("could not parse IOPlatformUUID") | ||
} | ||
|
||
type hostIDReaderLinux struct { | ||
readFile fileReader | ||
} | ||
|
||
// read attempts to read the machine-id from /etc/machine-id followed by | ||
// /var/lib/dbus/machine-id. If neither location yields an ID an error will | ||
// be returned. | ||
func (r *hostIDReaderLinux) read() (string, error) { | ||
if result, err := r.readFile("/etc/machine-id"); err == nil { | ||
return strings.TrimSpace(result), nil | ||
} | ||
|
||
if result, err := r.readFile("/var/lib/dbus/machine-id"); err == nil { | ||
return strings.TrimSpace(result), nil | ||
} | ||
|
||
return "", errors.New("host id not found in: /etc/machine-id or /var/lib/dbus/machine-id") | ||
} | ||
|
||
type hostIDDetector struct{} | ||
|
||
// Detect returns a *Resource containing the platform specific host id. | ||
func (hostIDDetector) Detect(ctx context.Context) (*Resource, error) { | ||
hostID, err := hostID() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return NewWithAttributes( | ||
semconv.SchemaURL, | ||
semconv.HostID(hostID), | ||
), 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,28 @@ | ||
// 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. | ||
|
||
//go:build dragonfly || freebsd || netbsd || openbsd || solaris | ||
// +build dragonfly freebsd netbsd openbsd solaris | ||
|
||
package resource // import "go.opentelemetry.io/otel/sdk/resource" | ||
|
||
import ( | ||
"errors" | ||
"strings" | ||
) | ||
|
||
var platformHostIDReader hostIDReader = &hostIDReaderBSD{ | ||
execCommand: execCommand, | ||
readFile: readFile, | ||
} |
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,19 @@ | ||
// 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 resource // import "go.opentelemetry.io/otel/sdk/resource" | ||
|
||
var platformHostIDReader hostIDReader = &hostIDReaderDarwin{ | ||
execCommand: execCommand, | ||
} |
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,37 @@ | ||
// 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 resource_test | ||
|
||
import ( | ||
"github.com/stretchr/testify/assert" | ||
|
||
"go.opentelemetry.io/otel/sdk/resource" | ||
) | ||
|
||
func mockHostIDProvider() { | ||
resource.SetHostIDProvider( | ||
func() (string, error) { return "f2c668b579780554f70f72a063dc0864", nil }, | ||
) | ||
} | ||
|
||
func mockHostIDProviderWithError() { | ||
resource.SetHostIDProvider( | ||
func() (string, error) { return "", assert.AnError }, | ||
) | ||
} | ||
|
||
func restoreHostIDProvider() { | ||
resource.SetDefaultHostIDProvider() | ||
} |
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,22 @@ | ||
// 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. | ||
|
||
//go:build linux | ||
// +build linux | ||
|
||
package resource // import "go.opentelemetry.io/otel/sdk/resource" | ||
|
||
var platformHostIDReader hostIDReader = &hostIDReaderLinux{ | ||
readFile: readFile, | ||
} |
Oops, something went wrong.