diff --git a/NOTICE.txt b/NOTICE.txt index 5aaa3cdfe24..a49a9cbf941 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -403,11 +403,11 @@ third-party archives. -------------------------------------------------------------------------------- Dependency : github.com/docker/go-units -Version: v0.4.0 +Version: v0.5.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/docker/go-units@v0.4.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/docker/go-units@v0.5.0/LICENSE: Apache License @@ -1130,11 +1130,11 @@ Contents of probable licence file $GOMODCACHE/github.com/elastic/elastic-agent-a -------------------------------------------------------------------------------- Dependency : github.com/elastic/elastic-agent-client/v7 -Version: v7.0.2-0.20221129150247-15881a8e64ef +Version: v7.0.3-0.20230315204017-166fd1fd746f Licence type (autodetected): Elastic -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/elastic/elastic-agent-client/v7@v7.0.2-0.20221129150247-15881a8e64ef/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/elastic/elastic-agent-client/v7@v7.0.3-0.20230315204017-166fd1fd746f/LICENSE.txt: ELASTIC LICENSE AGREEMENT @@ -1574,11 +1574,11 @@ Contents of probable licence file $GOMODCACHE/github.com/elastic/elastic-agent-l -------------------------------------------------------------------------------- Dependency : github.com/elastic/elastic-agent-system-metrics -Version: v0.4.4 +Version: v0.4.6-0.20230308003052-ba171438211e Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/elastic/elastic-agent-system-metrics@v0.4.4/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/elastic/elastic-agent-system-metrics@v0.4.6-0.20230308003052-ba171438211e/LICENSE.txt: Apache License Version 2.0, January 2004 @@ -1997,11 +1997,11 @@ Contents of probable licence file $GOMODCACHE/github.com/elastic/go-licenser@v0. -------------------------------------------------------------------------------- Dependency : github.com/elastic/go-sysinfo -Version: v1.8.1 +Version: v1.9.1-0.20230328042007-6dcfe88b8359 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/elastic/go-sysinfo@v1.8.1/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/elastic/go-sysinfo@v1.9.1-0.20230328042007-6dcfe88b8359/LICENSE.txt: Apache License @@ -2487,11 +2487,11 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- Dependency : github.com/google/go-cmp -Version: v0.5.6 +Version: v0.5.9 Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/google/go-cmp@v0.5.6/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/google/go-cmp@v0.5.9/LICENSE: Copyright (c) 2017 The Go Authors. All rights reserved. @@ -4084,11 +4084,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- Dependency : github.com/sirupsen/logrus -Version: v1.8.1 +Version: v1.9.0 Licence type (autodetected): MIT -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/sirupsen/logrus@v1.8.1/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/sirupsen/logrus@v1.9.0/LICENSE: The MIT License (MIT) @@ -5526,11 +5526,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- Dependency : golang.org/x/sync -Version: v0.0.0-20220722155255-886fb9371eb4 +Version: v0.1.0 Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/golang.org/x/sync@v0.0.0-20220722155255-886fb9371eb4/LICENSE: +Contents of probable licence file $GOMODCACHE/golang.org/x/sync@v0.1.0/LICENSE: Copyright (c) 2009 The Go Authors. All rights reserved. @@ -5563,11 +5563,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- Dependency : golang.org/x/sys -Version: v0.4.0 +Version: v0.6.0 Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/golang.org/x/sys@v0.4.0/LICENSE: +Contents of probable licence file $GOMODCACHE/golang.org/x/sys@v0.6.0/LICENSE: Copyright (c) 2009 The Go Authors. All rights reserved. @@ -7441,207 +7441,6 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------------------------------- -Dependency : github.com/containerd/containerd -Version: v1.5.13 -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/containerd/containerd@v1.5.13/LICENSE: - - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright The containerd Authors - - Licensed 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 - - https://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. - - -------------------------------------------------------------------------------- Dependency : github.com/cyphar/filepath-securejoin Version: v0.2.3 @@ -7957,11 +7756,11 @@ Apache License -------------------------------------------------------------------------------- Dependency : github.com/docker/docker -Version: v20.10.12+incompatible +Version: v20.10.22+incompatible Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/docker/docker@v20.10.12+incompatible/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/docker/docker@v20.10.22+incompatible/LICENSE: Apache License @@ -12519,11 +12318,11 @@ Contents of probable licence file $GOMODCACHE/github.com/moby/spdystream@v0.2.0/ -------------------------------------------------------------------------------- Dependency : github.com/moby/term -Version: v0.0.0-20210619224110-3f7ff695adc6 +Version: v0.0.0-20221205130635-1aeaba878587 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/moby/term@v0.0.0-20210619224110-3f7ff695adc6/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/moby/term@v0.0.0-20221205130635-1aeaba878587/LICENSE: Apache License @@ -13754,11 +13553,11 @@ SOFTWARE. -------------------------------------------------------------------------------- Dependency : github.com/prometheus/procfs -Version: v0.7.3 +Version: v0.9.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/prometheus/procfs@v0.7.3/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/prometheus/procfs@v0.9.0/LICENSE: Apache License Version 2.0, January 2004 @@ -14029,6 +13828,76 @@ DEALINGS IN THE SOFTWARE. +-------------------------------------------------------------------------------- +Dependency : github.com/shirou/gopsutil +Version: v3.21.11+incompatible +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/shirou/gopsutil@v3.21.11+incompatible/LICENSE: + +gopsutil is distributed under BSD license reproduced below. + +Copyright (c) 2014, WAKAYAMA Shirou +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the gopsutil authors nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +------- +internal/common/binary.go in the gopsutil is copied and modifid from golang/encoding/binary.go. + + + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + -------------------------------------------------------------------------------- Dependency : github.com/spf13/afero Version: v1.6.0 @@ -16314,11 +16183,11 @@ limitations under the License. -------------------------------------------------------------------------------- Dependency : gotest.tools/v3 -Version: v3.0.3 +Version: v3.4.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/gotest.tools/v3@v3.0.3/LICENSE: +Contents of probable licence file $GOMODCACHE/gotest.tools/v3@v3.4.0/LICENSE: Copyright 2018 gotest.tools authors diff --git a/Vagrantfile b/Vagrantfile index 8cfde6f4b3b..40f3164b94a 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -131,7 +131,10 @@ Vagrant.configure("2") do |config| config.vm.define "elastic-agent" do |nodeconfig| nodeconfig.vm.box = "ubuntu/jammy64" - nodeconfig.vm.hostname = "elastic-agent-dev" + + # We deliberately set a fully-qualified domain name for the VM; it helps + # test the FQDN feature flag. + nodeconfig.vm.hostname = "elastic-agent-dev.elastic.dev.internal" nodeconfig.vm.network "private_network", hostname: true, diff --git a/_meta/config/common.reference.p2.yml.tmpl b/_meta/config/common.reference.p2.yml.tmpl index 16008a2bd59..a8cf0febd47 100644 --- a/_meta/config/common.reference.p2.yml.tmpl +++ b/_meta/config/common.reference.p2.yml.tmpl @@ -154,6 +154,13 @@ inputs: # # period define how frequent we should look for changes in the configuration. # period: 10s +# Feature Flags + +# This section enables or disables feature flags supported by Agent and its components. +#agent.features: +# fqdn: +# enabled: false + # Logging # There are four options for the log output: file, stderr, syslog, eventlog diff --git a/changelog/fragments/1679422558-feature-flags.yaml b/changelog/fragments/1679422558-feature-flags.yaml new file mode 100644 index 00000000000..96abb99dcbc --- /dev/null +++ b/changelog/fragments/1679422558-feature-flags.yaml @@ -0,0 +1,34 @@ +# 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: feature-flags + +# 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: | + Add support for feature flags, starting with one to toggle FQDN reporting in + events generated by Agent components, via the `host.name` field. + +# Affected component; a word indicating the component this changeset affects. +component: 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/2218 + +# 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/elastic/elastic-agent/issues/2185 diff --git a/elastic-agent.reference.yml b/elastic-agent.reference.yml index 3a5fd32fdf6..b43b246eee8 100644 --- a/elastic-agent.reference.yml +++ b/elastic-agent.reference.yml @@ -160,6 +160,13 @@ inputs: # # period define how frequent we should look for changes in the configuration. # period: 10s +# Feature Flags + +# This section enables or disables feature flags supported by Agent and its components. +#agent.features: +# fqdn: +# enabled: false + # Logging # There are four options for the log output: file, stderr, syslog, eventlog diff --git a/go.mod b/go.mod index aa2513feea6..9bca400bdfb 100644 --- a/go.mod +++ b/go.mod @@ -3,25 +3,25 @@ module github.com/elastic/elastic-agent go 1.19 require ( - github.com/Microsoft/go-winio v0.5.2 + github.com/Microsoft/go-winio v0.6.0 github.com/antlr/antlr4 v0.0.0-20200820155224-be881fa6b91d github.com/billgraziano/dpapi v0.4.0 github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 github.com/cavaliercoder/go-rpm v0.0.0-20190131055624-7a9c54e3d83e github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534 - github.com/docker/go-units v0.4.0 + github.com/docker/go-units v0.5.0 github.com/dolmen-go/contextio v0.0.0-20200217195037-68fc5150bcd5 github.com/elastic/e2e-testing v1.99.2-0.20221205111528-ade3c840d0c0 github.com/elastic/elastic-agent-autodiscover v0.2.1 - github.com/elastic/elastic-agent-client/v7 v7.0.2-0.20221129150247-15881a8e64ef + github.com/elastic/elastic-agent-client/v7 v7.0.3-0.20230315204017-166fd1fd746f github.com/elastic/elastic-agent-libs v0.3.6 - github.com/elastic/elastic-agent-system-metrics v0.4.4 + github.com/elastic/elastic-agent-system-metrics v0.4.6-0.20230308003052-ba171438211e github.com/elastic/go-licenser v0.4.0 - github.com/elastic/go-sysinfo v1.8.1 + github.com/elastic/go-sysinfo v1.9.1-0.20230328042007-6dcfe88b8359 github.com/elastic/go-ucfg v0.8.6 github.com/gofrs/flock v0.8.1 github.com/gofrs/uuid v4.2.0+incompatible - github.com/google/go-cmp v0.5.6 + github.com/google/go-cmp v0.5.9 github.com/gorilla/mux v1.8.0 github.com/hashicorp/go-multierror v1.1.1 github.com/hectane/go-acl v0.0.0-20190604041725-da78bae5fc95 @@ -38,7 +38,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.27.0 github.com/shirou/gopsutil/v3 v3.21.12 - github.com/sirupsen/logrus v1.8.1 + github.com/sirupsen/logrus v1.9.0 github.com/spf13/cobra v1.3.0 github.com/stretchr/testify v1.8.2 github.com/tsg/go-daemon v0.0.0-20200207173439-e704b93fd89b @@ -48,8 +48,8 @@ require ( go.uber.org/zap v1.21.0 golang.org/x/crypto v0.5.0 golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 - golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 - golang.org/x/sys v0.4.0 + golang.org/x/sync v0.1.0 + golang.org/x/sys v0.6.0 golang.org/x/text v0.7.0 golang.org/x/time v0.3.0 golang.org/x/tools v0.1.12 @@ -69,12 +69,11 @@ require ( github.com/armon/go-radix v1.0.0 // indirect github.com/cavaliercoder/badio v0.0.0-20160213150051-ce5280129e9e // indirect github.com/cenkalti/backoff/v4 v4.1.2 // indirect - github.com/containerd/containerd v1.5.13 // indirect github.com/cyphar/filepath-securejoin v0.2.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dnephin/pflag v1.0.7 // indirect github.com/docker/distribution v2.8.1+incompatible // indirect - github.com/docker/docker v20.10.12+incompatible // indirect + github.com/docker/docker v20.10.22+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/elastic/go-structform v0.0.9 // indirect github.com/elastic/go-windows v1.0.1 // indirect @@ -111,9 +110,10 @@ require ( github.com/opencontainers/image-spec v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect - github.com/prometheus/procfs v0.7.3 // indirect + github.com/prometheus/procfs v0.9.0 // indirect github.com/santhosh-tekuri/jsonschema v1.2.4 // indirect github.com/sergi/go-diff v1.1.0 // indirect + github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.0 // indirect github.com/tklauser/go-sysconf v0.3.9 // indirect @@ -129,7 +129,6 @@ require ( golang.org/x/net v0.5.0 // indirect golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect golang.org/x/term v0.4.0 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20220426171045-31bebdecfb46 // indirect google.golang.org/grpc/examples v0.0.0-20220304170021-431ea809a767 // indirect diff --git a/go.sum b/go.sum index c5651973905..c6012438533 100644 --- a/go.sum +++ b/go.sum @@ -259,7 +259,6 @@ github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoT github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c= github.com/containerd/containerd v1.5.9/go.mod h1:fvQqCfadDGga5HZyn3j4+dx56qj2I9YwBrlSdalvJYQ= -github.com/containerd/containerd v1.5.13 h1:XqvKw9i4P7/mFrC3TSM7yV5cwFZ9avXe6M3YANKnzEE= github.com/containerd/containerd v1.5.13/go.mod h1:3AlCrzKROjIuP3JALsY14n8YtntaUDBu7vek+rPN5Vc= github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= @@ -372,8 +371,9 @@ github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6 github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v20.10.11+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v20.10.12+incompatible h1:CEeNmFM0QZIsJCZKMkZx0ZcahTiewkrgiwfYD+dfl1U= github.com/docker/docker v20.10.12+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.22+incompatible h1:6jX4yB+NtcbldT90k7vBSaWJDB3i+zkVJT9BEK8kQkk= +github.com/docker/docker v20.10.22+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= @@ -382,8 +382,9 @@ github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6Uezg github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= @@ -397,13 +398,13 @@ github.com/elastic/e2e-testing v1.99.2-0.20221205111528-ade3c840d0c0 h1:dTrVPE6H github.com/elastic/e2e-testing v1.99.2-0.20221205111528-ade3c840d0c0/go.mod h1:hzqVK19fiowHGWldLoKRHl3eXLErKyP89o7L/R3aHsk= github.com/elastic/elastic-agent-autodiscover v0.2.1 h1:Nbeayh3vq2FNm6xaFo34mhUdOu0EVlpj53CqCsbU0E4= github.com/elastic/elastic-agent-autodiscover v0.2.1/go.mod h1:gPnzzfdYNdgznAb+iG9eyyXaQXBbAMHa+Y6Z8hXfcGY= -github.com/elastic/elastic-agent-client/v7 v7.0.2-0.20221129150247-15881a8e64ef h1:+3AWaimDL826eoU06qOFBtA3xmyuTr9YUMVWvnim4mU= -github.com/elastic/elastic-agent-client/v7 v7.0.2-0.20221129150247-15881a8e64ef/go.mod h1:cHviLpA5fAwMbfBIHBVNl16qp90bO7pKHMAQaG+9raU= +github.com/elastic/elastic-agent-client/v7 v7.0.3-0.20230315204017-166fd1fd746f h1:IzNUtc4ZfDSUHbRI5Yz5tJ+lt9N75cxvlT9aXW2Hh2g= +github.com/elastic/elastic-agent-client/v7 v7.0.3-0.20230315204017-166fd1fd746f/go.mod h1:UlVOHSDvTA4Mfdhdg+BE7aqOsUR3ab+x2Zl0aHlBXs4= github.com/elastic/elastic-agent-libs v0.2.5/go.mod h1:chO3rtcLyGlKi9S0iGVZhYCzDfdDsAQYBc+ui588AFE= github.com/elastic/elastic-agent-libs v0.3.6 h1:PxV0+dq92vzM96qNQCfwsMMqWcdaGc9nbuTquv409Ws= github.com/elastic/elastic-agent-libs v0.3.6/go.mod h1:h48hzjQcn6XPwfWRM5HimAKlsG0J92ULgAzdX+WedA8= -github.com/elastic/elastic-agent-system-metrics v0.4.4 h1:Br3S+TlBhijrLysOvbHscFhgQ00X/trDT5VEnOau0E0= -github.com/elastic/elastic-agent-system-metrics v0.4.4/go.mod h1:tF/f9Off38nfzTZHIVQ++FkXrDm9keFhFpJ+3pQ00iI= +github.com/elastic/elastic-agent-system-metrics v0.4.6-0.20230308003052-ba171438211e h1:OIfumgZhI6lI7Qy1KD1VzuqvX9DWSBpXJsvj97s7MRM= +github.com/elastic/elastic-agent-system-metrics v0.4.6-0.20230308003052-ba171438211e/go.mod h1:v/t/qgYueW3ZOm7SZhYY3ng9GWDddDLu7pmG4Ra3PBs= github.com/elastic/elastic-package v0.36.0/go.mod h1:TUyhRXtf+kazrUthMF+5FtngcFJZtsgty0o/nnl8UFU= github.com/elastic/go-elasticsearch/v7 v7.16.0/go.mod h1:OJ4wdbtDNk5g503kvlHLyErCgQwwzmDtaFC4XyOxXA4= github.com/elastic/go-elasticsearch/v8 v8.0.0-20210317102009-a9d74cec0186/go.mod h1:xe9a/L2aeOgFKKgrO3ibQTnMdpAeL0GC+5/HpGScSa4= @@ -414,8 +415,8 @@ github.com/elastic/go-structform v0.0.9 h1:HpcS7xljL4kSyUfDJ8cXTJC6rU5ChL1wYb6cx github.com/elastic/go-structform v0.0.9/go.mod h1:CZWf9aIRYY5SuKSmOhtXScE5uQiLZNqAFnwKR4OrIM4= github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= github.com/elastic/go-sysinfo v1.7.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= -github.com/elastic/go-sysinfo v1.8.1 h1:4Yhj+HdV6WjbCRgGdZpPJ8lZQlXZLKDAeIkmQ/VRvi4= -github.com/elastic/go-sysinfo v1.8.1/go.mod h1:JfllUnzoQV/JRYymbH3dO1yggI3mV2oTKSXsDHM+uIM= +github.com/elastic/go-sysinfo v1.9.1-0.20230328042007-6dcfe88b8359 h1:qSCKykLGlUcO/wzq3xH+wtPHM2KCpQnqXOKClSg5K2w= +github.com/elastic/go-sysinfo v1.9.1-0.20230328042007-6dcfe88b8359/go.mod h1:j/gGAinRS+z3loQ/1pO+s9pCyQsna8U13kqhF1Aa0fg= github.com/elastic/go-ucfg v0.8.4/go.mod h1:4E8mPOLSUV9hQ7sgLEJ4bvt0KhMuDJa8joDT2QGAEKA= github.com/elastic/go-ucfg v0.8.5/go.mod h1:4E8mPOLSUV9hQ7sgLEJ4bvt0KhMuDJa8joDT2QGAEKA= github.com/elastic/go-ucfg v0.8.6 h1:stUeyh2goTgGX+/wb9gzKvTv0YB0231LTpKUgCKj4U0= @@ -622,8 +623,9 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= @@ -933,8 +935,8 @@ github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdx github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= -github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -1077,8 +1079,9 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -1106,6 +1109,8 @@ github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvW github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= +github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil/v3 v3.21.10/go.mod h1:t75NhzCZ/dYyPQjyQmrAYP6c8+LCdFANeBMdLPCNnew= github.com/shirou/gopsutil/v3 v3.21.12 h1:VoGxEW2hpmz0Vt3wUvHIl9fquzYLNpVpgNNB7pGJimA= github.com/shirou/gopsutil/v3 v3.21.12/go.mod h1:BToYZVTlSVlfazpDDYFnsVZLaoRG+g8ufT6fPQLdJzA= @@ -1119,8 +1124,9 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= @@ -1492,8 +1498,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1620,8 +1626,9 @@ golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1962,8 +1969,8 @@ gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81 gotest.tools/gotestsum v1.7.0 h1:RwpqwwFKBAa2h+F6pMEGpE707Edld0etUD3GhqqhDNc= gotest.tools/gotestsum v1.7.0/go.mod h1:V1m4Jw3eBerhI/A6qCxUE07RnCg7ACkKj9BYcAm09V8= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= helm.sh/helm/v3 v3.8.0/go.mod h1:0nYPSuvuj8TTJDLRSAfbzGGbazPZsayaDpP8s9FfZT8= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/pkg/agent/application/application.go b/internal/pkg/agent/application/application.go index fb45671f5f5..a0fa5ec9c24 100644 --- a/internal/pkg/agent/application/application.go +++ b/internal/pkg/agent/application/application.go @@ -25,6 +25,7 @@ import ( "github.com/elastic/elastic-agent/pkg/component" "github.com/elastic/elastic-agent/pkg/component/runtime" "github.com/elastic/elastic-agent/pkg/core/logger" + "github.com/elastic/elastic-agent/pkg/features" ) // New creates a new Agent and bootstrap the required subsystem. @@ -69,6 +70,10 @@ func New( return nil, fmt.Errorf("failed to load configuration: %w", err) } + if err := features.Apply(rawConfig); err != nil { + return nil, nil, fmt.Errorf("could not parse and apply feature flags config: %w", err) + } + // monitoring is not supported in bootstrap mode https://github.com/elastic/elastic-agent/issues/1761 isMonitoringSupported := !disableMonitoring && cfg.Settings.V1MonitoringEnabled upgrader := upgrade.NewUpgrader(log, cfg.Settings.DownloadConfig, agentInfo) diff --git a/internal/pkg/agent/application/coordinator/coordinator.go b/internal/pkg/agent/application/coordinator/coordinator.go index 8c9b4c8c1eb..eea3f6ad0b8 100644 --- a/internal/pkg/agent/application/coordinator/coordinator.go +++ b/internal/pkg/agent/application/coordinator/coordinator.go @@ -30,6 +30,7 @@ import ( "github.com/elastic/elastic-agent/pkg/component" "github.com/elastic/elastic-agent/pkg/component/runtime" "github.com/elastic/elastic-agent/pkg/core/logger" + "github.com/elastic/elastic-agent/pkg/features" ) var ( @@ -127,7 +128,7 @@ type ConfigManager interface { // ActionErrors returns the error channel for actions. // May return errors for fleet managed agents. - // Will always be empty for stand alone agents. + // Will always be empty for standalone agents. ActionErrors() <-chan error // Watch returns the chanel to watch for configuration changes. @@ -734,6 +735,10 @@ func (c *Coordinator) processConfig(ctx context.Context, cfg *config.Config) (er } } + if err := features.Apply(cfg); err != nil { + return fmt.Errorf("could not update feature flags config: %w", err) + } + if err := c.upgradeMgr.Reload(cfg); err != nil { return fmt.Errorf("failed to reload upgrade manager configuration: %w", err) } @@ -831,7 +836,7 @@ func (c *Coordinator) compute() (map[string]interface{}, []component.Component, comps, err := c.specs.ToComponents( cfg, configInjector, - c.state.logLevel, + c.State(false).LogLevel, c.agentInfo, ) if err != nil { diff --git a/internal/pkg/agent/application/coordinator/diagnostics_test.go b/internal/pkg/agent/application/coordinator/diagnostics_test.go index 5b8fc62cdd3..a1901e79fd1 100644 --- a/internal/pkg/agent/application/coordinator/diagnostics_test.go +++ b/internal/pkg/agent/application/coordinator/diagnostics_test.go @@ -16,6 +16,8 @@ import ( "testing" "time" + "github.com/elastic/elastic-agent-client/v7/pkg/proto" + "github.com/stretchr/testify/assert" mock "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -153,6 +155,10 @@ func TestCoordinatorDiagnosticHooks(t *testing.T) { Version: "1.2.3", }, Units: unitsStates, + Features: &proto.Features{ + Fqdn: &proto.FQDNFeature{Enabled: true}, + }, + FeaturesIdx: 1, }, } diff --git a/internal/pkg/agent/application/coordinator/testdata/simple_config/elastic-agent.yml b/internal/pkg/agent/application/coordinator/testdata/simple_config/elastic-agent.yml index 48d9f7e0d86..c92ff47ef95 100644 --- a/internal/pkg/agent/application/coordinator/testdata/simple_config/elastic-agent.yml +++ b/internal/pkg/agent/application/coordinator/testdata/simple_config/elastic-agent.yml @@ -153,7 +153,9 @@ agent: namespace: default logs: true metrics: true - features: {} + features: + fqdn: + enabled: true inputs: - id: logfile-system-d38b6b0b-cc52-4a61-b897-1b236982ac42 name: system-1 @@ -344,4 +346,4 @@ inputs: type: metrics metricsets: - uptime - period: 10s \ No newline at end of file + period: 10s diff --git a/internal/pkg/agent/application/coordinator/testdata/simple_config/expected/components-expected.yaml b/internal/pkg/agent/application/coordinator/testdata/simple_config/expected/components-expected.yaml index ef27699d724..6b1d87aec7f 100644 --- a/internal/pkg/agent/application/coordinator/testdata/simple_config/expected/components-expected.yaml +++ b/internal/pkg/agent/application/coordinator/testdata/simple_config/expected/components-expected.yaml @@ -57,6 +57,26 @@ components: preventions: [] shippers: - shipper + features: + fqdn: + enabled: true + source: + fields: + agent: + kind: + structvalue: + fields: + features: + kind: + structvalue: + fields: + fqdn: + kind: + structvalue: + fields: + enabled: + kind: + boolvalue: true units: - config: datastream: @@ -477,6 +497,26 @@ components: preventions: [] shippers: - shipper + features: + fqdn: + enabled: true + source: + fields: + agent: + kind: + structvalue: + fields: + features: + kind: + structvalue: + fields: + fqdn: + kind: + structvalue: + fields: + enabled: + kind: + boolvalue: true units: - config: datastream: diff --git a/internal/pkg/agent/application/coordinator/testdata/simple_config/expected/computed-config.yaml b/internal/pkg/agent/application/coordinator/testdata/simple_config/expected/computed-config.yaml index 01bd3d61958..0f3c2e5e02d 100644 --- a/internal/pkg/agent/application/coordinator/testdata/simple_config/expected/computed-config.yaml +++ b/internal/pkg/agent/application/coordinator/testdata/simple_config/expected/computed-config.yaml @@ -1,7 +1,9 @@ agent: download: sourceURI: https://artifacts.elastic.co/downloads/ - features: null + features: + fqdn: + enabled: true monitoring: enabled: true logs: true @@ -400,4 +402,4 @@ path: data: /data home: /data/elastic-agent-unknow logs: -revision: 5 \ No newline at end of file +revision: 5 diff --git a/internal/pkg/agent/application/coordinator/testdata/simple_config/expected/pre-config.yaml b/internal/pkg/agent/application/coordinator/testdata/simple_config/expected/pre-config.yaml index 337150a6cd5..e80f6920905 100644 --- a/internal/pkg/agent/application/coordinator/testdata/simple_config/expected/pre-config.yaml +++ b/internal/pkg/agent/application/coordinator/testdata/simple_config/expected/pre-config.yaml @@ -1,7 +1,9 @@ agent: download: sourceURI: https://artifacts.elastic.co/downloads/ - features: null + features: + fqdn: + enabled: true monitoring: enabled: true logs: true @@ -431,4 +433,4 @@ path: data: /data home: /data/elastic-agent-unknow logs: -revision: 5 \ No newline at end of file +revision: 5 diff --git a/internal/pkg/agent/application/coordinator/testdata/simple_config/expected/state.yaml b/internal/pkg/agent/application/coordinator/testdata/simple_config/expected/state.yaml index 234e2ded7c3..978de5cadf5 100644 --- a/internal/pkg/agent/application/coordinator/testdata/simple_config/expected/state.yaml +++ b/internal/pkg/agent/application/coordinator/testdata/simple_config/expected/state.yaml @@ -11,6 +11,7 @@ components: version_info: name: Mock system/metrics version: 1.2.3 + features_idx: 1 - id: log-default state: message: "" @@ -19,6 +20,7 @@ components: version_info: name: Mock log version: 1.2.3 + features_idx: 1 - id: filestream-monitoring state: message: "" @@ -27,6 +29,7 @@ components: version_info: name: Mock filestream version: 1.2.3 + features_idx: 1 - id: beat/metrics-monitoring state: message: "" @@ -35,6 +38,7 @@ components: version_info: name: Mock beat/metrics version: 1.2.3 + features_idx: 1 - id: http/metrics-monitoring state: message: "" @@ -43,4 +47,5 @@ components: version_info: name: Mock http/metrics version: 1.2.3 + features_idx: 1 log_level: info diff --git a/internal/pkg/agent/application/gateway/fleet/fleet_gateway.go b/internal/pkg/agent/application/gateway/fleet/fleet_gateway.go index 9d9024ef523..128179ed82e 100644 --- a/internal/pkg/agent/application/gateway/fleet/fleet_gateway.go +++ b/internal/pkg/agent/application/gateway/fleet/fleet_gateway.go @@ -307,7 +307,7 @@ func (f *fleetGateway) convertToCheckinComponents(components []runtime.Component } func (f *fleetGateway) execute(ctx context.Context) (*fleetapi.CheckinResponse, time.Duration, error) { - ecsMeta, err := info.Metadata() + ecsMeta, err := info.Metadata(f.log) if err != nil { f.log.Error(errors.New("failed to load metadata", err)) } diff --git a/internal/pkg/agent/application/info/agent_metadata.go b/internal/pkg/agent/application/info/agent_metadata.go index 49afeca9dc7..ec4a31efccb 100644 --- a/internal/pkg/agent/application/info/agent_metadata.go +++ b/internal/pkg/agent/application/info/agent_metadata.go @@ -6,15 +6,17 @@ package info import ( "fmt" - "os" "runtime" "strings" - "github.com/elastic/go-sysinfo" - "github.com/elastic/go-sysinfo/types" + "github.com/elastic/elastic-agent/pkg/core/logger" "github.com/elastic/elastic-agent/internal/pkg/agent/errors" "github.com/elastic/elastic-agent/internal/pkg/release" + "github.com/elastic/elastic-agent/pkg/features" + + "github.com/elastic/go-sysinfo" + "github.com/elastic/go-sysinfo/types" ) // ECSMeta is a collection of agent related metadata in ECS compliant object form. @@ -121,13 +123,13 @@ const ( ) // Metadata loads metadata from disk. -func Metadata() (*ECSMeta, error) { +func Metadata(l *logger.Logger) (*ECSMeta, error) { agentInfo, err := NewAgentInfo(false) if err != nil { return nil, fmt.Errorf("failed to create new agent info: %w", err) } - meta, err := agentInfo.ECSMetadata() + meta, err := agentInfo.ECSMetadata(l) if err != nil { return nil, errors.New(err, "failed to gather host metadata") } @@ -136,18 +138,23 @@ func Metadata() (*ECSMeta, error) { } // ECSMetadata returns an agent ECS compliant metadata. -func (i *AgentInfo) ECSMetadata() (*ECSMeta, error) { - hostname, err := os.Hostname() - if err != nil { - return nil, err - } - +func (i *AgentInfo) ECSMetadata(l *logger.Logger) (*ECSMeta, error) { sysInfo, err := sysinfo.Host() if err != nil { return nil, err } info := sysInfo.Info() + hostname := info.Hostname + l.Debugf("in ECSMetadata, hostname = %s", hostname) + if features.FQDN() { + fqdn, err := sysInfo.FQDN() + if err != nil { + l.Debugf("unable to lookup FQDN: %s, using hostname = %s", err.Error(), hostname) + } else { + hostname = fqdn + } + } return &ECSMeta{ Elastic: &ElasticECSMeta{ @@ -184,12 +191,7 @@ func (i *AgentInfo) ECSMetadata() (*ECSMeta, error) { } // ECSMetadataFlatMap returns an agent ECS compliant metadata in a form of flattened map. -func (i *AgentInfo) ECSMetadataFlatMap() (map[string]interface{}, error) { - hostname, err := os.Hostname() - if err != nil { - return nil, err - } - +func (i *AgentInfo) ECSMetadataFlatMap(l *logger.Logger) (map[string]interface{}, error) { // TODO: remove these values when kibana migrates to ECS meta := make(map[string]interface{}) @@ -199,6 +201,16 @@ func (i *AgentInfo) ECSMetadataFlatMap() (map[string]interface{}, error) { } info := sysInfo.Info() + hostname := info.Hostname + l.Debugf("in ECSMetadataFlatMap, hostname = %s", hostname) + if features.FQDN() { + fqdn, err := sysInfo.FQDN() + if err != nil { + l.Debugf("unable to lookup FQDN: %s, using hostname = %s", err.Error(), hostname) + } else { + hostname = fqdn + } + } // Agent meta[agentIDKey] = i.agentID diff --git a/internal/pkg/agent/application/monitoring/v1_monitor.go b/internal/pkg/agent/application/monitoring/v1_monitor.go index f8c61370628..de49866215c 100644 --- a/internal/pkg/agent/application/monitoring/v1_monitor.go +++ b/internal/pkg/agent/application/monitoring/v1_monitor.go @@ -113,8 +113,13 @@ func (b *BeatsMonitor) MonitoringConfig( return nil, nil } + cfg := make(map[string]interface{}) + monitoringOutputName := defaultOutputName if agentCfg, found := policy[agentKey]; found { + // The agent section is required for feature flags + cfg[agentKey] = agentCfg + agentCfgMap, ok := agentCfg.(map[string]interface{}) if ok { if monitoringCfg, found := agentCfgMap[monitoringKey]; found { @@ -130,8 +135,6 @@ func (b *BeatsMonitor) MonitoringConfig( } } - cfg := make(map[string]interface{}) - if err := b.injectMonitoringOutput(policy, cfg, monitoringOutputName); err != nil && !errors.Is(err, errNoOuputPresent) { return nil, errors.New(err, "failed to inject monitoring output") } else if errors.Is(err, errNoOuputPresent) { diff --git a/internal/pkg/agent/cmd/enroll_cmd.go b/internal/pkg/agent/cmd/enroll_cmd.go index 612c6eb0203..0dde22b4ff1 100644 --- a/internal/pkg/agent/cmd/enroll_cmd.go +++ b/internal/pkg/agent/cmd/enroll_cmd.go @@ -501,7 +501,7 @@ func (c *enrollCmd) enrollWithBackoff(ctx context.Context, persistentConfig map[ func (c *enrollCmd) enroll(ctx context.Context, persistentConfig map[string]interface{}) error { cmd := fleetapi.NewEnrollCmd(c.client) - metadata, err := info.Metadata() + metadata, err := info.Metadata(c.log) if err != nil { return errors.New(err, "acquiring metadata failed") } diff --git a/internal/pkg/composable/providers/host/host.go b/internal/pkg/composable/providers/host/host.go index b722a5f4c69..ca0bc8fbdf7 100644 --- a/internal/pkg/composable/providers/host/host.go +++ b/internal/pkg/composable/providers/host/host.go @@ -6,11 +6,11 @@ package host import ( "fmt" - "os" "reflect" "runtime" "time" + "github.com/elastic/elastic-agent/pkg/features" "github.com/elastic/go-sysinfo" "github.com/elastic/elastic-agent/internal/pkg/agent/errors" @@ -80,7 +80,7 @@ func (c *contextProvider) Run(comm corecomp.ContextProviderComm) error { func ContextProviderBuilder(log *logger.Logger, c *config.Config, _ bool) (corecomp.ContextProvider, error) { p := &contextProvider{ logger: log, - fetcher: getHostInfo, + fetcher: getHostInfo(log), } if c != nil { err := c.Unpack(p) @@ -94,22 +94,31 @@ func ContextProviderBuilder(log *logger.Logger, c *config.Config, _ bool) (corec return p, nil } -func getHostInfo() (map[string]interface{}, error) { - hostname, err := os.Hostname() - if err != nil { - return nil, err - } - sysInfo, err := sysinfo.Host() - if err != nil { - return nil, err +func getHostInfo(log *logger.Logger) func() (map[string]interface{}, error) { + return func() (map[string]interface{}, error) { + sysInfo, err := sysinfo.Host() + if err != nil { + return nil, err + } + + info := sysInfo.Info() + name := info.Hostname + if features.FQDN() { + fqdn, err := sysInfo.FQDN() + if err != nil { + log.Debugf("unable to lookup FQDN: %s, using hostname = %s", err.Error(), name) + } else { + name = fqdn + } + } + + return map[string]interface{}{ + "id": info.UniqueID, + "name": name, + "platform": runtime.GOOS, + "architecture": info.Architecture, + "ip": info.IPs, + "mac": info.MACs, + }, nil } - info := sysInfo.Info() - return map[string]interface{}{ - "id": info.UniqueID, - "name": hostname, - "platform": runtime.GOOS, - "architecture": info.Architecture, - "ip": info.IPs, - "mac": info.MACs, - }, nil } diff --git a/internal/pkg/composable/providers/host/host_test.go b/internal/pkg/composable/providers/host/host_test.go index 7cf2f208abd..1aefcefbf6e 100644 --- a/internal/pkg/composable/providers/host/host_test.go +++ b/internal/pkg/composable/providers/host/host_test.go @@ -21,8 +21,12 @@ import ( ) func TestContextProvider(t *testing.T) { + log, err := logger.New("host_test", false) + require.NoError(t, err) + // first call will have idx of 0 - starting, err := getHostInfo() + fetcher := getHostInfo(log) + starting, err := fetcher() starting["idx"] = 0 require.NoError(t, err) @@ -31,13 +35,11 @@ func TestContextProvider(t *testing.T) { }) require.NoError(t, err) builder, _ := composable.Providers.GetContextProvider("host") - log, err := logger.New("host_test", false) - require.NoError(t, err) provider, err := builder(log, c, true) require.NoError(t, err) hostProvider, _ := provider.(*contextProvider) - hostProvider.fetcher = returnHostMapping() + hostProvider.fetcher = returnHostMapping(log) require.Equal(t, 100*time.Millisecond, hostProvider.CheckInterval) ctx, cancel := context.WithCancel(context.Background()) @@ -72,7 +74,7 @@ func TestContextProvider(t *testing.T) { cancel() // next should have been set idx to 1 - next, err := getHostInfo() + next, err := fetcher() require.NoError(t, err) next["idx"] = 1 next, err = ctesting.CloneMap(next) @@ -80,10 +82,11 @@ func TestContextProvider(t *testing.T) { assert.Equal(t, next, comm.Current()) } -func returnHostMapping() infoFetcher { +func returnHostMapping(log *logger.Logger) infoFetcher { i := -1 + fetcher := getHostInfo(log) return func() (map[string]interface{}, error) { - host, err := getHostInfo() + host, err := fetcher() if err != nil { return nil, err } diff --git a/pkg/component/component.go b/pkg/component/component.go index 2b9ed7a0316..cf591e7ea03 100644 --- a/pkg/component/component.go +++ b/pkg/component/component.go @@ -15,6 +15,7 @@ import ( "github.com/elastic/elastic-agent-libs/logp" "github.com/elastic/elastic-agent/internal/pkg/agent/transpiler" "github.com/elastic/elastic-agent/internal/pkg/eql" + "github.com/elastic/elastic-agent/pkg/features" "github.com/elastic/elastic-agent/pkg/utils" ) @@ -94,6 +95,9 @@ type Component struct { // Units that should be running inside this component. Units []Unit `yaml:"units"` + // Features configuration the component should use. + Features *proto.Features `yaml:"features,omitempty"` + // Shipper references the component/unit that this component used as its output. (not set when ShipperSpec) Shipper *ShipperReference `yaml:"shipper,omitempty"` } @@ -148,6 +152,12 @@ func (r *RuntimeSpecs) PolicyToComponents( ll logp.Level, headers HeadersProvider, ) ([]Component, map[string]string, error) { + // get feature flags from policy + featureFlags, err := features.Parse(policy) + if err != nil { + return nil, nil, fmt.Errorf("could not parse feature flags from policy: %w", err) + } + outputsMap, err := toIntermediate(policy, r.aliasMapping, ll, headers) if err != nil { return nil, nil, err @@ -272,11 +282,13 @@ func (r *RuntimeSpecs) PolicyToComponents( Err: cfgErr, }) } + components = append(components, Component{ ID: componentID, Err: err, InputSpec: &inputSpec, Units: units, + Features: featureFlags.AsProto(), }) componentIdsInputMap[componentID] = inputSpec.BinaryName } @@ -314,6 +326,8 @@ func (r *RuntimeSpecs) PolicyToComponents( Config: cfg, Err: cfgErr, }) + component.Features = featureFlags.AsProto() + components[i] = component break } @@ -333,6 +347,7 @@ func (r *RuntimeSpecs) PolicyToComponents( ID: shipperCompID, ShipperSpec: &shipperSpec, Units: shipperUnits, + Features: featureFlags.AsProto(), }) } } diff --git a/pkg/component/fake/component/comp/actions.go b/pkg/component/fake/component/comp/actions.go index f70da876c0f..7ac7332bc20 100644 --- a/pkg/component/fake/component/comp/actions.go +++ b/pkg/component/fake/component/comp/actions.go @@ -16,6 +16,12 @@ import ( "github.com/elastic/elastic-agent-client/v7/pkg/client" ) +const ActionRetrieveFeatures = "retrieve_features" + +type retrieveFeaturesAction struct { + input *fakeInput +} + type stateSetterAction struct { input *fakeInput } @@ -45,6 +51,19 @@ func (s *stateSetterAction) Execute(_ context.Context, params map[string]interfa return nil, nil } +func (a *retrieveFeaturesAction) Name() string { + return ActionRetrieveFeatures +} + +func (a *retrieveFeaturesAction) Execute( + _ context.Context, + _ map[string]interface{}) (map[string]interface{}, error) { + + a.input.logger.Info().Msg("executing " + ActionRetrieveFeatures + " action") + + return map[string]interface{}{"features": a.input.features}, nil +} + func (s *sendEventAction) Name() string { return "send_event" } @@ -94,20 +113,23 @@ func (s *killAction) Execute(_ context.Context, _ map[string]interface{}) (map[s } func newRunningUnit(logger zerolog.Logger, manager *StateManager, unit *client.Unit) (runningUnit, error) { - _, logLevel, config := unit.Expected() - if config.Type == "" { + expected := unit.Expected() + if expected.Config.Type == "" { return nil, fmt.Errorf("unit config type empty") } if unit.Type() == client.UnitTypeOutput { - switch config.Type { + switch expected.Config.Type { case fakeShipper: - return newFakeShipperOutput(logger, logLevel, unit, config) + return newFakeShipperOutput( + logger, expected.LogLevel, unit, expected.Config) } - return nil, fmt.Errorf("unknown output unit config type: %s", config.Type) + return nil, fmt.Errorf("unknown output unit config type: %s", + expected.Config.Type) } - switch config.Type { + switch expected.Config.Type { case Fake: - return newFakeInput(logger, logLevel, manager, unit, config) + return newFakeInput(logger, expected.LogLevel, manager, unit, expected.Config) } - return nil, fmt.Errorf("unknown input unit config type: %s", config.Type) + return nil, fmt.Errorf("unknown input unit config type: %s", + expected.Config.Type) } diff --git a/pkg/component/fake/component/comp/component.go b/pkg/component/fake/component/comp/component.go index 6fdeaca27f3..25c4f688a90 100644 --- a/pkg/component/fake/component/comp/component.go +++ b/pkg/component/fake/component/comp/component.go @@ -73,28 +73,34 @@ func (s *StateManager) Added(unit *client.Unit) { s.inputs[unit.ID()] = r } -func (s *StateManager) Modified(unit *client.Unit) { - if unit.Type() == client.UnitTypeOutput { +func (s *StateManager) Modified(change client.UnitChanged) { + unit := change.Unit + switch unit.Type() { + case client.UnitTypeOutput: if s.output == nil { _ = unit.UpdateState(client.UnitStateFailed, "Error: modified a non-existing output unit", nil) return } - err := s.output.Update(unit) + err := s.output.Update(unit, client.TriggeredNothing) if err != nil { _ = unit.UpdateState(client.UnitStateFailed, fmt.Sprintf("Error: %s", err), nil) } return - } - existing, ok := s.inputs[unit.ID()] - if !ok { - _ = unit.UpdateState(client.UnitStateFailed, "Error: unknown unit", nil) + case client.UnitTypeInput: + existingInput, ok := s.inputs[unit.ID()] + if !ok { + _ = unit.UpdateState(client.UnitStateFailed, "Error: unknown unit", nil) + return + } + + err := existingInput.Update(unit, change.Triggers) + if err != nil { + _ = unit.UpdateState(client.UnitStateFailed, fmt.Sprintf("Error: %s", err), nil) + } + return } - err := existing.Update(unit) - if err != nil { - _ = unit.UpdateState(client.UnitStateFailed, fmt.Sprintf("Error: %s", err), nil) - } } func (s *StateManager) Removed(unit *client.Unit) { @@ -114,7 +120,7 @@ func (s *StateManager) Removed(unit *client.Unit) { type runningUnit interface { Unit() *client.Unit - Update(u *client.Unit) error + Update(u *client.Unit, triggers client.Trigger) error } type sendEvent struct { @@ -156,9 +162,9 @@ func (f *fakeShipperOutput) Unit() *client.Unit { return f.unit } -func (f *fakeShipperOutput) Update(u *client.Unit) error { - expected, _, config := u.Expected() - if expected == client.UnitStateStopped { +func (f *fakeShipperOutput) Update(u *client.Unit, triggers client.Trigger) error { + expected := u.Expected() + if expected.State == client.UnitStateStopped { // agent is requesting this input to stop f.logger.Debug().Str("state", client.UnitStateStopping.String()).Str("message", stoppingMsg).Msg("updating unit state") _ = u.UpdateState(client.UnitStateStopping, stoppingMsg, nil) @@ -170,16 +176,17 @@ func (f *fakeShipperOutput) Update(u *client.Unit) error { return nil } - if config.Type == "" { + if expected.Config.Type == "" { return fmt.Errorf("unit missing config type") } - if config.Type != fakeShipper { - return fmt.Errorf("unit type changed with the same unit ID: %s", config.Type) + if expected.Config.Type != fakeShipper { + return fmt.Errorf("unit type changed with the same unit ID: %s", + expected.Config.Type) } f.stop() - f.cfg = config - f.start(u, config) + f.cfg = expected.Config + f.start(u, expected.Config) return nil } @@ -281,6 +288,8 @@ type fakeInput struct { state client.UnitState stateMsg string + features *proto.Features + canceller context.CancelFunc killerCanceller context.CancelFunc } @@ -307,6 +316,8 @@ func newFakeInput(logger zerolog.Logger, logLevel client.UnitLogLevel, manager * unit.RegisterAction(&sendEventAction{i}) logger.Trace().Msg("registering kill action for unit") unit.RegisterAction(&killAction{i.logger}) + logger.Trace().Msg("registering " + ActionRetrieveFeatures + " action for unit") + unit.RegisterAction(&retrieveFeaturesAction{i}) logger.Debug(). Str("state", i.state.String()). @@ -347,37 +358,59 @@ func (f *fakeInput) Unit() *client.Unit { return f.unit } -func (f *fakeInput) Update(u *client.Unit) error { - expected, _, config := u.Expected() - if expected == client.UnitStateStopped { +func (f *fakeInput) Update(u *client.Unit, triggers client.Trigger) error { + expected := u.Expected() + if expected.State == client.UnitStateStopped { // agent is requesting this input to stop - f.logger.Debug().Str("state", client.UnitStateStopping.String()).Str("message", stoppingMsg).Msg("updating unit state") + f.logger.Debug(). + Str("state", client.UnitStateStopping.String()). + Str("message", stoppingMsg). + Msg("updating unit state") _ = u.UpdateState(client.UnitStateStopping, stoppingMsg, nil) f.canceller() go func() { <-time.After(1 * time.Second) - f.logger.Debug().Str("state", client.UnitStateStopped.String()).Str("message", stoppedMsg).Msg("updating unit state") + f.logger.Debug(). + Str("state", client.UnitStateStopped.String()). + Str("message", stoppedMsg). + Msg("updating unit state") _ = u.UpdateState(client.UnitStateStopped, stoppedMsg, nil) }() return nil } - if config.Type == "" { + if expected.Config.Type == "" { return fmt.Errorf("unit missing config type") } - if config.Type != Fake { - return fmt.Errorf("unit type changed with the same unit ID: %s", config.Type) + if expected.Config.Type != Fake { + return fmt.Errorf("unit type changed with the same unit ID: %s", + expected.Config.Type) } - f.parseConfig(config) - state, stateMsg, err := getStateFromConfig(config) + f.parseConfig(expected.Config) + state, stateMsg, err := getStateFromConfig(expected.Config) if err != nil { return fmt.Errorf("unit config parsing error: %w", err) } + f.state = state f.stateMsg = stateMsg - f.logger.Debug().Str("state", f.state.String()).Str("message", f.stateMsg).Msg("updating unit state") + f.logger.Debug(). + Str("state", f.state.String()). + Str("message", f.stateMsg). + Msg("updating unit state") _ = u.UpdateState(f.state, f.stateMsg, nil) + + if triggers&client.TriggeredFeatureChange == client.TriggeredFeatureChange { + f.logger.Info(). + Interface("features", expected.Features). + Msg("updating features") + f.features = &proto.Features{ + Source: nil, + Fqdn: &proto.FQDNFeature{Enabled: expected.Features.Fqdn.Enabled}, + } + } + return nil } diff --git a/pkg/component/fake/component/main.go b/pkg/component/fake/component/main.go index a7e3f9e0915..a4339478af5 100644 --- a/pkg/component/fake/component/main.go +++ b/pkg/component/fake/component/main.go @@ -13,10 +13,11 @@ import ( "os/signal" "syscall" + "github.com/elastic/elastic-agent/pkg/component/fake/component/comp" + "github.com/rs/zerolog" "github.com/elastic/elastic-agent-client/v7/pkg/client" - "github.com/elastic/elastic-agent/pkg/component/fake/component/comp" ) func main() { @@ -68,10 +69,11 @@ func run() error { return nil case change := <-c.UnitChanges(): switch change.Type { + case client.UnitChangedAdded: s.Added(change.Unit) case client.UnitChangedModified: - s.Modified(change.Unit) + s.Modified(change) case client.UnitChangedRemoved: s.Removed(change.Unit) } diff --git a/pkg/component/fake/shipper/actions.go b/pkg/component/fake/shipper/actions.go index 6e4b69762ea..0e78033dd81 100644 --- a/pkg/component/fake/shipper/actions.go +++ b/pkg/component/fake/shipper/actions.go @@ -37,22 +37,22 @@ func (s *killAction) Execute(_ context.Context, _ map[string]interface{}) (map[s } func newRunningUnit(logger zerolog.Logger, manager *stateManager, unit *client.Unit) (runningUnit, error) { - _, logLevel, config := unit.Expected() - if config.Type == "" { + expected := unit.Expected() + if expected.Config.Type == "" { return nil, fmt.Errorf("unit config type empty") } if unit.Type() == client.UnitTypeOutput { - switch config.Type { + switch expected.Config.Type { case fakeActionOutput: - return newFakeActionOutputRuntime(logger, logLevel, unit, config) + return newFakeActionOutputRuntime(logger, expected.LogLevel, unit, expected.Config) } - return nil, fmt.Errorf("unknown output unit config type: %s", config.Type) + return nil, fmt.Errorf("unknown output unit config type: %s", expected.Config.Type) } else if unit.Type() == client.UnitTypeInput { - switch config.Type { + switch expected.Config.Type { case fakeShipper: - return newFakeShipperInput(logger, logLevel, manager, unit, config) + return newFakeShipperInput(logger, expected.LogLevel, manager, unit, expected.Config) } - return nil, fmt.Errorf("unknown input unit config type: %s", config.Type) + return nil, fmt.Errorf("unknown input unit config type: %s", expected.Config.Type) } return nil, fmt.Errorf("unknown unit type: %+v", unit.Type()) } diff --git a/pkg/component/fake/shipper/main.go b/pkg/component/fake/shipper/main.go index b9541913d5c..1f1376cd4aa 100644 --- a/pkg/component/fake/shipper/main.go +++ b/pkg/component/fake/shipper/main.go @@ -238,8 +238,8 @@ func (f *fakeActionOutputRuntime) Unit() *client.Unit { } func (f *fakeActionOutputRuntime) Update(u *client.Unit) error { - expected, _, config := u.Expected() - if expected == client.UnitStateStopped { + expected := u.Expected() + if expected.State == client.UnitStateStopped { // agent is requesting this to stop f.logger.Debug().Str("state", client.UnitStateStopping.String()).Str("message", stoppingMsg).Msg("updating unit state") _ = u.UpdateState(client.UnitStateStopping, stoppingMsg, nil) @@ -251,11 +251,12 @@ func (f *fakeActionOutputRuntime) Update(u *client.Unit) error { return nil } - if config.Type == "" { + if expected.Config.Type == "" { return fmt.Errorf("unit missing config type") } - if config.Type != fakeActionOutput { - return fmt.Errorf("unit type changed with the same unit ID: %s", config.Type) + if expected.Config.Type != fakeActionOutput { + return fmt.Errorf("unit type changed with the same unit ID: %s", + expected.Config.Type) } // nothing to really do return nil @@ -380,28 +381,40 @@ func (f *fakeShipperInput) Unit() *client.Unit { } func (f *fakeShipperInput) Update(u *client.Unit) error { - expected, _, config := u.Expected() - if expected == client.UnitStateStopped { + if u.Type() != client.UnitTypeOutput { + return nil // right now, it deals only with output + } + + expected := u.Expected() + if expected.State == client.UnitStateStopped { // agent is requesting this to stop - f.logger.Debug().Str("state", client.UnitStateStopping.String()).Str("message", stoppingMsg).Msg("updating unit state") + f.logger.Debug(). + Str("state", client.UnitStateStopping.String()). + Str("message", stoppingMsg). + Msg("updating unit state") _ = u.UpdateState(client.UnitStateStopping, stoppingMsg, nil) + go func() { if f.srv != nil { f.srv.Stop() _ = f.wg.Wait() f.srv = nil } - f.logger.Debug().Str("state", client.UnitStateStopped.String()).Str("message", stoppedMsg).Msg("updating unit state") + f.logger.Debug(). + Str("state", client.UnitStateStopped.String()). + Str("message", stoppedMsg). + Msg("updating unit state") _ = u.UpdateState(client.UnitStateStopped, stoppedMsg, nil) }() return nil } - if config.Type == "" { + if expected.Config.Type == "" { return fmt.Errorf("unit missing config type") } - if config.Type != fakeActionOutput { - return fmt.Errorf("unit type changed with the same unit ID: %s", config.Type) + if expected.Config.Type != fakeActionOutput { + return fmt.Errorf("unit type changed with the same unit ID: %s", + expected.Config.Type) } // nothing to really do return nil diff --git a/pkg/component/runtime/failed.go b/pkg/component/runtime/failed.go index b495eeb4d2a..22a16abd88a 100644 --- a/pkg/component/runtime/failed.go +++ b/pkg/component/runtime/failed.go @@ -97,8 +97,9 @@ func createState(comp component.Component, done bool) ComponentState { } } return ComponentState{ - State: state, - Message: comp.Err.Error(), - Units: unitErrs, + State: state, + Message: comp.Err.Error(), + Units: unitErrs, + Features: comp.Features, } } diff --git a/pkg/component/runtime/manager_test.go b/pkg/component/runtime/manager_test.go index dfa5c1ad804..8d0e808a860 100644 --- a/pkg/component/runtime/manager_test.go +++ b/pkg/component/runtime/manager_test.go @@ -16,19 +16,22 @@ import ( "testing" "time" - "github.com/gofrs/uuid" + fakecmp "github.com/elastic/elastic-agent/pkg/component/fake/component/comp" + "github.com/gofrs/uuid" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.elastic.co/apm/apmtest" "github.com/elastic/elastic-agent-client/v7/pkg/client" + "github.com/elastic/elastic-agent-client/v7/pkg/proto" "github.com/elastic/elastic-agent-libs/logp" - "github.com/elastic/elastic-agent/internal/pkg/agent/application/info" "github.com/elastic/elastic-agent/internal/pkg/agent/application/paths" "github.com/elastic/elastic-agent/internal/pkg/agent/configuration" "github.com/elastic/elastic-agent/pkg/component" "github.com/elastic/elastic-agent/pkg/core/logger" + "github.com/elastic/elastic-agent/pkg/features" ) const ( @@ -294,6 +297,211 @@ LOOP: require.ErrorIs(t, err, os.ErrNotExist) } +func TestManager_FakeInput_Features(t *testing.T) { + testPaths(t) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + agentInfo, _ := info.NewAgentInfo(true) + m, err := NewManager( + newDebugLogger(t), + newDebugLogger(t), + "localhost:0", + agentInfo, + apmtest.DiscardTracer, + newTestMonitoringMgr(), + configuration.DefaultGRPCConfig()) + require.NoError(t, err) + + managerErrCh := make(chan error) + go func() { + err := m.Run(ctx) + if errors.Is(err, context.Canceled) { + err = nil + } + managerErrCh <- err + }() + + waitCtx, waitCancel := context.WithTimeout(ctx, 1*time.Second) + defer waitCancel() + if err := m.WaitForReady(waitCtx); err != nil { + require.NoError(t, err) + } + + binaryPath := testBinary(t, "component") + const compID = "fake-default" + comp := component.Component{ + ID: compID, + InputSpec: &component.InputRuntimeSpec{ + InputType: "fake", + BinaryName: "", + BinaryPath: binaryPath, + Spec: fakeInputSpec, + }, + Units: []component.Unit{ + { + ID: "fake-input", + Type: client.UnitTypeInput, + LogLevel: client.UnitLogLevelTrace, + Config: component.MustExpectedConfig(map[string]interface{}{ + "type": "fake", + "state": int(client.UnitStateHealthy), + "message": "Fake Healthy", + }), + }, + }, + } + + subscriptionCtx, subCancel := context.WithCancel(context.Background()) + defer subCancel() + subscriptionErrCh := make(chan error) + doneCh := make(chan struct{}) + + go func() { + sub := m.Subscribe(subscriptionCtx, compID) + var healthIteration int + + for { + select { + case <-subscriptionCtx.Done(): + return + case componentState := <-sub.Ch(): + t.Logf("component state changed: %+v", componentState) + + if componentState.State == client.UnitStateFailed { + subscriptionErrCh <- fmt.Errorf("component failed: %s", componentState.Message) + return + } + + unit, ok := componentState.Units[ComponentUnitKey{UnitType: client.UnitTypeInput, UnitID: "fake-input"}] + if !ok { + subscriptionErrCh <- errors.New("unit missing: fake-input") + return + } + + switch unit.State { + case client.UnitStateFailed: + subscriptionErrCh <- fmt.Errorf("unit failed: %s", unit.Message) + + case client.UnitStateHealthy: + healthIteration++ + switch healthIteration { + case 1: // yes, it's starting on 1 + comp.Features = &proto.Features{ + Fqdn: &proto.FQDNFeature{Enabled: true}, + } + + err := m.Update([]component.Component{comp}) + if err != nil { + subscriptionErrCh <- fmt.Errorf("[case %d]: failed to update component: %w", + healthIteration, err) + return + } + + // check if config sent on iteration 1 was set + case 2: + // In the previous iteration, the (fake) component has received a CheckinExpected + // message to enable the feature flag for FQDN. In this iteration we are about to + // retrieve the feature flags information from the same component via the retrieve_features + // action. Within the component, which is running as a separate process, actions + // and CheckinExpected messages are processed concurrently. We need some way to wait + // a reasonably short amount of time for the CheckinExpected message to be applied by the + // component (thus setting the FQDN feature flag to true) before we as the same component + // for feature flags information. We accomplish this via assert.Eventually. + assert.Eventuallyf(t, func() bool { + // check the component + res, err := m.PerformAction( + context.Background(), + comp, + comp.Units[0], + fakecmp.ActionRetrieveFeatures, + nil) + if err != nil { + subscriptionErrCh <- fmt.Errorf("[case %d]: failed to PerformAction %s: %w", + healthIteration, fakecmp.ActionRetrieveFeatures, err) + return false + } + + ff, err := features.Parse(map[string]any{"agent": res}) + if err != nil { + subscriptionErrCh <- fmt.Errorf("[case %d]: failed to parse action %s response as features config: %w", + healthIteration, fakecmp.ActionRetrieveFeatures, err) + return false + } + + return ff.FQDN() + }, 1*time.Second, 100*time.Millisecond, "failed to assert that FQDN feature flag was enabled by component") + + doneCh <- struct{}{} + } + + case client.UnitStateStarting: + // acceptable + + case client.UnitStateConfiguring: + // set unit back to healthy, so other cases will run. + comp.Units[0].Config = component.MustExpectedConfig(map[string]interface{}{ + "type": "fake", + "state": int(client.UnitStateHealthy), + "message": "Fake Healthy", + }) + + err := m.Update([]component.Component{comp}) + if err != nil { + t.Logf("error updating component state to health: %v", err) + + subscriptionErrCh <- fmt.Errorf("failed to update component: %w", err) + } + + default: + // unexpected state that should not have occurred + subscriptionErrCh <- fmt.Errorf("unit reported unexpected state: %v", + unit.State) + } + + } + } + }() + + defer drainErrChan(managerErrCh) + defer drainErrChan(subscriptionErrCh) + + startTimer := time.NewTimer(100 * time.Millisecond) + defer startTimer.Stop() + + select { + case <-startTimer.C: + err = m.Update([]component.Component{comp}) + require.NoError(t, err) + case err := <-managerErrCh: + t.Fatalf("manager failed early: %s", err) + } + + timeout := 30 * time.Second + timeoutTimer := time.NewTimer(timeout) + defer timeoutTimer.Stop() + + // Wait for a success, an error or time out + for { + select { + case <-timeoutTimer.C: + t.Fatalf("timed out after %s", timeout) + case err := <-managerErrCh: + require.NoError(t, err) + case err := <-subscriptionErrCh: + require.NoError(t, err) + case <-doneCh: + subCancel() + cancel() + + err = <-managerErrCh + require.NoError(t, err) + return + } + } +} + func TestManager_FakeInput_BadUnitToGood(t *testing.T) { testPaths(t) @@ -1946,8 +2154,16 @@ func TestManager_FakeInput_LogLevel(t *testing.T) { defer cancel() ai, _ := info.NewAgentInfo(true) - m, err := NewManager(newDebugLogger(t), newDebugLogger(t), "localhost:0", ai, apmtest.DiscardTracer, newTestMonitoringMgr(), configuration.DefaultGRPCConfig()) + m, err := NewManager( + newDebugLogger(t), + newDebugLogger(t), + "localhost:0", + ai, + apmtest.DiscardTracer, + newTestMonitoringMgr(), + configuration.DefaultGRPCConfig()) require.NoError(t, err) + errCh := make(chan error) go func() { err := m.Run(ctx) @@ -2332,13 +2548,14 @@ func TestManager_FakeShipper(t *testing.T) { t.Fatalf("failed early: %s", err) } - endTimer := time.NewTimer(2 * time.Minute) + timeout := 2 * time.Minute + endTimer := time.NewTimer(timeout) defer endTimer.Stop() LOOP: for { select { case <-endTimer.C: - t.Fatalf("timed out after 2 minutes") + t.Fatalf("timed out after %s", timeout) case err := <-errCh: require.NoError(t, err) case err := <-subErrCh: @@ -2647,23 +2864,23 @@ func testBinary(t *testing.T, name string) string { t.Helper() var err error - binaryPath := filepath.Join("..", "fake", name, name) + binaryPath := fakeBinaryPath(name) + binaryPath, err = filepath.Abs(binaryPath) if err != nil { t.Fatalf("failed abs %s: %s", binaryPath, err) } + + return binaryPath +} + +func fakeBinaryPath(name string) string { + binaryPath := filepath.Join("..", "fake", name, name) + if runtime.GOOS == component.Windows { binaryPath += exeExt - } else { - err = os.Chown(binaryPath, os.Geteuid(), os.Getgid()) - if err != nil { - t.Fatalf("failed chown %s: %s", binaryPath, err) - } - err = os.Chmod(binaryPath, 0755) - if err != nil { - t.Fatalf("failed chmod %s: %s", binaryPath, err) - } } + return binaryPath } diff --git a/pkg/component/runtime/state.go b/pkg/component/runtime/state.go index 868c87e02f0..4f8dcc24221 100644 --- a/pkg/component/runtime/state.go +++ b/pkg/component/runtime/state.go @@ -59,10 +59,18 @@ type ComponentState struct { Units map[ComponentUnitKey]ComponentUnitState `yaml:"units"` + // We don't serialize the Features field as YAML so it doesn't show up + // in the diagnostics-generated state.yaml file, keeping it concise. + Features *proto.Features `yaml:"-"` + FeaturesIdx uint64 `yaml:"features_idx"` + VersionInfo ComponentVersionInfo `yaml:"version_info"` // internal expectedUnits map[ComponentUnitKey]expectedUnitState + + expectedFeatures *proto.Features + expectedFeaturesIdx uint64 } // expectedUnitState is the expected state of a unit. @@ -79,6 +87,7 @@ func newComponentState(comp *component.Component) (s ComponentState) { s.Message = startingMsg s.Units = make(map[ComponentUnitKey]ComponentUnitState) s.expectedUnits = make(map[ComponentUnitKey]expectedUnitState) + s.syncComponent(comp) return s } @@ -94,6 +103,12 @@ func (s *ComponentState) Copy() (c ComponentState) { for k, v := range s.expectedUnits { c.expectedUnits[k] = v } + + c.Features = s.Features + c.FeaturesIdx = s.FeaturesIdx + c.expectedFeatures = s.expectedFeatures + c.expectedFeaturesIdx = s.expectedFeaturesIdx + return c } @@ -159,6 +174,15 @@ func (s *ComponentState) syncExpected(comp *component.Component) bool { } } } + + if !gproto.Equal(s.expectedFeatures, comp.Features) { + changed = true + s.expectedFeaturesIdx++ + s.expectedFeatures = comp.Features + } else { + s.expectedFeaturesIdx = 1 + } + return changed } @@ -212,6 +236,12 @@ func (s *ComponentState) syncUnits(comp *component.Component) bool { } } } + + if !gproto.Equal(s.Features, comp.Features) { + s.Features = comp.Features + changed = true + } + return changed } @@ -260,6 +290,7 @@ func (s *ComponentState) syncCheckin(checkin *proto.CheckinObserved) bool { } s.Units[key] = existing } + for key, unit := range s.Units { _, ok := touched[key] if !ok { @@ -284,8 +315,10 @@ func (s *ComponentState) syncCheckin(checkin *proto.CheckinObserved) bool { } } } + s.Units[key] = unit } + if checkin.VersionInfo != nil { if checkin.VersionInfo.Name != "" && s.VersionInfo.Name != checkin.VersionInfo.Name { s.VersionInfo.Name = checkin.VersionInfo.Name @@ -300,6 +333,19 @@ func (s *ComponentState) syncCheckin(checkin *proto.CheckinObserved) bool { changed = true } } + + if s.FeaturesIdx != checkin.FeaturesIdx { + s.FeaturesIdx = checkin.FeaturesIdx + if checkin.Features != nil { + s.Features = &proto.Features{ + Fqdn: &proto.FQDNFeature{ + Enabled: checkin.Features.Fqdn.Enabled, + }, + } + } + changed = true + } + return changed } @@ -315,13 +361,14 @@ func (s *ComponentState) unsettled() bool { // unit missing return true } - if o.configStateIdx != e.configStateIdx || e.state != o.State { + if o.configStateIdx != e.configStateIdx || + e.state != o.State { // config or state mismatch return true } } - return false + return s.FeaturesIdx != s.expectedFeaturesIdx } func (s *ComponentState) toCheckinExpected() *proto.CheckinExpected { @@ -353,7 +400,11 @@ func (s *ComponentState) toCheckinExpected() *proto.CheckinExpected { units = append(units, e) } - return &proto.CheckinExpected{Units: units} + return &proto.CheckinExpected{ + Units: units, + Features: s.expectedFeatures, + FeaturesIdx: s.expectedFeaturesIdx, + } } func (s *ComponentState) cleanupStopped() bool { diff --git a/pkg/features/features.go b/pkg/features/features.go new file mode 100644 index 00000000000..297e735fde3 --- /dev/null +++ b/pkg/features/features.go @@ -0,0 +1,146 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package features + +import ( + "encoding/json" + "fmt" + "sync" + + "github.com/elastic/elastic-agent-client/v7/pkg/proto" + "github.com/elastic/elastic-agent/internal/pkg/config" + + "google.golang.org/protobuf/types/known/structpb" +) + +var ( + current = Flags{} +) + +type Flags struct { + mu sync.RWMutex + source *structpb.Struct + fqdn bool +} + +type cfg struct { + Agent struct { + Features struct { + FQDN struct { + Enabled bool `json:"enabled" yaml:"enabled" config:"enabled"` + } `json:"fqdn" yaml:"fqdn" config:"fqdn"` + } `json:"features" yaml:"features" config:"features"` + } `json:"agent" yaml:"agent" config:"agent"` +} + +func (f *Flags) FQDN() bool { + f.mu.RLock() + defer f.mu.RUnlock() + + return f.fqdn +} + +func (f *Flags) AsProto() *proto.Features { + return &proto.Features{ + Fqdn: &proto.FQDNFeature{ + Enabled: f.FQDN(), + }, + Source: f.source, + } +} + +// setFQDN sets the value of the FQDN flag in Flags. +func (f *Flags) setFQDN(newValue bool) { + f.mu.Lock() + defer f.mu.Unlock() + + f.fqdn = newValue +} + +// setSource sets the source from he given cfg. +func (f *Flags) setSource(c cfg) error { + // Use JSON marshalling-unmarshalling to convert cfg to mapstr + data, err := json.Marshal(c) + if err != nil { + return fmt.Errorf("could not convert feature flags configuration to JSON: %w", err) + } + + var s map[string]interface{} + if err := json.Unmarshal(data, &s); err != nil { + return fmt.Errorf("could not convert feature flags JSON to mapstr: %w", err) + } + + source, err := structpb.NewStruct(s) + if err != nil { + return fmt.Errorf("unable to create source from feature flags configuration: %w", err) + } + + f.source = source + return nil +} + +// Parse receives a policy, parses and returns it. +// policy can be a *config.Config, config.Config or anything config.NewConfigFrom +// can work with. If policy is nil, Parse is a no-op. +func Parse(policy any) (*Flags, error) { + if policy == nil { + return nil, nil + } + + var c *config.Config + switch policy.(type) { + case *config.Config: + c = (policy).(*config.Config) + case config.Config: + aa := (policy).(config.Config) + c = &aa + default: + var err error + c, err = config.NewConfigFrom(policy) + if err != nil { + return nil, fmt.Errorf("could not get a config from type %T: %w", + policy, err) + } + } + + if c == nil { + return nil, nil + } + + parsedFlags := cfg{} + if err := c.Unpack(&parsedFlags); err != nil { + return nil, fmt.Errorf("could not umpack features config: %w", err) + } + + flags := new(Flags) + flags.setFQDN(parsedFlags.Agent.Features.FQDN.Enabled) + if err := flags.setSource(parsedFlags); err != nil { + return nil, fmt.Errorf("error creating feature flags source: %w", err) + } + + return flags, nil +} + +// Apply receives a config and applies it. If c is nil, Apply is a no-op. +func Apply(c *config.Config) error { + if c == nil { + return nil + } + + var err error + + parsed, err := Parse(c) // Updating global state + if err != nil { + return fmt.Errorf("could not apply feature flag config: %w", err) + } + + current.setFQDN(parsed.FQDN()) + return err +} + +// FQDN reports if FQDN should be used instead of hostname for host.name. +func FQDN() bool { + return current.FQDN() +} diff --git a/pkg/features/features_test.go b/pkg/features/features_test.go new file mode 100644 index 00000000000..a46d723154d --- /dev/null +++ b/pkg/features/features_test.go @@ -0,0 +1,81 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package features + +import ( + "testing" + + "github.com/elastic/elastic-agent/internal/pkg/config" +) + +func TestFQDN(t *testing.T) { + tcs := []struct { + name string + yaml string + want bool + }{ + { + name: "FQDN enabled", + yaml: ` +agent: + features: + fqdn: + enabled: true`, + want: true, + }, + { + name: "FQDN disabled", + yaml: ` +agent: + features: + fqdn: + enabled: false`, + want: false, + }, + { + name: "FQDN only {}", + yaml: ` +agent: + features: + fqdn: {}`, + want: false, + }, + { + name: "FQDN empty", + yaml: ` +agent: + features: + fqdn:`, + want: false, + }, + { + name: "FQDN absent", + yaml: ` +agent: + features:`, + want: false, + }, + } + + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + + c, err := config.NewConfigFrom(tc.yaml) + if err != nil { + t.Fatalf("could not parse config YAML: %v", err) + } + + err = Apply(c) + if err != nil { + t.Fatalf("Apply failed: %v", err) + } + + got := FQDN() + if got != tc.want { + t.Errorf("want: %t, got %t", tc.want, got) + } + }) + } +}