Skip to content

Commit 7ea72a6

Browse files
authored
Merge branch 'main' into dependabot/go_modules/github.com/elastic/elastic-transport-go/v8-8.4.0
2 parents decfae2 + 82efe13 commit 7ea72a6

File tree

11 files changed

+346
-33
lines changed

11 files changed

+346
-33
lines changed

.mergify.yml

+13
Original file line numberDiff line numberDiff line change
@@ -293,3 +293,16 @@ pull_request_rules:
293293
labels:
294294
- "backport"
295295
title: "[{{ destination_branch }}](backport #{{ number }}) {{ title }}"
296+
- name: backport patches to 8.13 branch
297+
conditions:
298+
- merged
299+
- label=backport-v8.13.0
300+
actions:
301+
backport:
302+
assignees:
303+
- "{{ author }}"
304+
branches:
305+
- "8.13"
306+
labels:
307+
- "backport"
308+
title: "[{{ destination_branch }}](backport #{{ number }}) {{ title }}"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Kind can be one of:
2+
# - breaking-change: a change to previously-documented behavior
3+
# - deprecation: functionality that is being removed in a later release
4+
# - bug-fix: fixes a problem in a previous version
5+
# - enhancement: extends functionality but does not break or fix existing behavior
6+
# - feature: new functionality
7+
# - known-issue: problems that we are aware of in a given version
8+
# - security: impacts on the security of a product or a user’s deployment.
9+
# - upgrade: important information for someone upgrading from a prior version
10+
# - other: does not fit into any of the other categories
11+
kind: bug-fix
12+
13+
# Change summary; a 80ish characters long description of the change.
14+
summary: Set timeout of 1 minute for FQDN lookups
15+
16+
# Long description; in case the summary is not enough to describe the change
17+
# this field accommodate a description without length limits.
18+
# NOTE: This field will be rendered only for breaking-change and known-issue kinds at the moment.
19+
#description:
20+
21+
# Affected component; usually one of "elastic-agent", "fleet-server", "filebeat", "metricbeat", "auditbeat", "all", etc.
22+
component: elastic-agent
23+
24+
# PR URL; optional; the PR number that added the changeset.
25+
# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added.
26+
# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number.
27+
# Please provide it if you are adding a fragment for a different PR.
28+
pr: https://github.com/elastic/elastic-agent/pull/4147
29+
30+
# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of).
31+
# If not present is automatically filled by the tooling with the issue linked to the PR number.
32+
#issue: https://github.com/owner/repo/1234
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Kind can be one of:
2+
# - breaking-change: a change to previously-documented behavior
3+
# - deprecation: functionality that is being removed in a later release
4+
# - bug-fix: fixes a problem in a previous version
5+
# - enhancement: extends functionality but does not break or fix existing behavior
6+
# - feature: new functionality
7+
# - known-issue: problems that we are aware of in a given version
8+
# - security: impacts on the security of a product or a user’s deployment.
9+
# - upgrade: important information for someone upgrading from a prior version
10+
# - other: does not fit into any of the other categories
11+
kind: bug-fix
12+
13+
# Change summary; a 80ish characters long description of the change.
14+
summary: On Windows make sure the service is stopped before uninstalling.
15+
16+
# Long description; in case the summary is not enough to describe the change
17+
# this field accommodate a description without length limits.
18+
# NOTE: This field will be rendered only for breaking-change and known-issue kinds at the moment.
19+
#description:
20+
21+
# Affected component; a word indicating the component this changeset affects.
22+
component: elastic-agent
23+
24+
# PR URL; optional; the PR number that added the changeset.
25+
# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added.
26+
# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number.
27+
# Please provide it if you are adding a fragment for a different PR.
28+
#pr: https://github.com/owner/repo/1234
29+
30+
# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of).
31+
# If not present is automatically filled by the tooling with the issue linked to the PR number.
32+
#issue: https://github.com/owner/repo/1234

internal/pkg/agent/application/info/agent_metadata.go

+5-19
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@ import (
88
"context"
99
"fmt"
1010

11+
"github.com/elastic/elastic-agent/pkg/features"
12+
1113
"runtime"
1214
"strings"
1315

1416
"github.com/elastic/elastic-agent/internal/pkg/agent/application/paths"
1517
"github.com/elastic/elastic-agent/internal/pkg/agent/errors"
1618
"github.com/elastic/elastic-agent/internal/pkg/release"
19+
"github.com/elastic/elastic-agent/internal/pkg/util"
1720
"github.com/elastic/elastic-agent/pkg/core/logger"
18-
"github.com/elastic/elastic-agent/pkg/features"
1921

2022
"github.com/elastic/go-sysinfo"
2123
"github.com/elastic/go-sysinfo/types"
@@ -149,15 +151,7 @@ func (i *AgentInfo) ECSMetadata(l *logger.Logger) (*ECSMeta, error) {
149151
}
150152

151153
info := sysInfo.Info()
152-
hostname := info.Hostname
153-
if features.FQDN() {
154-
fqdn, err := sysInfo.FQDN()
155-
if err != nil {
156-
l.Debugf("unable to lookup FQDN: %s, using hostname = %s", err.Error(), hostname)
157-
} else {
158-
hostname = fqdn
159-
}
160-
}
154+
hostname := util.GetHostName(features.FQDN(), info, sysInfo, l)
161155

162156
return &ECSMeta{
163157
Elastic: &ElasticECSMeta{
@@ -205,15 +199,7 @@ func (i *AgentInfo) ECSMetadataFlatMap(l *logger.Logger) (map[string]interface{}
205199
}
206200

207201
info := sysInfo.Info()
208-
hostname := info.Hostname
209-
if features.FQDN() {
210-
fqdn, err := sysInfo.FQDN()
211-
if err != nil {
212-
l.Debugf("unable to lookup FQDN: %s, using hostname = %s", err.Error(), hostname)
213-
} else {
214-
hostname = fqdn
215-
}
216-
}
202+
hostname := util.GetHostName(features.FQDN(), info, sysInfo, l)
217203

218204
// Agent
219205
meta[agentIDKey] = i.agentID

internal/pkg/agent/install/uninstall.go

+14-2
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,25 @@ func Uninstall(cfgFile, topPath, uninstallToken string, log *logp.Logger, pt *pr
5454
if status == service.StatusRunning {
5555
err := svc.Stop()
5656
if err != nil {
57-
pt.Describe("Failed to stop service")
57+
pt.Describe("Failed to issue stop service")
5858
return aerrors.New(
5959
err,
60-
fmt.Sprintf("failed to stop service (%s)", paths.ServiceName),
60+
fmt.Sprintf("failed to issue stop service (%s)", paths.ServiceName),
6161
aerrors.M("service", paths.ServiceName))
6262
}
6363
}
64+
// The kardianos service manager can't tell the difference
65+
// between 'Stopped' and 'StopPending' on Windows, so make
66+
// sure the service is stopped.
67+
err = isStopped(30*time.Second, 250*time.Millisecond, paths.ServiceName)
68+
if err != nil {
69+
pt.Describe("Failed to complete stop of service")
70+
return aerrors.New(
71+
err,
72+
fmt.Sprintf("failed to complete stop service (%s)", paths.ServiceName),
73+
aerrors.M("service", paths.ServiceName))
74+
}
75+
6476
pt.Describe("Successfully stopped service")
6577

6678
// kill any running watcher
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2+
// or more contributor license agreements. Licensed under the Elastic License;
3+
// you may not use this file except in compliance with the Elastic License.
4+
5+
//go:build !windows
6+
7+
package install
8+
9+
import (
10+
"time"
11+
)
12+
13+
// isStopped waits until the service has stopped. On non Windows
14+
// systems this isn't necessary so just return.
15+
func isStopped(timeout time.Duration, interval time.Duration, service string) error {
16+
return nil
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2+
// or more contributor license agreements. Licensed under the Elastic License;
3+
// you may not use this file except in compliance with the Elastic License.
4+
5+
//go:build windows
6+
7+
package install
8+
9+
import (
10+
"fmt"
11+
"time"
12+
13+
"golang.org/x/sys/windows/svc"
14+
"golang.org/x/sys/windows/svc/mgr"
15+
)
16+
17+
// isStopped queries the Windows service manager to see if the state
18+
// of the service is stopped. It will repeat the query every
19+
// 'interval' until the 'timeout' is reached. It returns nil if the
20+
// system is stopped within the timeout period. An error is returned
21+
// if the service doesn't stop before the timeout or if there are
22+
// errors communicating with the service manager.
23+
func isStopped(timeout time.Duration, interval time.Duration, service string) error {
24+
var err error
25+
var status svc.Status
26+
27+
m, err := mgr.Connect()
28+
if err != nil {
29+
return fmt.Errorf("failed to connect to service manager: %w", err)
30+
}
31+
defer func() {
32+
_ = m.Disconnect()
33+
}()
34+
35+
s, err := m.OpenService(service)
36+
if err != nil {
37+
return fmt.Errorf("failed to open service (%s): %w", service, err)
38+
}
39+
defer s.Close()
40+
41+
ticker := time.NewTicker(interval)
42+
defer ticker.Stop()
43+
timer := time.NewTimer(timeout)
44+
defer timer.Stop()
45+
46+
for {
47+
select {
48+
case <-ticker.C:
49+
status, err = s.Query()
50+
if err != nil {
51+
return fmt.Errorf("error querying service (%s): %w", service, err)
52+
}
53+
if status.State == svc.Stopped {
54+
return nil
55+
}
56+
case <-timer.C:
57+
return fmt.Errorf("timed out after %s waiting for service (%s) to stop, last state was: %d", timeout, service, status.State)
58+
}
59+
}
60+
}

internal/pkg/composable/providers/host/host.go

+4-12
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ import (
1111
"runtime"
1212
"time"
1313

14-
"github.com/elastic/elastic-agent/pkg/features"
15-
"github.com/elastic/go-sysinfo"
16-
1714
"github.com/elastic/elastic-agent/internal/pkg/agent/errors"
1815
"github.com/elastic/elastic-agent/internal/pkg/composable"
1916
"github.com/elastic/elastic-agent/internal/pkg/config"
2017
corecomp "github.com/elastic/elastic-agent/internal/pkg/core/composable"
18+
"github.com/elastic/elastic-agent/internal/pkg/util"
2119
"github.com/elastic/elastic-agent/pkg/core/logger"
20+
"github.com/elastic/elastic-agent/pkg/features"
21+
"github.com/elastic/go-sysinfo"
2222
)
2323

2424
const (
@@ -137,15 +137,7 @@ func getHostInfo(log *logger.Logger) func() (map[string]interface{}, error) {
137137
}
138138

139139
info := sysInfo.Info()
140-
name := info.Hostname
141-
if features.FQDN() {
142-
fqdn, err := sysInfo.FQDN()
143-
if err != nil {
144-
log.Debugf("unable to lookup FQDN: %s, using hostname = %s", err.Error(), name)
145-
} else {
146-
name = fqdn
147-
}
148-
}
140+
name := util.GetHostName(features.FQDN(), info, sysInfo, log)
149141

150142
return map[string]interface{}{
151143
"id": info.UniqueID,

internal/pkg/util/host.go

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2+
// or more contributor license agreements. Licensed under the Elastic License;
3+
// you may not use this file except in compliance with the Elastic License.
4+
5+
package util
6+
7+
import (
8+
"context"
9+
"time"
10+
11+
"github.com/elastic/elastic-agent/pkg/core/logger"
12+
"github.com/elastic/go-sysinfo/types"
13+
)
14+
15+
// GetHostName returns the host's FQDN if the FDQN feature flag is enabled; otherwise, it
16+
// returns the OS-provided hostname.
17+
func GetHostName(isFqdnFeatureEnabled bool, hostInfo types.HostInfo, host types.Host, log *logger.Logger) string {
18+
if !isFqdnFeatureEnabled {
19+
return hostInfo.Hostname
20+
}
21+
22+
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
23+
defer cancel()
24+
25+
fqdn, err := host.FQDNWithContext(ctx)
26+
if err != nil {
27+
// If we are unable to lookup the FQDN, we fallback to the OS-provided hostname
28+
log.Debugf("unable to lookup FQDN: %s, using hostname = %s", err.Error(), hostInfo.Hostname)
29+
return hostInfo.Hostname
30+
}
31+
32+
return fqdn
33+
}

internal/pkg/util/host_test.go

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2+
// or more contributor license agreements. Licensed under the Elastic License;
3+
// you may not use this file except in compliance with the Elastic License.
4+
5+
package util
6+
7+
import (
8+
"context"
9+
"errors"
10+
"testing"
11+
12+
"github.com/elastic/elastic-agent-libs/logp"
13+
14+
"github.com/stretchr/testify/require"
15+
16+
"github.com/elastic/go-sysinfo/types"
17+
)
18+
19+
func TestGetHostName(t *testing.T) {
20+
cases := map[string]struct {
21+
fqdnFeatureEnabled bool
22+
hostInfo types.HostInfo
23+
host types.Host
24+
log *logp.Logger
25+
26+
expected string
27+
}{
28+
"fqdn_feature_disabled": {
29+
fqdnFeatureEnabled: false,
30+
hostInfo: types.HostInfo{Hostname: "foobar"},
31+
expected: "foobar",
32+
},
33+
"fqdn_lookup_fails": {
34+
fqdnFeatureEnabled: true,
35+
hostInfo: types.HostInfo{Hostname: "foobar"},
36+
host: &mockHost{
37+
fqdn: "",
38+
fqdnErr: errors.New("fqdn lookup failed while testing"),
39+
},
40+
log: logp.NewLogger("testing"),
41+
expected: "foobar",
42+
},
43+
"fqdn_lookup_succeeds": {
44+
fqdnFeatureEnabled: true,
45+
hostInfo: types.HostInfo{Hostname: "foobar"},
46+
host: &mockHost{
47+
fqdn: "qux",
48+
fqdnErr: nil,
49+
},
50+
expected: "qux",
51+
},
52+
}
53+
54+
for name, test := range cases {
55+
t.Run(name, func(t *testing.T) {
56+
hostname := GetHostName(test.fqdnFeatureEnabled, test.hostInfo, test.host, test.log)
57+
require.Equal(t, test.expected, hostname)
58+
})
59+
}
60+
}
61+
62+
type mockHost struct {
63+
fqdn string
64+
fqdnErr error
65+
}
66+
67+
func (m *mockHost) CPUTime() (types.CPUTimes, error) { return types.CPUTimes{}, nil }
68+
func (m *mockHost) Info() types.HostInfo { return types.HostInfo{} }
69+
func (m *mockHost) Memory() (*types.HostMemoryInfo, error) { return nil, nil }
70+
func (m *mockHost) FQDNWithContext(ctx context.Context) (string, error) {
71+
return m.fqdn, m.fqdnErr
72+
}
73+
func (m *mockHost) FQDN() (string, error) { return m.FQDNWithContext(context.Background()) }

0 commit comments

Comments
 (0)