diff --git a/changelog/fragments/1765439361-service-component-avoid-stop-start.yaml b/changelog/fragments/1765439361-service-component-avoid-stop-start.yaml new file mode 100644 index 00000000000..d54446ab59f --- /dev/null +++ b/changelog/fragments/1765439361-service-component-avoid-stop-start.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: feature + +# Change summary; a 80ish characters long description of the change. +summary: Avoid stopping and starting service components on policy changes + +# 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/owner/repo/1234 + +# 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/pkg/component/component.go b/pkg/component/component.go index ed005e5f341..a1654a30e7e 100644 --- a/pkg/component/component.go +++ b/pkg/component/component.go @@ -514,7 +514,17 @@ func (r *RuntimeSpecs) componentsForInputType( // Treat as non isolated units component on error of reading the input spec if componentErr != nil || !inputSpec.Spec.IsolateUnits { + // Components are generally identified by their input type and output name. However, for + // Service Runtime components, there can only ever be a single instance of the component running, + // as a service. So we identify these only by their input type. This way, if the output for a service + // component were to change, it would not result in a different ID for that component. By keeping the same + // ID, we prevent the component from being identified as a new one and the corresponding service from being + // unnecessarily stopped and started. componentID := fmt.Sprintf("%s-%s", inputType, output.Name) + if inputSpec.Spec.Service != nil { + componentID = inputType + } + if componentErr == nil && !containsStr(inputSpec.Spec.Outputs, output.OutputType) { // This output is unsupported. componentErr = ErrOutputNotSupported @@ -559,7 +569,17 @@ func (r *RuntimeSpecs) componentsForInputType( } else { for _, input := range output.Inputs[inputType] { // Units are being mapped to components, so we need a unique ID for each. + // Components are generally identified by their input type and output name. However, for + // Service Runtime components, there can only ever be a single instance of the component running, + // as a service. So we identify these only by their input type. This way, if the output for a service + // component were to change, it would not result in a different ID for that component. By keeping the same + // ID, we prevent the component from being identified as a new one and the corresponding service from being + // unnecessarily stopped and started. componentID := fmt.Sprintf("%s-%s-%s", inputType, output.Name, input.id) + if inputSpec.Spec.Service != nil { + componentID = fmt.Sprintf("%s-%s", inputType, input.id) + } + if componentErr == nil && !containsStr(inputSpec.Spec.Outputs, output.OutputType) { // This output is unsupported. componentErr = ErrOutputNotSupported diff --git a/pkg/component/component_test.go b/pkg/component/component_test.go index 63bab01d5d6..095e6950e67 100644 --- a/pkg/component/component_test.go +++ b/pkg/component/component_test.go @@ -609,7 +609,7 @@ func TestToComponents(t *testing.T) { { InputType: "endpoint", OutputType: "elasticsearch", - ID: "endpoint-default", + ID: "endpoint", InputSpec: &InputRuntimeSpec{ InputType: "endpoint", BinaryName: "endpoint-security", @@ -618,7 +618,7 @@ func TestToComponents(t *testing.T) { Err: NewErrInputRuntimeCheckFail("Elastic Defend doesn't support RHEL7 on arm64"), Units: []Unit{ { - ID: "endpoint-default", + ID: "endpoint", Type: client.UnitTypeOutput, LogLevel: defaultUnitLogLevel, Config: MustExpectedConfig(map[string]interface{}{ @@ -626,7 +626,7 @@ func TestToComponents(t *testing.T) { }), }, { - ID: "endpoint-default-endpoint-0", + ID: "endpoint-endpoint-0", Type: client.UnitTypeInput, LogLevel: defaultUnitLogLevel, Config: MustExpectedConfig(map[string]interface{}{ diff --git a/testing/integration/ess/monitoring_endpoint_test.go b/testing/integration/ess/monitoring_endpoint_test.go index 0bde8ffc4a2..ade035a3186 100644 --- a/testing/integration/ess/monitoring_endpoint_test.go +++ b/testing/integration/ess/monitoring_endpoint_test.go @@ -51,7 +51,7 @@ func TestEndpointAgentServiceMonitoring(t *testing.T) { runner := &EndpointMetricsMonRunner{ info: info, fixture: fixture, - endpointID: "endpoint-default", + endpointID: "endpoint", } suite.Run(t, runner)