diff --git a/changelog/fragments/1787356110-support-multiple-upgrade-source-uris.yaml b/changelog/fragments/1787356110-support-multiple-upgrade-source-uris.yaml new file mode 100644 index 0000000000..6c96eddf6a --- /dev/null +++ b/changelog/fragments/1787356110-support-multiple-upgrade-source-uris.yaml @@ -0,0 +1,45 @@ +# REQUIRED +# 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: feature + +# REQUIRED for all kinds +# Change summary; a 80ish characters long description of the change. +summary: Add support for multiple upgrade artifact source URIs. + +# REQUIRED for breaking-change, deprecation, known-issue +# Long description; in case the summary is not enough to describe the change +# this field accommodate a description without length limits. +description: Adds an ordered sources field to upgrade actions for multiple upgrade artifact source URIs. The existing source_uri setting is deprecated but remains supported for backward compatibility. + +# REQUIRED for breaking-change, deprecation, known-issue +# impact: + +# REQUIRED for breaking-change, deprecation, known-issue +# action: + +# REQUIRED for all kinds +# Affected component; usually one of "elastic-agent", "fleet-server", "filebeat", "metricbeat", "auditbeat", "all", etc. +component: fleet-server + +# AUTOMATED +# OPTIONAL to manually add other PR URLs +# PR URL: A link the PR 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/owner/repo/1234 + +# AUTOMATED +# OPTIONAL to manually add other issue URLs +# 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/api/handleCheckin.go b/internal/pkg/api/handleCheckin.go index 99c8ed0d31..cf72e6d435 100644 --- a/internal/pkg/api/handleCheckin.go +++ b/internal/pkg/api/handleCheckin.go @@ -971,6 +971,20 @@ func convertActionData(aType ActionType, raw json.RawMessage) (ad Action_Data, e if err != nil { return } + if d.Sources != nil { + if len(*d.Sources) > 0 { + sourceURI := (*d.Sources)[0] + d.SourceUri = &sourceURI + } else { + d.SourceUri = nil + } + } else if d.SourceUri != nil { + sources := []string{} + if *d.SourceUri != "" { + sources = append(sources, *d.SourceUri) + } + d.Sources = &sources + } err = ad.FromActionUpgrade(d) return case REQUESTDIAGNOSTICS: diff --git a/internal/pkg/api/handleCheckin_test.go b/internal/pkg/api/handleCheckin_test.go index 76f36a23e5..c80553c563 100644 --- a/internal/pkg/api/handleCheckin_test.go +++ b/internal/pkg/api/handleCheckin_test.go @@ -125,8 +125,38 @@ func TestConvertActionData(t *testing.T) { }, { name: "upgrade action", aType: UPGRADE, - raw: json.RawMessage(`{"source_uri":"https://localhost:8080","version":"1.2.3"}`), - expect: Action_Data{json.RawMessage(`{"source_uri":"https://localhost:8080","version":"1.2.3"}`)}, + raw: json.RawMessage(`{"sources":["https://localhost:8080"],"version":"1.2.3"}`), + expect: Action_Data{json.RawMessage(`{"source_uri":"https://localhost:8080","sources":["https://localhost:8080"],"version":"1.2.3"}`)}, + hasErr: false, + }, { + name: "upgrade action populates source uri from sources", + aType: UPGRADE, + raw: json.RawMessage(`{"sources":["https://first.example.com","https://second.example.com"],"version":"1.2.3"}`), + expect: Action_Data{json.RawMessage(`{"source_uri":"https://first.example.com","sources":["https://first.example.com","https://second.example.com"],"version":"1.2.3"}`)}, + hasErr: false, + }, { + name: "upgrade action populates sources from source uri", + aType: UPGRADE, + raw: json.RawMessage(`{"source_uri":"https://legacy.example.com","version":"1.2.3"}`), + expect: Action_Data{json.RawMessage(`{"source_uri":"https://legacy.example.com","sources":["https://legacy.example.com"],"version":"1.2.3"}`)}, + hasErr: false, + }, { + name: "upgrade action uses sources over source uri", + aType: UPGRADE, + raw: json.RawMessage(`{"source_uri":"https://legacy.example.com","sources":["https://new.example.com"],"version":"1.2.3"}`), + expect: Action_Data{json.RawMessage(`{"source_uri":"https://new.example.com","sources":["https://new.example.com"],"version":"1.2.3"}`)}, + hasErr: false, + }, { + name: "upgrade action uses empty sources over source uri", + aType: UPGRADE, + raw: json.RawMessage(`{"source_uri":"https://legacy.example.com","sources":[],"version":"1.2.3"}`), + expect: Action_Data{json.RawMessage(`{"sources":[],"version":"1.2.3"}`)}, + hasErr: false, + }, { + name: "upgrade action does not populate sources from empty source uri", + aType: UPGRADE, + raw: json.RawMessage(`{"source_uri":"","version":"1.2.3"}`), + expect: Action_Data{json.RawMessage(`{"source_uri":"","sources":[],"version":"1.2.3"}`)}, hasErr: false, }, { name: "request diagnostics action", @@ -231,6 +261,16 @@ func TestConvertActions(t *testing.T) { Data: Action_Data{json.RawMessage(`{}`)}, }}, token: "", + }, { + name: "upgrade action", + actions: []model.Action{{ActionID: "1234", Type: "UPGRADE", Data: json.RawMessage(`{"sources":["https://first.example.com","https://second.example.com"],"version":"9.6.0"}`)}}, + resp: []Action{{ + AgentId: "agent-id", + Id: "1234", + Type: UPGRADE, + Data: Action_Data{json.RawMessage(`{"source_uri":"https://first.example.com","sources":["https://first.example.com","https://second.example.com"],"version":"9.6.0"}`)}, + }}, + token: "", }, {name: "multiple actions", actions: []model.Action{ { diff --git a/internal/pkg/api/openapi.gen.go b/internal/pkg/api/openapi.gen.go index 12217ecd42..0e8e0df7b6 100644 --- a/internal/pkg/api/openapi.gen.go +++ b/internal/pkg/api/openapi.gen.go @@ -299,8 +299,12 @@ type ActionUpgrade struct { Rollback *bool `json:"rollback,omitempty"` // SourceUri The source of the upgrade artifact. + // Deprecated: Replaced by sources. SourceUri *string `json:"source_uri,omitempty"` + // Sources An ordered list of sources for the upgrade artifact. + Sources *[]string `json:"sources,omitempty"` + // Version The version number that the agent should upgrade to. Version string `json:"version"` } diff --git a/model/openapi.yml b/model/openapi.yml index b8ec67214c..e994e5d656 100644 --- a/model/openapi.yml +++ b/model/openapi.yml @@ -743,6 +743,13 @@ components: source_uri: description: The source of the upgrade artifact. type: string + deprecated: true + x-deprecated-reason: Replaced by sources. + sources: + description: An ordered list of sources for the upgrade artifact. + type: array + items: + type: string rollback: description: Indicates if this version change should be performed as a rollback to a previous version. type: boolean diff --git a/pkg/api/types.gen.go b/pkg/api/types.gen.go index 4847dfb32b..a745afeb35 100644 --- a/pkg/api/types.gen.go +++ b/pkg/api/types.gen.go @@ -296,8 +296,12 @@ type ActionUpgrade struct { Rollback *bool `json:"rollback,omitempty"` // SourceUri The source of the upgrade artifact. + // Deprecated: Replaced by sources. SourceUri *string `json:"source_uri,omitempty"` + // Sources An ordered list of sources for the upgrade artifact. + Sources *[]string `json:"sources,omitempty"` + // Version The version number that the agent should upgrade to. Version string `json:"version"` }