diff --git a/changelog/fragments/1697588586-upgrade-details-in-diagnostics.yaml b/changelog/fragments/1697588586-upgrade-details-in-diagnostics.yaml new file mode 100644 index 00000000000..ed415252d53 --- /dev/null +++ b/changelog/fragments/1697588586-upgrade-details-in-diagnostics.yaml @@ -0,0 +1,32 @@ +# Kind can be one of: +# - breaking-change: a change to previously-documented behavior +# - deprecation: functionality that is being removed in a later release +# - bug-fix: fixes a problem in a previous version +# - enhancement: extends functionality but does not break or fix existing behavior +# - feature: new functionality +# - known-issue: problems that we are aware of in a given version +# - security: impacts on the security of a product or a user’s deployment. +# - upgrade: important information for someone upgrading from a prior version +# - other: does not fit into any of the other categories +kind: enhancement + +# Change summary; a 80ish characters long description of the change. +summary: Include upgrade details in diagnostics bundle. + +# Long description; in case the summary is not enough to describe the change +# this field accommodate a description without length limits. +# NOTE: This field will be rendered only for breaking-change and known-issue kinds at the moment. +#description: + +# Affected component; usually one of "elastic-agent", "fleet-server", "filebeat", "metricbeat", "auditbeat", "all", etc. +component: elastic-agent + +# PR URL; optional; the PR number that added the changeset. +# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added. +# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number. +# Please provide it if you are adding a fragment for a different PR. +pr: https://github.com/elastic/elastic-agent/pull/3624 + +# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of). +# If not present is automatically filled by the tooling with the issue linked to the PR number. +#issue: https://github.com/owner/repo/1234 diff --git a/internal/pkg/agent/application/coordinator/coordinator.go b/internal/pkg/agent/application/coordinator/coordinator.go index 778232b91d8..4604313fb04 100644 --- a/internal/pkg/agent/application/coordinator/coordinator.go +++ b/internal/pkg/agent/application/coordinator/coordinator.go @@ -791,12 +791,13 @@ func (c *Coordinator) DiagnosticHooks() diagnostics.Hooks { State runtime.ComponentState `yaml:"state"` } type StateHookOutput struct { - State agentclient.State `yaml:"state"` - Message string `yaml:"message"` - FleetState agentclient.State `yaml:"fleet_state"` - FleetMessage string `yaml:"fleet_message"` - LogLevel logp.Level `yaml:"log_level"` - Components []StateComponentOutput `yaml:"components"` + State agentclient.State `yaml:"state"` + Message string `yaml:"message"` + FleetState agentclient.State `yaml:"fleet_state"` + FleetMessage string `yaml:"fleet_message"` + LogLevel logp.Level `yaml:"log_level"` + Components []StateComponentOutput `yaml:"components"` + UpgradeDetails *details.Details `yaml:"upgrade_details,omitempty"` } s := c.State() @@ -809,12 +810,13 @@ func (c *Coordinator) DiagnosticHooks() diagnostics.Hooks { } } output := StateHookOutput{ - State: s.State, - Message: s.Message, - FleetState: s.FleetState, - FleetMessage: s.FleetMessage, - LogLevel: s.LogLevel, - Components: compStates, + State: s.State, + Message: s.Message, + FleetState: s.FleetState, + FleetMessage: s.FleetMessage, + LogLevel: s.LogLevel, + Components: compStates, + UpgradeDetails: s.UpgradeDetails, } o, err := yaml.Marshal(output) if err != nil { diff --git a/internal/pkg/agent/application/coordinator/diagnostics_test.go b/internal/pkg/agent/application/coordinator/diagnostics_test.go index c6f2dc4fc97..9fec8e1844b 100644 --- a/internal/pkg/agent/application/coordinator/diagnostics_test.go +++ b/internal/pkg/agent/application/coordinator/diagnostics_test.go @@ -7,16 +7,18 @@ package coordinator import ( "context" "errors" + "fmt" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gopkg.in/yaml.v2" - "github.com/elastic/elastic-agent-client/v7/pkg/proto" - "github.com/elastic/elastic-agent-client/v7/pkg/client" + "github.com/elastic/elastic-agent-client/v7/pkg/proto" + "github.com/elastic/elastic-agent/internal/pkg/agent/application/upgrade/details" "github.com/elastic/elastic-agent/internal/pkg/agent/configuration" "github.com/elastic/elastic-agent/internal/pkg/agent/transpiler" monitoringCfg "github.com/elastic/elastic-agent/internal/pkg/core/monitoring/config" @@ -413,6 +415,7 @@ func TestDiagnosticState(t *testing.T) { // Create a coordinator with a test state and verify that the state // diagnostic reports it + now := time.Now().UTC() state := State{ State: agentclient.Starting, Message: "starting up", @@ -432,9 +435,19 @@ func TestDiagnosticState(t *testing.T) { }, }, }, + UpgradeDetails: &details.Details{ + TargetVersion: "8.12.0", + State: "UPG_DOWNLOADING", + ActionID: "foobar", + Metadata: details.Metadata{ + DownloadPercent: 0.17469, + ScheduledAt: now, + DownloadRate: 123.56, + }, + }, } - expected := ` + expected := fmt.Sprintf(` state: 0 message: "starting up" fleet_state: 1 @@ -451,7 +464,15 @@ components: version_info: name: "version name" version: "version value" -` +upgrade_details: + target_version: 8.12.0 + state: UPG_DOWNLOADING + action_id: foobar + metadata: + download_percent: 0.17469 + scheduled_at: %s + download_rate: 123.56 +`, now.Format(time.RFC3339Nano)) coord := &Coordinator{ // This test needs a broadcaster since the components-actual diagnostic diff --git a/internal/pkg/agent/application/upgrade/details/details.go b/internal/pkg/agent/application/upgrade/details/details.go index 028990aafcd..a4cb9954d4b 100644 --- a/internal/pkg/agent/application/upgrade/details/details.go +++ b/internal/pkg/agent/application/upgrade/details/details.go @@ -24,10 +24,10 @@ type Observer func(details *Details) // Details consists of details regarding an ongoing upgrade. type Details struct { - TargetVersion string `json:"target_version"` - State State `json:"state"` - ActionID string `json:"action_id,omitempty"` - Metadata Metadata `json:"metadata"` + TargetVersion string `json:"target_version" yaml:"target_version"` + State State `json:"state" yaml:"state"` + ActionID string `json:"action_id,omitempty" yaml:"action_id,omitempty"` + Metadata Metadata `json:"metadata" yaml:"metadata"` observers []Observer mu sync.Mutex @@ -35,19 +35,25 @@ type Details struct { // Metadata consists of metadata relating to a specific upgrade state type Metadata struct { - ScheduledAt time.Time `json:"scheduled_at,omitempty"` - DownloadPercent float64 `json:"download_percent,omitempty"` - DownloadRate downloadRate `json:"download_rate,omitempty"` + ScheduledAt time.Time `json:"scheduled_at,omitempty" yaml:"scheduled_at,omitempty"` + + // DownloadPercent is the percentage of the artifact that has been + // downloaded. Minimum value is 0 and maximum value is 1. + DownloadPercent float64 `json:"download_percent,omitempty" yaml:"download_percent,omitempty"` + + // DownloadRate is the rate, in bytes per second, at which the download + // is progressing. + DownloadRate downloadRate `json:"download_rate,omitempty" yaml:"download_rate,omitempty"` // FailedState is the state an upgrade was in if/when it failed. Use the // Fail() method of UpgradeDetails to correctly record details when // an upgrade fails. - FailedState State `json:"failed_state,omitempty"` + FailedState State `json:"failed_state,omitempty" yaml:"failed_state,omitempty"` // ErrorMsg is any error message encountered if/when an upgrade fails. Use // the Fail() method of UpgradeDetails to correctly record details when // an upgrade fails. - ErrorMsg string `json:"error_msg,omitempty"` + ErrorMsg string `json:"error_msg,omitempty" yaml:"error_msg,omitempty"` } func NewDetails(targetVersion string, initialState State, actionID string) *Details { @@ -71,7 +77,7 @@ func (d *Details) SetState(s State) { } // SetDownloadProgress is a convenience method to set the download percent -// when the upgrade is in UPG_DOWNLOADING state. +// and download rate when the upgrade is in UPG_DOWNLOADING state. func (d *Details) SetDownloadProgress(percent, rateBytesPerSecond float64) { d.mu.Lock() defer d.mu.Unlock() diff --git a/internal/pkg/agent/application/upgrade/step_download.go b/internal/pkg/agent/application/upgrade/step_download.go index d86a43a5a3b..121a8e9cc26 100644 --- a/internal/pkg/agent/application/upgrade/step_download.go +++ b/internal/pkg/agent/application/upgrade/step_download.go @@ -12,8 +12,6 @@ import ( "strings" "time" - "github.com/elastic/elastic-agent/internal/pkg/agent/application/upgrade/details" - "github.com/cenkalti/backoff/v4" "go.elastic.co/apm" @@ -26,6 +24,7 @@ import ( "github.com/elastic/elastic-agent/internal/pkg/agent/application/upgrade/artifact/download/http" "github.com/elastic/elastic-agent/internal/pkg/agent/application/upgrade/artifact/download/localremote" "github.com/elastic/elastic-agent/internal/pkg/agent/application/upgrade/artifact/download/snapshot" + "github.com/elastic/elastic-agent/internal/pkg/agent/application/upgrade/details" "github.com/elastic/elastic-agent/internal/pkg/agent/errors" "github.com/elastic/elastic-agent/internal/pkg/release" "github.com/elastic/elastic-agent/pkg/core/logger"