From 6ed87cafa2439050cdd3529a834e01df30f0a000 Mon Sep 17 00:00:00 2001 From: Anderson Queiroz Date: Thu, 22 Aug 2024 12:05:15 +0200 Subject: [PATCH 1/5] allow to choose hostname and FQDN to be lowercased or not providers.LowercaseHostname and providers.SetLowerHostname allow to control hostname case sensitivity This addresses the behavior change introduced in v1.11.0 and reverted in v1.14.1. By default, hostnames are not lowercased. --- .changelog/236.txt | 3 +++ providers/aix/host_aix_ppc64.go | 6 ++++++ providers/darwin/host_darwin.go | 6 ++++++ providers/doc.go | 30 +++++++++++++++++++++++++++ providers/linux/host_linux.go | 9 +++++++- providers/lowerhostname.go | 34 +++++++++++++++++++++++++++++++ providers/shared/fqdn.go | 6 ++++++ providers/shared/fqdn_test.go | 23 +++++++++++++++++---- providers/windows/host_windows.go | 7 ++++++- 9 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 .changelog/236.txt create mode 100644 providers/doc.go create mode 100644 providers/lowerhostname.go diff --git a/.changelog/236.txt b/.changelog/236.txt new file mode 100644 index 0000000..9d4ece1 --- /dev/null +++ b/.changelog/236.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +Allow to choose hostname and FQDN to be lowercased or not +``` diff --git a/providers/aix/host_aix_ppc64.go b/providers/aix/host_aix_ppc64.go index 9af09e5..9be0b04 100644 --- a/providers/aix/host_aix_ppc64.go +++ b/providers/aix/host_aix_ppc64.go @@ -34,9 +34,11 @@ import ( "errors" "fmt" "os" + "strings" "time" "github.com/elastic/go-sysinfo/internal/registry" + "github.com/elastic/go-sysinfo/providers" "github.com/elastic/go-sysinfo/providers/shared" "github.com/elastic/go-sysinfo/types" ) @@ -190,6 +192,10 @@ func (r *reader) hostname(h *host) { if r.addErr(err) { return } + + if providers.LowercaseHostname() { + v = strings.ToLower(v) + } h.info.Hostname = v } diff --git a/providers/darwin/host_darwin.go b/providers/darwin/host_darwin.go index 8b53eee..b3259b3 100644 --- a/providers/darwin/host_darwin.go +++ b/providers/darwin/host_darwin.go @@ -24,9 +24,11 @@ import ( "errors" "fmt" "os" + "strings" "time" "github.com/elastic/go-sysinfo/internal/registry" + "github.com/elastic/go-sysinfo/providers" "github.com/elastic/go-sysinfo/providers/shared" "github.com/elastic/go-sysinfo/types" ) @@ -225,6 +227,10 @@ func (r *reader) hostname(h *host) { if r.addErr(err) { return } + + if providers.LowercaseHostname() { + v = strings.ToLower(v) + } h.info.Hostname = v } diff --git a/providers/doc.go b/providers/doc.go new file mode 100644 index 0000000..9ec0afe --- /dev/null +++ b/providers/doc.go @@ -0,0 +1,30 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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 providers +// +// # Hostname Behavior +// +// Starting from version v1.11.0, the host provider started automatically +// lowercasing hostnames. This behavior was reverted in v1.14.1. +// +// To provide flexibility and allow users to control this behavior, the +// `LowercaseHostname` and `SetLowerHostname` functions were added. +// +// By default, hostnames are not lowercased. If you require hostnames to be +// lowercased, explicitly set this using `SetLowerHostname(true)`. +package providers diff --git a/providers/linux/host_linux.go b/providers/linux/host_linux.go index 24e72d0..152b77c 100644 --- a/providers/linux/host_linux.go +++ b/providers/linux/host_linux.go @@ -23,11 +23,13 @@ import ( "fmt" "os" "path/filepath" + "strings" "time" "github.com/prometheus/procfs" "github.com/elastic/go-sysinfo/internal/registry" + "github.com/elastic/go-sysinfo/providers" "github.com/elastic/go-sysinfo/providers/shared" "github.com/elastic/go-sysinfo/types" ) @@ -176,7 +178,8 @@ func newHost(fs procFS) (*host, error) { } type reader struct { - errs []error + errs []error + lowerHostname bool } func (r *reader) addErr(err error) bool { @@ -233,6 +236,10 @@ func (r *reader) hostname(h *host) { if r.addErr(err) { return } + + if providers.LowercaseHostname() { + v = strings.ToLower(v) + } h.info.Hostname = v } diff --git a/providers/lowerhostname.go b/providers/lowerhostname.go new file mode 100644 index 0000000..6612b10 --- /dev/null +++ b/providers/lowerhostname.go @@ -0,0 +1,34 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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 providers + +import "sync/atomic" + +var lowerHostname atomic.Bool + +// LowercaseHostname returns if the hostname should be lowercased or not. +func LowercaseHostname() bool { + return lowerHostname.Load() +} + +// SetLowerHostname instruct the host provider to lowercase the hostname. +// The LowercaseHostname and SetLowerHostname exist as a fix to allow the user +// to choose or not this behaviour introduced on v1.11.0 and reverted on v1.14.1. +func SetLowerHostname(lower bool) { + lowerHostname.Store(lower) +} diff --git a/providers/shared/fqdn.go b/providers/shared/fqdn.go index b8bb455..e257999 100644 --- a/providers/shared/fqdn.go +++ b/providers/shared/fqdn.go @@ -25,6 +25,8 @@ import ( "net" "os" "strings" + + "github.com/elastic/go-sysinfo/providers" ) // FQDNWithContext attempts to lookup the host's fully-qualified domain name and returns it. @@ -67,6 +69,10 @@ func fqdn(ctx context.Context, hostname string) (string, error) { if cname != "" { cname = strings.TrimSuffix(cname, ".") + if providers.LowercaseHostname() { + return strings.ToLower(cname), nil + } + // Go might lowercase the cname "for convenience". Therefore, if cname // is the same as hostname, return hostname as is. // See https://github.com/golang/go/blob/go1.22.5/src/net/hosts.go#L38 diff --git a/providers/shared/fqdn_test.go b/providers/shared/fqdn_test.go index ffddd5a..c5ac4a0 100644 --- a/providers/shared/fqdn_test.go +++ b/providers/shared/fqdn_test.go @@ -26,14 +26,22 @@ import ( "time" "github.com/stretchr/testify/require" + + "github.com/elastic/go-sysinfo/providers" ) func TestFQDN(t *testing.T) { + lowercaseHostname := providers.LowercaseHostname() + defer func() { + providers.SetLowerHostname(lowercaseHostname) + }() + tests := map[string]struct { - osHostname string - expectedFQDN string - expectedErrRegex string - timeout time.Duration + lowercaseHostname bool + osHostname string + expectedFQDN string + expectedErrRegex string + timeout time.Duration }{ // This test case depends on network, particularly DNS, // being available. If it starts to fail often enough @@ -59,6 +67,12 @@ func TestFQDN(t *testing.T) { expectedFQDN: "eLaSTic.co", expectedErrRegex: "", }, + "long_mixed_case_hostname_lowercaseHostname": { + lowercaseHostname: true, + osHostname: "eLaSTic.co", + expectedFQDN: "elastic.co", + expectedErrRegex: "", + }, "nonexistent_timeout": { osHostname: "foobarbaz", expectedFQDN: "", @@ -77,6 +91,7 @@ func TestFQDN(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() + providers.SetLowerHostname(test.lowercaseHostname) actualFQDN, err := fqdn(ctx, test.osHostname) require.Equal(t, test.expectedFQDN, actualFQDN) diff --git a/providers/windows/host_windows.go b/providers/windows/host_windows.go index ed94881..c90bced 100644 --- a/providers/windows/host_windows.go +++ b/providers/windows/host_windows.go @@ -28,9 +28,10 @@ import ( stdwindows "golang.org/x/sys/windows" - windows "github.com/elastic/go-windows" + "github.com/elastic/go-windows" "github.com/elastic/go-sysinfo/internal/registry" + "github.com/elastic/go-sysinfo/providers" "github.com/elastic/go-sysinfo/providers/shared" "github.com/elastic/go-sysinfo/types" ) @@ -161,6 +162,10 @@ func (r *reader) hostname(h *host) { if r.addErr(err) { return } + + if providers.LowercaseHostname() { + v = strings.ToLower(v) + } h.info.Hostname = v } From 421e72c9b1dd0e38b5c1f9c2f8c3740d18a44bd0 Mon Sep 17 00:00:00 2001 From: Anderson Queiroz Date: Fri, 23 Aug 2024 12:13:05 +0200 Subject: [PATCH 2/5] another approach --- internal/registry/registry.go | 3 +- providers/aix/host_aix_ppc64.go | 40 ++++++++++++------ providers/aix/process_aix_ppc64.go | 5 +-- providers/darwin/host_darwin.go | 36 +++++++++++----- providers/doc.go | 30 -------------- ...host_fqdn_integration_docker_linux_test.go | 22 +++++++++- .../linux/host_fqdn_integration_linux_test.go | 4 +- providers/linux/host_linux.go | 41 ++++++++++++------- providers/linux/host_linux_test.go | 10 ++--- providers/lowerhostname.go | 34 --------------- providers/shared/fqdn.go | 6 --- providers/shared/fqdn_test.go | 23 ++--------- providers/windows/host_windows.go | 36 +++++++++++----- system.go | 6 +++ 14 files changed, 144 insertions(+), 152 deletions(-) delete mode 100644 providers/doc.go delete mode 100644 providers/lowerhostname.go diff --git a/internal/registry/registry.go b/internal/registry/registry.go index 00a9d2c..4021631 100644 --- a/internal/registry/registry.go +++ b/internal/registry/registry.go @@ -41,7 +41,8 @@ type ProcessProvider interface { } type ProviderOptions struct { - Hostfs string + Hostfs string + LowerHostname bool } var ( diff --git a/providers/aix/host_aix_ppc64.go b/providers/aix/host_aix_ppc64.go index 9be0b04..b2526d7 100644 --- a/providers/aix/host_aix_ppc64.go +++ b/providers/aix/host_aix_ppc64.go @@ -38,7 +38,6 @@ import ( "time" "github.com/elastic/go-sysinfo/internal/registry" - "github.com/elastic/go-sysinfo/providers" "github.com/elastic/go-sysinfo/providers/shared" "github.com/elastic/go-sysinfo/types" ) @@ -47,18 +46,27 @@ import ( // As cgo will return some psinfo's fields with *byte, binary.Read will refuse this type. func init() { - registry.Register(aixSystem{}) + // register wrappers that implement the HostFS versions of the ProcessProvider and HostProvider + registry.Register(func(opts registry.ProviderOptions) registry.HostProvider { + return aixSystem{lowerHostname: opts.LowerHostname} + }) + registry.Register(func(opts registry.ProviderOptions) registry.ProcessProvider { + return aixSystem{lowerHostname: opts.LowerHostname} + }) } -type aixSystem struct{} +type aixSystem struct { + lowerHostname bool +} // Host returns a new AIX host. -func (aixSystem) Host() (types.Host, error) { - return newHost() +func (a aixSystem) Host() (types.Host, error) { + return newHost(a.lowerHostname) } type host struct { - info types.HostInfo + info types.HostInfo + lowerHostname bool } // Architecture returns the architecture of the host @@ -71,7 +79,7 @@ func (h *host) Info() types.HostInfo { return h.info } -// Info returns the current CPU usage of the host. +// CPUTime returns the current CPU usage of the host. func (*host) CPUTime() (types.CPUTimes, error) { clock := uint64(C.sysconf(C._SC_CLK_TCK)) tick2nsec := func(val uint64) uint64 { @@ -129,16 +137,21 @@ func (*host) Memory() (*types.HostMemoryInfo, error) { } func (h *host) FQDNWithContext(ctx context.Context) (string, error) { - return shared.FQDNWithContext(ctx) + fqdn, err := shared.FQDNWithContext(ctx) + if h.lowerHostname { + fqdn = strings.ToLower(fqdn) + } + + return fqdn, err } func (h *host) FQDN() (string, error) { return h.FQDNWithContext(context.Background()) } -func newHost() (*host, error) { - h := &host{} - r := &reader{} +func newHost(lowerHostname bool) (*host, error) { + h := &host{lowerHostname: lowerHostname} + r := &reader{lowerHostname: lowerHostname} r.architecture(h) r.bootTime(h) r.hostname(h) @@ -151,7 +164,8 @@ func newHost() (*host, error) { } type reader struct { - errs []error + errs []error + lowerHostname bool } func (r *reader) addErr(err error) bool { @@ -193,7 +207,7 @@ func (r *reader) hostname(h *host) { return } - if providers.LowercaseHostname() { + if r.lowerHostname { v = strings.ToLower(v) } h.info.Hostname = v diff --git a/providers/aix/process_aix_ppc64.go b/providers/aix/process_aix_ppc64.go index 6fb669d..bd0e756 100644 --- a/providers/aix/process_aix_ppc64.go +++ b/providers/aix/process_aix_ppc64.go @@ -35,7 +35,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "os" "path/filepath" "strconv" @@ -77,8 +76,8 @@ func (aixSystem) Process(pid int) (types.Process, error) { } // Self returns the current process. -func (s aixSystem) Self() (types.Process, error) { - return s.Process(os.Getpid()) +func (a aixSystem) Self() (types.Process, error) { + return a.Process(os.Getpid()) } type process struct { diff --git a/providers/darwin/host_darwin.go b/providers/darwin/host_darwin.go index b3259b3..e8cf4f3 100644 --- a/providers/darwin/host_darwin.go +++ b/providers/darwin/host_darwin.go @@ -28,23 +28,31 @@ import ( "time" "github.com/elastic/go-sysinfo/internal/registry" - "github.com/elastic/go-sysinfo/providers" "github.com/elastic/go-sysinfo/providers/shared" "github.com/elastic/go-sysinfo/types" ) func init() { - registry.Register(darwinSystem{}) + // register wrappers that implement the HostFS versions of the ProcessProvider and HostProvider + registry.Register(func(opts registry.ProviderOptions) registry.HostProvider { + return darwinSystem{lowerHostname: opts.LowerHostname} + }) + registry.Register(func(opts registry.ProviderOptions) registry.ProcessProvider { + return darwinSystem{lowerHostname: opts.LowerHostname} + }) } -type darwinSystem struct{} +type darwinSystem struct { + lowerHostname bool +} func (s darwinSystem) Host() (types.Host, error) { - return newHost() + return newHost(s.lowerHostname) } type host struct { - info types.HostInfo + info types.HostInfo + lowerHostname bool } func (h *host) Info() types.HostInfo { @@ -140,7 +148,12 @@ func (h *host) Memory() (*types.HostMemoryInfo, error) { } func (h *host) FQDNWithContext(ctx context.Context) (string, error) { - return shared.FQDNWithContext(ctx) + fqdn, err := shared.FQDNWithContext(ctx) + if h.lowerHostname { + fqdn = strings.ToLower(fqdn) + } + + return fqdn, err } func (h *host) FQDN() (string, error) { @@ -162,9 +175,9 @@ func (h *host) LoadAverage() (*types.LoadAverageInfo, error) { }, nil } -func newHost() (*host, error) { - h := &host{} - r := &reader{} +func newHost(lowerHostname bool) (*host, error) { + h := &host{lowerHostname: lowerHostname} + r := &reader{lowerHostname: lowerHostname} r.architecture(h) r.nativeArchitecture(h) r.bootTime(h) @@ -178,7 +191,8 @@ func newHost() (*host, error) { } type reader struct { - errs []error + errs []error + lowerHostname bool } func (r *reader) addErr(err error) bool { @@ -228,7 +242,7 @@ func (r *reader) hostname(h *host) { return } - if providers.LowercaseHostname() { + if r.lowerHostname { v = strings.ToLower(v) } h.info.Hostname = v diff --git a/providers/doc.go b/providers/doc.go deleted file mode 100644 index 9ec0afe..0000000 --- a/providers/doc.go +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed to Elasticsearch B.V. under one or more contributor -// license agreements. See the NOTICE file distributed with -// this work for additional information regarding copyright -// ownership. Elasticsearch B.V. licenses this file to you 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 providers -// -// # Hostname Behavior -// -// Starting from version v1.11.0, the host provider started automatically -// lowercasing hostnames. This behavior was reverted in v1.14.1. -// -// To provide flexibility and allow users to control this behavior, the -// `LowercaseHostname` and `SetLowerHostname` functions were added. -// -// By default, hostnames are not lowercased. If you require hostnames to be -// lowercased, explicitly set this using `SetLowerHostname(true)`. -package providers diff --git a/providers/linux/host_fqdn_integration_docker_linux_test.go b/providers/linux/host_fqdn_integration_docker_linux_test.go index ba67eb4..6457408 100644 --- a/providers/linux/host_fqdn_integration_docker_linux_test.go +++ b/providers/linux/host_fqdn_integration_docker_linux_test.go @@ -22,6 +22,7 @@ package linux import ( "context" "fmt" + "strings" "testing" "time" @@ -29,7 +30,7 @@ import ( ) func TestHost_FQDN_set(t *testing.T) { - host, err := newLinuxSystem("").Host() + host, err := newLinuxSystem("", false).Host() if err != nil { t.Fatal(fmt.Errorf("could not get host information: %w", err)) } @@ -44,8 +45,25 @@ func TestHost_FQDN_set(t *testing.T) { } } +func TestHost_FQDN_set_lowerHostname(t *testing.T) { + want := strings.ToLower(wantFQDN) + host, err := newLinuxSystem("", true).Host() + if err != nil { + t.Fatal(fmt.Errorf("could not get host information: %w", err)) + } + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + gotFQDN, err := host.FQDNWithContext(ctx) + require.NoError(t, err) + if gotFQDN != want { + t.Errorf("got FQDN %q, want: %q", gotFQDN, want) + } +} + func TestHost_FQDN_not_set(t *testing.T) { - host, err := newLinuxSystem("").Host() + host, err := newLinuxSystem("", false).Host() if err != nil { t.Fatal(fmt.Errorf("could not get host information: %w", err)) } diff --git a/providers/linux/host_fqdn_integration_linux_test.go b/providers/linux/host_fqdn_integration_linux_test.go index b6c6175..9b742a4 100644 --- a/providers/linux/host_fqdn_integration_linux_test.go +++ b/providers/linux/host_fqdn_integration_linux_test.go @@ -31,8 +31,8 @@ import ( ) const ( - wantHostname = "hostname" - wantDomain = "some.domain" + wantHostname = "hostName" + wantDomain = "some.Domain" wantFQDN = wantHostname + "." + wantDomain ) diff --git a/providers/linux/host_linux.go b/providers/linux/host_linux.go index 152b77c..49ef943 100644 --- a/providers/linux/host_linux.go +++ b/providers/linux/host_linux.go @@ -29,37 +29,43 @@ import ( "github.com/prometheus/procfs" "github.com/elastic/go-sysinfo/internal/registry" - "github.com/elastic/go-sysinfo/providers" "github.com/elastic/go-sysinfo/providers/shared" "github.com/elastic/go-sysinfo/types" ) func init() { // register wrappers that implement the HostFS versions of the ProcessProvider and HostProvider - registry.Register(func(opts registry.ProviderOptions) registry.HostProvider { return newLinuxSystem(opts.Hostfs) }) - registry.Register(func(opts registry.ProviderOptions) registry.ProcessProvider { return newLinuxSystem(opts.Hostfs) }) + registry.Register(func(opts registry.ProviderOptions) registry.HostProvider { + return newLinuxSystem(opts.Hostfs, opts.LowerHostname) + }) + registry.Register(func(opts registry.ProviderOptions) registry.ProcessProvider { + return newLinuxSystem(opts.Hostfs, opts.LowerHostname) + }) } type linuxSystem struct { - procFS procFS + procFS procFS + lowerHostname bool } -func newLinuxSystem(hostFS string) linuxSystem { +func newLinuxSystem(hostFS string, lowerHostname bool) linuxSystem { mountPoint := filepath.Join(hostFS, procfs.DefaultMountPoint) fs, _ := procfs.NewFS(mountPoint) return linuxSystem{ - procFS: procFS{FS: fs, mountPoint: mountPoint, baseMount: hostFS}, + procFS: procFS{FS: fs, mountPoint: mountPoint, baseMount: hostFS}, + lowerHostname: lowerHostname, } } func (s linuxSystem) Host() (types.Host, error) { - return newHost(s.procFS) + return newHost(s.procFS, s.lowerHostname) } type host struct { - procFS procFS - stat procfs.Stat - info types.HostInfo + procFS procFS + stat procfs.Stat + info types.HostInfo + lowerHostname bool } // Info returns host info @@ -79,7 +85,12 @@ func (h *host) Memory() (*types.HostMemoryInfo, error) { } func (h *host) FQDNWithContext(ctx context.Context) (string, error) { - return shared.FQDNWithContext(ctx) + fqdn, err := shared.FQDNWithContext(ctx) + if h.lowerHostname { + fqdn = strings.ToLower(fqdn) + } + + return fqdn, err } func (h *host) FQDN() (string, error) { @@ -155,14 +166,14 @@ func (h *host) CPUTime() (types.CPUTimes, error) { }, nil } -func newHost(fs procFS) (*host, error) { +func newHost(fs procFS, lowerHostname bool) (*host, error) { stat, err := fs.Stat() if err != nil { return nil, fmt.Errorf("failed to read proc stat: %w", err) } - h := &host{stat: stat, procFS: fs} - r := &reader{} + h := &host{stat: stat, procFS: fs, lowerHostname: lowerHostname} + r := &reader{lowerHostname: lowerHostname} r.architecture(h) r.nativeArchitecture(h) r.bootTime(h) @@ -237,7 +248,7 @@ func (r *reader) hostname(h *host) { return } - if providers.LowercaseHostname() { + if r.lowerHostname { v = strings.ToLower(v) } h.info.Hostname = v diff --git a/providers/linux/host_linux_test.go b/providers/linux/host_linux_test.go index 97d728d..889ad34 100644 --- a/providers/linux/host_linux_test.go +++ b/providers/linux/host_linux_test.go @@ -30,7 +30,7 @@ import ( var _ registry.HostProvider = linuxSystem{} func TestHost(t *testing.T) { - host, err := newLinuxSystem("").Host() + host, err := newLinuxSystem("", false).Host() if err != nil { t.Logf("could not get all host info: %v\n", err) } @@ -41,7 +41,7 @@ func TestHost(t *testing.T) { } func TestHostMemoryInfo(t *testing.T) { - host, err := newLinuxSystem("testdata/ubuntu1710").Host() + host, err := newLinuxSystem("testdata/ubuntu1710", false).Host() if err != nil { t.Fatal(err) } @@ -56,7 +56,7 @@ func TestHostMemoryInfo(t *testing.T) { } func TestHostVMStat(t *testing.T) { - host, err := newLinuxSystem("testdata/ubuntu1710").Host() + host, err := newLinuxSystem("testdata/ubuntu1710", false).Host() if err != nil { t.Fatal(err) } @@ -73,7 +73,7 @@ func TestHostVMStat(t *testing.T) { } func TestHostLoadAverage(t *testing.T) { - host, err := newLinuxSystem("testdata/ubuntu1710").Host() + host, err := newLinuxSystem("testdata/ubuntu1710", false).Host() if err != nil { t.Fatal(err) } @@ -90,7 +90,7 @@ func TestHostLoadAverage(t *testing.T) { } func TestHostNetworkCounters(t *testing.T) { - host, err := newLinuxSystem("testdata/fedora30").Host() + host, err := newLinuxSystem("testdata/fedora30", false).Host() if err != nil { t.Fatal(err) } diff --git a/providers/lowerhostname.go b/providers/lowerhostname.go deleted file mode 100644 index 6612b10..0000000 --- a/providers/lowerhostname.go +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to Elasticsearch B.V. under one or more contributor -// license agreements. See the NOTICE file distributed with -// this work for additional information regarding copyright -// ownership. Elasticsearch B.V. licenses this file to you 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 providers - -import "sync/atomic" - -var lowerHostname atomic.Bool - -// LowercaseHostname returns if the hostname should be lowercased or not. -func LowercaseHostname() bool { - return lowerHostname.Load() -} - -// SetLowerHostname instruct the host provider to lowercase the hostname. -// The LowercaseHostname and SetLowerHostname exist as a fix to allow the user -// to choose or not this behaviour introduced on v1.11.0 and reverted on v1.14.1. -func SetLowerHostname(lower bool) { - lowerHostname.Store(lower) -} diff --git a/providers/shared/fqdn.go b/providers/shared/fqdn.go index e257999..b8bb455 100644 --- a/providers/shared/fqdn.go +++ b/providers/shared/fqdn.go @@ -25,8 +25,6 @@ import ( "net" "os" "strings" - - "github.com/elastic/go-sysinfo/providers" ) // FQDNWithContext attempts to lookup the host's fully-qualified domain name and returns it. @@ -69,10 +67,6 @@ func fqdn(ctx context.Context, hostname string) (string, error) { if cname != "" { cname = strings.TrimSuffix(cname, ".") - if providers.LowercaseHostname() { - return strings.ToLower(cname), nil - } - // Go might lowercase the cname "for convenience". Therefore, if cname // is the same as hostname, return hostname as is. // See https://github.com/golang/go/blob/go1.22.5/src/net/hosts.go#L38 diff --git a/providers/shared/fqdn_test.go b/providers/shared/fqdn_test.go index c5ac4a0..ffddd5a 100644 --- a/providers/shared/fqdn_test.go +++ b/providers/shared/fqdn_test.go @@ -26,22 +26,14 @@ import ( "time" "github.com/stretchr/testify/require" - - "github.com/elastic/go-sysinfo/providers" ) func TestFQDN(t *testing.T) { - lowercaseHostname := providers.LowercaseHostname() - defer func() { - providers.SetLowerHostname(lowercaseHostname) - }() - tests := map[string]struct { - lowercaseHostname bool - osHostname string - expectedFQDN string - expectedErrRegex string - timeout time.Duration + osHostname string + expectedFQDN string + expectedErrRegex string + timeout time.Duration }{ // This test case depends on network, particularly DNS, // being available. If it starts to fail often enough @@ -67,12 +59,6 @@ func TestFQDN(t *testing.T) { expectedFQDN: "eLaSTic.co", expectedErrRegex: "", }, - "long_mixed_case_hostname_lowercaseHostname": { - lowercaseHostname: true, - osHostname: "eLaSTic.co", - expectedFQDN: "elastic.co", - expectedErrRegex: "", - }, "nonexistent_timeout": { osHostname: "foobarbaz", expectedFQDN: "", @@ -91,7 +77,6 @@ func TestFQDN(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() - providers.SetLowerHostname(test.lowercaseHostname) actualFQDN, err := fqdn(ctx, test.osHostname) require.Equal(t, test.expectedFQDN, actualFQDN) diff --git a/providers/windows/host_windows.go b/providers/windows/host_windows.go index c90bced..06cb49e 100644 --- a/providers/windows/host_windows.go +++ b/providers/windows/host_windows.go @@ -31,23 +31,31 @@ import ( "github.com/elastic/go-windows" "github.com/elastic/go-sysinfo/internal/registry" - "github.com/elastic/go-sysinfo/providers" "github.com/elastic/go-sysinfo/providers/shared" "github.com/elastic/go-sysinfo/types" ) func init() { - registry.Register(windowsSystem{}) + // register wrappers that implement the HostFS versions of the ProcessProvider and HostProvider + registry.Register(func(opts registry.ProviderOptions) registry.HostProvider { + return windowsSystem{lowerHostname: opts.LowerHostname} + }) + registry.Register(func(opts registry.ProviderOptions) registry.ProcessProvider { + return windowsSystem{lowerHostname: opts.LowerHostname} + }) } -type windowsSystem struct{} +type windowsSystem struct { + lowerHostname bool +} func (s windowsSystem) Host() (types.Host, error) { - return newHost() + return newHost(s.lowerHostname) } type host struct { - info types.HostInfo + info types.HostInfo + lowerHostname bool } func (h *host) Info() types.HostInfo { @@ -90,16 +98,21 @@ func (h *host) FQDNWithContext(_ context.Context) (string, error) { return "", fmt.Errorf("could not get windows FQDN: %s", err) } - return strings.TrimSuffix(fqdn, "."), nil + fqdn = strings.TrimSuffix(fqdn, ".") + if h.lowerHostname { + fqdn = strings.ToLower(fqdn) + } + + return fqdn, nil } func (h *host) FQDN() (string, error) { return h.FQDNWithContext(context.Background()) } -func newHost() (*host, error) { - h := &host{} - r := &reader{} +func newHost(lowerHostname bool) (*host, error) { + h := &host{lowerHostname: lowerHostname} + r := &reader{lowerHostname: lowerHostname} r.architecture(h) r.nativeArchitecture(h) r.bootTime(h) @@ -113,7 +126,8 @@ func newHost() (*host, error) { } type reader struct { - errs []error + errs []error + lowerHostname bool } func (r *reader) addErr(err error) bool { @@ -163,7 +177,7 @@ func (r *reader) hostname(h *host) { return } - if providers.LowercaseHostname() { + if r.lowerHostname { v = strings.ToLower(v) } h.info.Hostname = v diff --git a/system.go b/system.go index e2edfe2..ff765d2 100644 --- a/system.go +++ b/system.go @@ -45,6 +45,12 @@ func WithHostFS(hostfs string) ProviderOption { } } +func WithLowerHostname() ProviderOption { + return func(po *registry.ProviderOptions) { + po.LowerHostname = true + } +} + // Go returns information about the Go runtime. func Go() types.GoInfo { return types.GoInfo{ From 0d81bd7149cdd77225a7a136549548c46ffd59c4 Mon Sep 17 00:00:00 2001 From: Anderson Queiroz Date: Fri, 23 Aug 2024 12:16:28 +0200 Subject: [PATCH 3/5] wee fix --- providers/linux/process_linux_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/linux/process_linux_test.go b/providers/linux/process_linux_test.go index f545101..c24dd17 100644 --- a/providers/linux/process_linux_test.go +++ b/providers/linux/process_linux_test.go @@ -32,7 +32,7 @@ var ( ) func TestProcessNetstat(t *testing.T) { - proc, err := newLinuxSystem("").Self() + proc, err := newLinuxSystem("", false).Self() if err != nil { t.Fatal(err) } From 95b728f289779bd40d045daff5af6b76c42d9cd7 Mon Sep 17 00:00:00 2001 From: Anderson Queiroz Date: Fri, 23 Aug 2024 14:08:10 +0200 Subject: [PATCH 4/5] undo linux docker test --- .../host_fqdn_integration_docker_linux_test.go | 18 ------------------ .../linux/host_fqdn_integration_linux_test.go | 4 ++-- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/providers/linux/host_fqdn_integration_docker_linux_test.go b/providers/linux/host_fqdn_integration_docker_linux_test.go index 6457408..9216fd0 100644 --- a/providers/linux/host_fqdn_integration_docker_linux_test.go +++ b/providers/linux/host_fqdn_integration_docker_linux_test.go @@ -22,7 +22,6 @@ package linux import ( "context" "fmt" - "strings" "testing" "time" @@ -45,23 +44,6 @@ func TestHost_FQDN_set(t *testing.T) { } } -func TestHost_FQDN_set_lowerHostname(t *testing.T) { - want := strings.ToLower(wantFQDN) - host, err := newLinuxSystem("", true).Host() - if err != nil { - t.Fatal(fmt.Errorf("could not get host information: %w", err)) - } - - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - gotFQDN, err := host.FQDNWithContext(ctx) - require.NoError(t, err) - if gotFQDN != want { - t.Errorf("got FQDN %q, want: %q", gotFQDN, want) - } -} - func TestHost_FQDN_not_set(t *testing.T) { host, err := newLinuxSystem("", false).Host() if err != nil { diff --git a/providers/linux/host_fqdn_integration_linux_test.go b/providers/linux/host_fqdn_integration_linux_test.go index 9b742a4..b6c6175 100644 --- a/providers/linux/host_fqdn_integration_linux_test.go +++ b/providers/linux/host_fqdn_integration_linux_test.go @@ -31,8 +31,8 @@ import ( ) const ( - wantHostname = "hostName" - wantDomain = "some.Domain" + wantHostname = "hostname" + wantDomain = "some.domain" wantFQDN = wantHostname + "." + wantDomain ) From 199943165104753b55cebcaff9255757333ebfd0 Mon Sep 17 00:00:00 2001 From: Anderson Queiroz Date: Fri, 23 Aug 2024 15:01:50 +0200 Subject: [PATCH 5/5] add more docker tests --- ...host_fqdn_integration_docker_linux_test.go | 33 +++++++++++++++++++ .../linux/host_fqdn_integration_linux_test.go | 19 ++++++++--- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/providers/linux/host_fqdn_integration_docker_linux_test.go b/providers/linux/host_fqdn_integration_docker_linux_test.go index 9216fd0..62dffae 100644 --- a/providers/linux/host_fqdn_integration_docker_linux_test.go +++ b/providers/linux/host_fqdn_integration_docker_linux_test.go @@ -28,6 +28,39 @@ import ( "github.com/stretchr/testify/require" ) +func TestHost_hostname(t *testing.T) { + testCases := []struct { + name string + want string + lowercase bool + }{ + { + name: "hostname", + want: "hostName", + lowercase: false, + }, + { + name: "lowercase hostname", + want: "hostname", + lowercase: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + host, err := newLinuxSystem("", tc.lowercase).Host() + if err != nil { + t.Fatalf("could not get host info: %v\n", err) + } + + got := host.Info() + if got.Hostname != tc.want { + t.Errorf("got hostname %q; want hostname %q", + got.Hostname, tc.want) + } + }) + } +} func TestHost_FQDN_set(t *testing.T) { host, err := newLinuxSystem("", false).Host() if err != nil { diff --git a/providers/linux/host_fqdn_integration_linux_test.go b/providers/linux/host_fqdn_integration_linux_test.go index b6c6175..615acf1 100644 --- a/providers/linux/host_fqdn_integration_linux_test.go +++ b/providers/linux/host_fqdn_integration_linux_test.go @@ -31,12 +31,13 @@ import ( ) const ( - wantHostname = "hostname" - wantDomain = "some.domain" - wantFQDN = wantHostname + "." + wantDomain + wantHostnameMixedCase = "hostName" + wantHostname = "hostname" + wantDomain = "some.domain" + wantFQDN = wantHostname + "." + wantDomain ) -func TestHost_FQDN(t *testing.T) { +func TestHost_Docker(t *testing.T) { if _, err := execabs.LookPath("docker"); err != nil { t.Skipf("Skipping because docker was not found: %v", err) } @@ -77,6 +78,16 @@ func TestHost_FQDN(t *testing.T) { "./providers/linux", }, }, + { + name: "TestHost_hostname", + Hostname: wantHostnameMixedCase, + Cmd: []string{ + "go", "test", "-v", "-count", "1", + "-tags", "integration,docker", + "-run", "^TestHost_FQDN_not_set$", + "./providers/linux", + }, + }, } for _, tc := range tcs {