From 0c2a6c1a29ccd6f7b42baf8423bd0935b706ecd2 Mon Sep 17 00:00:00 2001 From: Blake Rouse Date: Mon, 29 Aug 2022 16:17:32 -0400 Subject: [PATCH] [v2] Switch to Elastic Agent v2 control protocol (#1751) * Switch to new client.V2 for communication with Elastic Agent. * Fix tests. * Fix integration tests. * Update go.sum. * Fix some lint issues. * Fix panic with agentInfo. * Fix panic in logger reconfigure. * Fixes for switching units. --- NOTICE.txt | 1003 ++++++--------------- cmd/fleet/main.go | 487 ++++++---- cmd/fleet/main_integration_test.go | 378 +++++--- cmd/fleet/server_integration_test.go | 40 +- go.mod | 15 +- go.sum | 26 +- internal/pkg/api/handleStatus.go | 14 +- internal/pkg/api/handleStatus_test.go | 17 +- internal/pkg/logger/logger.go | 2 +- internal/pkg/policy/policy_output_test.go | 4 +- internal/pkg/policy/self.go | 80 +- internal/pkg/policy/self_test.go | 84 +- internal/pkg/state/reporter.go | 51 ++ internal/pkg/status/reporter.go | 53 -- 14 files changed, 1087 insertions(+), 1167 deletions(-) create mode 100644 internal/pkg/state/reporter.go delete mode 100644 internal/pkg/status/reporter.go diff --git a/NOTICE.txt b/NOTICE.txt index 823aca275..85b28508f 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -330,11 +330,11 @@ these terms. -------------------------------------------------------------------------------- Dependency : github.com/elastic/elastic-agent-client/v7 -Version: v7.0.0-20210922110810-e6f1f402a9ed +Version: v7.0.0-20220804181728-b0328d2fe484 Licence type (autodetected): Elastic -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/elastic/elastic-agent-client/v7@v7.0.0-20210922110810-e6f1f402a9ed/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/elastic/elastic-agent-client/v7@v7.0.0-20220804181728-b0328d2fe484/LICENSE.txt: ELASTIC LICENSE AGREEMENT @@ -3964,6 +3964,255 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- +Dependency : google.golang.org/grpc +Version: v1.46.0 +Licence type (autodetected): Apache-2.0 +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/google.golang.org/grpc@v1.46.0/LICENSE: + + + Apache License + Version 2.0, January 2004 + http://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 + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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 + + http://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 : google.golang.org/protobuf +Version: v1.28.0 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/google.golang.org/protobuf@v1.28.0/LICENSE: + +Copyright (c) 2018 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. + + ================================================================================ @@ -10122,11 +10371,11 @@ limitations under the License. -------------------------------------------------------------------------------- Dependency : github.com/envoyproxy/go-control-plane -Version: v0.10.1 +Version: v0.10.2-0.20220325020618-49ff273808a1 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/envoyproxy/go-control-plane@v0.10.1/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/envoyproxy/go-control-plane@v0.10.2-0.20220325020618-49ff273808a1/LICENSE: Apache License Version 2.0, January 2004 @@ -13975,225 +14224,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- -Dependency : github.com/grpc-ecosystem/go-grpc-middleware -Version: v1.3.0 -Licence type (autodetected): Apache-2.0 +Dependency : github.com/grpc-ecosystem/grpc-gateway +Version: v1.16.0 +Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/grpc-ecosystem/go-grpc-middleware@v1.3.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/grpc-ecosystem/grpc-gateway@v1.16.0/LICENSE.txt: - Apache License - Version 2.0, January 2004 - http://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 - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 - - http://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/grpc-ecosystem/grpc-gateway -Version: v1.16.0 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/grpc-ecosystem/grpc-gateway@v1.16.0/LICENSE.txt: - -Copyright (c) 2015, Gengo, Inc. -All rights reserved. +Copyright (c) 2015, Gengo, Inc. +All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -23386,252 +23425,41 @@ Contents of probable licence file $GOMODCACHE/github.com/opencontainers/image-sp -------------------------------------------------------------------------------- -Dependency : github.com/opentracing/opentracing-go -Version: v1.1.0 -Licence type (autodetected): Apache-2.0 +Dependency : github.com/otiai10/copy +Version: v1.2.0 +Licence type (autodetected): MIT -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/opentracing/opentracing-go@v1.1.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/otiai10/copy@v1.2.0/LICENSE: - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ +The MIT License (MIT) - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +Copyright (c) 2018 otiai10 - 1. Definitions. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER 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. - "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 - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2016 The OpenTracing 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 - - http://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/otiai10/copy -Version: v1.2.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/otiai10/copy@v1.2.0/LICENSE: - -The MIT License (MIT) - -Copyright (c) 2018 otiai10 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER 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/pascaldekloe/goe -Version: v0.1.0 -Licence type (autodetected): CC0 --------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +Dependency : github.com/pascaldekloe/goe +Version: v0.1.0 +Licence type (autodetected): CC0 +-------------------------------------------------------------------------------- Contents of probable licence file $GOMODCACHE/github.com/pascaldekloe/goe@v0.1.0/LICENSE: @@ -28978,11 +28806,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- Dependency : golang.org/x/net -Version: v0.0.0-20220225172249-27dd8689420f +Version: v0.0.0-20220425223048-2871e0cb64e4 Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/golang.org/x/net@v0.0.0-20220225172249-27dd8689420f/LICENSE: +Contents of probable licence file $GOMODCACHE/golang.org/x/net@v0.0.0-20220425223048-2871e0cb64e4/LICENSE: Copyright (c) 2009 The Go Authors. All rights reserved. @@ -29052,11 +28880,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- Dependency : golang.org/x/sys -Version: v0.0.0-20220405052023-b1e9470b6e64 +Version: v0.0.0-20220422013727-9388b58f7150 Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/golang.org/x/sys@v0.0.0-20220405052023-b1e9470b6e64/LICENSE: +Contents of probable licence file $GOMODCACHE/golang.org/x/sys@v0.0.0-20220422013727-9388b58f7150/LICENSE: Copyright (c) 2009 The Go Authors. All rights reserved. @@ -29486,223 +29314,11 @@ Contents of probable licence file $GOMODCACHE/google.golang.org/appengine@v1.6.7 -------------------------------------------------------------------------------- Dependency : google.golang.org/genproto -Version: v0.0.0-20211208223120-3a66f561d7aa +Version: v0.0.0-20220426171045-31bebdecfb46 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/google.golang.org/genproto@v0.0.0-20211208223120-3a66f561d7aa/LICENSE: - - - Apache License - Version 2.0, January 2004 - http://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 - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 - - http://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 : google.golang.org/grpc -Version: v1.43.0 -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/google.golang.org/grpc@v1.43.0/LICENSE: +Contents of probable licence file $GOMODCACHE/google.golang.org/genproto@v0.0.0-20220426171045-31bebdecfb46/LICENSE: Apache License @@ -30332,43 +29948,6 @@ Contents of probable licence file $GOMODCACHE/google.golang.org/grpc/examples@v0 limitations under the License. --------------------------------------------------------------------------------- -Dependency : google.golang.org/protobuf -Version: v1.27.1 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/google.golang.org/protobuf@v1.27.1/LICENSE: - -Copyright (c) 2018 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 : gopkg.in/alecthomas/kingpin.v2 Version: v2.2.6 diff --git a/cmd/fleet/main.go b/cmd/fleet/main.go index a28ec50c3..61618eb12 100644 --- a/cmd/fleet/main.go +++ b/cmd/fleet/main.go @@ -42,7 +42,7 @@ import ( "github.com/elastic/fleet-server/v7/internal/pkg/scheduler" "github.com/elastic/fleet-server/v7/internal/pkg/signal" "github.com/elastic/fleet-server/v7/internal/pkg/sleep" - "github.com/elastic/fleet-server/v7/internal/pkg/status" + "github.com/elastic/fleet-server/v7/internal/pkg/state" "github.com/elastic/fleet-server/v7/internal/pkg/ver" "github.com/hashicorp/go-version" @@ -52,14 +52,17 @@ import ( "golang.org/x/sync/errgroup" "github.com/elastic/elastic-agent-client/v7/pkg/client" - "github.com/elastic/elastic-agent-client/v7/pkg/proto" ) const ( kAgentMode = "agent-mode" kAgentModeRestartLoopDelay = 2 * time.Second + kFleetServer = "fleet-server" kUAFleetServer = "Fleet-Server" + kElasticsearch = "elasticsearch" + + kStopped = "Stopped" ) func init() { @@ -162,12 +165,12 @@ func getRunCommand(bi build.Info) func(cmd *cobra.Command, args []string) error return err } - srv, err := NewFleetServer(cfg, bi, status.NewLog()) + srv, err := NewFleetServer(bi, state.NewLog()) if err != nil { return err } - runErr = srv.Run(installSignalHandler()) + runErr = srv.Run(installSignalHandler(), cfg) } if runErr != nil && !errors.Is(runErr, context.Canceled) { @@ -192,24 +195,20 @@ func NewCommand(bi build.Info) *cobra.Command { return cmd } -type firstCfg struct { - cfg *config.Config - err error -} - type AgentMode struct { cliCfg *ucfg.Config bi build.Info reloadables []reload.Reloadable - agent client.Client + agent client.V2 + + outputUnit *client.Unit + inputUnit *client.Unit - mux sync.Mutex - firstCfg chan firstCfg srv *FleetServer srvCtx context.Context srvCanceller context.CancelFunc - startChan chan struct{} + srvDone chan bool } func NewAgentMode(cliCfg *ucfg.Config, reader io.Reader, bi build.Info, reloadables ...reload.Reloadable) (*AgentMode, error) { @@ -220,7 +219,14 @@ func NewAgentMode(cliCfg *ucfg.Config, reader io.Reader, bi build.Info, reloadab bi: bi, reloadables: reloadables, } - a.agent, err = client.NewFromReader(reader, a) + a.agent, _, err = client.NewV2FromReader(reader, client.VersionInfo{ + Name: kFleetServer, + Version: bi.Version, + Meta: map[string]string{ + "commit": bi.Commit, + "build_time": bi.BuildTime.String(), + }, + }) if err != nil { return nil, err } @@ -228,218 +234,356 @@ func NewAgentMode(cliCfg *ucfg.Config, reader io.Reader, bi build.Info, reloadab } func (a *AgentMode) Run(ctx context.Context) error { - ctx, canceller := context.WithCancel(ctx) - defer canceller() + subCtx, subCanceller := context.WithCancel(ctx) + defer subCanceller() + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + + t := time.NewTicker(1 * time.Second) + defer t.Stop() + for { + select { + case <-subCtx.Done(): + return + case err := <-a.agent.Errors(): + if err != nil && !errors.Is(err, context.Canceled) && !errors.Is(err, io.EOF) { + log.Error().Err(err) + } + case change := <-a.agent.UnitChanges(): + switch change.Type { + case client.UnitChangedAdded: + err := a.unitAdded(subCtx, change.Unit) + if err != nil { + log.Error().Str("unit", change.Unit.ID()).Err(err) + _ = change.Unit.UpdateState(client.UnitStateFailed, err.Error(), nil) + } + case client.UnitChangedModified: + err := a.unitModified(subCtx, change.Unit) + if err != nil { + log.Error().Str("unit", change.Unit.ID()).Err(err) + _ = change.Unit.UpdateState(client.UnitStateFailed, err.Error(), nil) + } + case client.UnitChangedRemoved: + a.unitRemoved(change.Unit) + } + case <-t.C: + // Fleet Server is the only component that gets started by Elastic Agent without an Agent ID. We loop + // here on interval waiting for the Elastic Agent to enroll so then the Agent ID is then set. + agentInfo := a.agent.AgentInfo() + if agentInfo != nil && agentInfo.ID != "" { + // Agent ID is not set for the component. + t.Stop() + err := a.reconfigure(subCtx) + if err != nil { + log.Error().Err(err) + } + } + } + } + }() - a.firstCfg = make(chan firstCfg) - a.startChan = make(chan struct{}, 1) log.Info().Msg("starting communication connection back to Elastic Agent") - err := a.agent.Start(ctx) + err := a.agent.Start(subCtx) if err != nil { return err } - // wait for the initial configuration to be sent from the - // Elastic Agent before starting the actual Fleet Server. - log.Info().Msg("waiting for Elastic Agent to send initial configuration") - var cfg firstCfg - select { - case <-ctx.Done(): - return fmt.Errorf("never received initial configuration: %w", ctx.Err()) - case cfg = <-a.firstCfg: + <-subCtx.Done() + wg.Wait() + + return nil +} + +// UpdateState updates the state of the message and payload. +func (a *AgentMode) UpdateState(state client.UnitState, message string, payload map[string]interface{}) error { + if a.inputUnit != nil { + _ = a.inputUnit.UpdateState(state, message, payload) } + if a.outputUnit != nil { + _ = a.outputUnit.UpdateState(state, message, payload) + } + return nil +} - // possible that first configuration resulted in an error - if cfg.err != nil { - // unblock startChan even though there was an error - a.startChan <- struct{}{} - return cfg.err +func (a *AgentMode) unitAdded(ctx context.Context, unit *client.Unit) error { + if unit.Type() == client.UnitTypeInput { + _, _, cfg := unit.Expected() + if cfg.Type != kFleetServer { + // not support input type + _ = unit.UpdateState(client.UnitStateFailed, fmt.Sprintf("%s is an unsupported input type", cfg.Type), nil) + return nil + } + if a.inputUnit != nil { + // original input unit is being stopped; swapping in this unit as the new input unit + _ = a.inputUnit.UpdateState(client.UnitStateStopped, kStopped, nil) + } + a.inputUnit = unit + if a.outputUnit == nil { + // waiting for output unit to really start Fleet Server + _ = unit.UpdateState(client.UnitStateStarting, "waiting for output unit", nil) + return nil + } + return a.start(ctx) + } + if unit.Type() == client.UnitTypeOutput { + _, _, cfg := unit.Expected() + if cfg.Type != kElasticsearch { + // not support output type + _ = unit.UpdateState(client.UnitStateFailed, fmt.Sprintf("%s is an unsupported output type", cfg.Type), nil) + return nil + } + if a.outputUnit != nil { + // original output unit is being stopped; swapping in this unit as the new output unit + _ = a.outputUnit.UpdateState(client.UnitStateStopped, kStopped, nil) + } + a.outputUnit = unit + if a.inputUnit == nil { + // waiting for input unit to really start Fleet Server + _ = unit.UpdateState(client.UnitStateStarting, "waiting for input unit", nil) + return nil + } + return a.start(ctx) } + return fmt.Errorf("unknown unit type %v", unit.Type()) +} + +func (a *AgentMode) unitModified(ctx context.Context, unit *client.Unit) error { + state, _, _ := unit.Expected() + if unit.Type() == client.UnitTypeInput { + if a.inputUnit != unit { + // not our input unit; would have been marked failed in unitAdded; do nothing + return nil + } + if state == client.UnitStateHealthy { + if a.outputUnit == nil { + // still no output unit; would have been marked starting already; do nothing + return nil + } + + // configuration modified (should still be running) + return a.reconfigure(ctx) + } else if state == client.UnitStateStopped { + // unit should be stopped + a.stop() + return nil + } + return fmt.Errorf("unknown unit state %v", state) + } + if unit.Type() == client.UnitTypeOutput { + if a.outputUnit != unit { + // not our output unit; would have been marked failed in unitAdded; do nothing + return nil + } + if state == client.UnitStateHealthy { + if a.inputUnit == nil { + // still no input unit; would have been marked starting already; do nothing + return nil + } + + // configuration modified (should still be running) + return a.reconfigure(ctx) + } else if state == client.UnitStateStopped { + // unit should be stopped + a.stop() + return nil + } + return fmt.Errorf("unknown unit state %v", state) + } + return fmt.Errorf("unknown unit type %v", unit.Type()) +} - // start fleet server with the initial configuration and its - // own context (needed so when OnStop occurs the fleet server - // is stopped and not the elastic-agent-client as well) - srvCtx, srvCancel := context.WithCancel(ctx) - defer srvCancel() - log.Info().Msg("received initial configuration starting Fleet Server") - srv, err := NewFleetServer(cfg.cfg, a.bi, status.NewChained(status.NewLog(), a.agent)) +func (a *AgentMode) unitRemoved(unit *client.Unit) { + stop := false + if a.inputUnit == unit || a.outputUnit == unit { + stop = true + } + if stop { + a.stop() + } + if a.inputUnit == unit { + a.inputUnit = nil + } + if a.outputUnit == unit { + a.outputUnit = nil + } +} + +func (a *AgentMode) start(ctx context.Context) error { + if a.srv != nil { + return a.reconfigure(ctx) + } + + cfg, err := a.configFromUnits() if err != nil { - // unblock startChan even though there was an error - a.startChan <- struct{}{} return err } - a.mux.Lock() - close(a.firstCfg) - a.firstCfg = nil - a.srv = srv - a.srvCtx = srvCtx - a.srvCanceller = srvCancel - a.mux.Unlock() - // trigger startChan so OnConfig can continue - a.startChan <- struct{}{} + // reload the generic reloadables + for _, r := range a.reloadables { + err = r.Reload(ctx, cfg) + if err != nil { + return err + } + } + + srvDone := make(chan bool) + srvCtx, srvCanceller := context.WithCancel(ctx) + srv, err := NewFleetServer(a.bi, state.NewChained(state.NewLog(), a)) + if err != nil { + close(srvDone) + srvCanceller() + return err + } - // keep trying to restart the FleetServer on failure, reporting - // the status back to Elastic Agent - res := make(chan error) go func() { + defer close(srvDone) for { - err := a.srv.Run(srvCtx) + err := srv.Run(srvCtx, cfg) if err == nil || errors.Is(err, context.Canceled) { - res <- err return } // sleep some before calling Run again _ = sleep.WithContext(srvCtx, kAgentModeRestartLoopDelay) } }() - return <-res -} - -func (a *AgentMode) OnConfig(s string) { - a.mux.Lock() - cliCfg := ucfg.MustNewFrom(a.cliCfg, config.DefaultOptions...) - srv := a.srv - ctx := a.srvCtx - canceller := a.srvCanceller - cfgChan := a.firstCfg - startChan := a.startChan - a.mux.Unlock() - - var cfg *config.Config - var err error - defer func() { - if err != nil { - if cfgChan != nil { - // failure on first config - cfgChan <- firstCfg{ - cfg: nil, - err: err, - } - // block until startChan signalled - <-startChan - return - } - log.Err(err).Msg("failed to reload configuration") - if canceller != nil { - canceller() - } - } - }() + a.srv = srv + a.srvCtx = srvCtx + a.srvCanceller = srvCanceller + a.srvDone = srvDone + return nil +} - // load configuration and then merge it on top of the CLI configuration - var cfgData *ucfg.Config - cfgData, err = yaml.NewConfig([]byte(s), config.DefaultOptions...) - if err != nil { - return - } - err = cliCfg.Merge(cfgData, config.DefaultOptions...) - if err != nil { - return +func (a *AgentMode) reconfigure(ctx context.Context) error { + if a.srv == nil { + return a.start(ctx) } - cfg, err = config.FromConfig(cliCfg) + + cfg, err := a.configFromUnits() if err != nil { - return + return err } - if cfgChan != nil { - // reload the generic reloadables - for _, r := range a.reloadables { - err = r.Reload(ctx, cfg) - if err != nil { - return - } - } - - // send starting configuration so Fleet Server can start - cfgChan <- firstCfg{ - cfg: cfg, - err: nil, + // reload the generic reloadables + for _, r := range a.reloadables { + err = r.Reload(ctx, cfg) + if err != nil { + return err } + } - // block handling more OnConfig calls until the Fleet Server - // has been fully started - <-startChan - } else if srv != nil { - // reload the generic reloadables - for _, r := range a.reloadables { - err = r.Reload(ctx, cfg) - if err != nil { - return - } - } + return a.srv.Reload(ctx, cfg) +} - // reload the server - err = srv.Reload(ctx, cfg) - if err != nil { - return - } - } else { - err = fmt.Errorf("internal service should have been started") +func (a *AgentMode) stop() { + if a.srvCanceller == nil { return } -} -func (a *AgentMode) OnStop() { - a.mux.Lock() canceller := a.srvCanceller - a.mux.Unlock() - - if canceller != nil { - canceller() + a.srvCanceller = nil + a.srvCtx = nil + a.srv = nil + canceller() + <-a.srvDone + a.srvDone = nil + + if a.inputUnit != nil { + _ = a.inputUnit.UpdateState(client.UnitStateStopped, kStopped, nil) + } + if a.outputUnit != nil { + _ = a.outputUnit.UpdateState(client.UnitStateStopped, kStopped, nil) } } -func (a *AgentMode) OnError(err error) { - // Log communication error through the logger. These errors are only - // provided for logging purposes. The elastic-agent-client handles - // retries and reconnects internally automatically. - log.Err(err) +// configFromUnits takes both inputUnit and outputUnit and creates a single configuration just like fleet server was +// being started from a configuration file. +func (a *AgentMode) configFromUnits() (*config.Config, error) { + agentID := "" + agentVersion := "" + agentInfo := a.agent.AgentInfo() + if agentInfo != nil { + agentID = agentInfo.ID + agentVersion = agentInfo.Version + } + _, inputLevel, inputCfg := a.inputUnit.Expected() + _, outputLevel, outputCfg := a.outputUnit.Expected() + logLevel := inputLevel + if outputLevel > logLevel { + logLevel = outputLevel + } + + cfgData, err := ucfg.NewFrom(map[string]interface{}{ + "fleet": map[string]interface{}{ + "agent": map[string]interface{}{ + "id": agentID, + "version": agentVersion, + "logging": map[string]interface{}{ + "level": logLevel.String(), + }, + }, + }, + "output": map[string]interface{}{ + "elasticsearch": outputCfg.Source.AsMap(), + }, + "inputs": []interface{}{ + inputCfg.Source.AsMap(), + }, + "logging": map[string]interface{}{ + "level": logLevel.String(), + }, + }) + if err != nil { + return nil, err + } + return config.FromConfig(cfgData) } type FleetServer struct { bi build.Info verCon version.Constraints - cfg *config.Config cfgCh chan *config.Config cache cache.Cache - reporter status.Reporter + reporter state.Reporter } // NewFleetServer creates the actual fleet server service. -func NewFleetServer(cfg *config.Config, bi build.Info, reporter status.Reporter) (*FleetServer, error) { +func NewFleetServer(bi build.Info, reporter state.Reporter) (*FleetServer, error) { verCon, err := api.BuildVersionConstraint(bi.Version) if err != nil { return nil, err } - err = cfg.LoadServerLimits() - if err != nil { - return nil, fmt.Errorf("encountered error while loading server limits: %w", err) - } - cache, err := makeCache(cfg) - if err != nil { - return nil, err - } - return &FleetServer{ bi: bi, verCon: verCon, - cfg: cfg, cfgCh: make(chan *config.Config, 1), - cache: cache, reporter: reporter, }, nil } type runFunc func(context.Context) error +type runFuncCfg func(context.Context, *config.Config) error + // Run runs the fleet server -func (f *FleetServer) Run(ctx context.Context) error { +func (f *FleetServer) Run(ctx context.Context, initCfg *config.Config) error { + err := initCfg.LoadServerLimits() + if err != nil { + return fmt.Errorf("encountered error while loading server limits: %w", err) + } + cache, err := makeCache(initCfg) + if err != nil { + return err + } + f.cache = cache + var curCfg *config.Config - newCfg := f.cfg + newCfg := initCfg // Replace context with cancellable ctx // in order to automatically cancel all the go routines @@ -459,12 +603,12 @@ func (f *FleetServer) Run(ctx context.Context) error { } } - start := func(ctx context.Context, runfn runFunc, ech chan<- error) (*errgroup.Group, context.CancelFunc) { + start := func(ctx context.Context, runfn runFuncCfg, cfg *config.Config, ech chan<- error) (*errgroup.Group, context.CancelFunc) { ctx, cn = context.WithCancel(ctx) g, ctx := errgroup.WithContext(ctx) g.Go(func() error { - err := runfn(ctx) + err := runfn(ctx, cfg) if err != nil { ech <- err } @@ -484,10 +628,10 @@ LOOP: for { ech := make(chan error, 2) if started { - f.reporter.Status(proto.StateObserved_CONFIGURING, "Re-configuring", nil) //nolint:errcheck // unclear on what should we do if updating the status fails? + f.reporter.UpdateState(client.UnitStateConfiguring, "Re-configuring", nil) //nolint:errcheck // unclear on what should we do if updating the status fails? } else { started = true - f.reporter.Status(proto.StateObserved_STARTING, "Starting", nil) //nolint:errcheck // unclear on what should we do if updating the status fails? + f.reporter.UpdateState(client.UnitStateStarting, "Starting", nil) //nolint:errcheck // unclear on what should we do if updating the status fails? } err := newCfg.LoadServerLimits() @@ -515,9 +659,9 @@ LOOP: proEg, proCancel = nil, nil if newCfg.Inputs[0].Server.Profiler.Enabled { log.Info().Msg("starting profiler on configuration change") - proEg, proCancel = start(ctx, func(ctx context.Context) error { - return profile.RunProfiler(ctx, newCfg.Inputs[0].Server.Profiler.Bind) - }, ech) + proEg, proCancel = start(ctx, func(ctx context.Context, cfg *config.Config) error { + return profile.RunProfiler(ctx, cfg.Inputs[0].Server.Profiler.Bind) + }, newCfg, ech) } } @@ -528,30 +672,29 @@ LOOP: stop(srvCancel, srvEg) } log.Info().Msg("starting server on configuration change") - srvEg, srvCancel = start(ctx, func(ctx context.Context) error { - return f.runServer(ctx, newCfg) - }, ech) + srvEg, srvCancel = start(ctx, func(ctx context.Context, cfg *config.Config) error { + return f.runServer(ctx, cfg) + }, newCfg, ech) } curCfg = newCfg - f.cfg = curCfg select { case newCfg = <-f.cfgCh: log.Info().Msg("Server configuration update") case err := <-ech: - f.reporter.Status(proto.StateObserved_FAILED, fmt.Sprintf("Error - %s", err), nil) //nolint:errcheck // unclear on what should we do if updating the status fails? + f.reporter.UpdateState(client.UnitStateFailed, fmt.Sprintf("Error - %s", err), nil) //nolint:errcheck // unclear on what should we do if updating the status fails? log.Error().Err(err).Msg("Fleet Server failed") return err case <-ctx.Done(): - f.reporter.Status(proto.StateObserved_STOPPING, "Stopping", nil) //nolint:errcheck // unclear on what should we do if updating the status fails? + f.reporter.UpdateState(client.UnitStateStopping, "Stopping", nil) //nolint:errcheck // unclear on what should we do if updating the status fails? break LOOP } } // Server is coming down; wait for the server group to exit cleanly. // Timeout if something is locked up. - err := safeWait(srvEg, time.Second) + err = safeWait(srvEg, time.Second) // Eat cancel error to minimize confusion in logs if errors.Is(err, context.Canceled) { diff --git a/cmd/fleet/main_integration_test.go b/cmd/fleet/main_integration_test.go index d0f842536..27d4c183a 100644 --- a/cmd/fleet/main_integration_test.go +++ b/cmd/fleet/main_integration_test.go @@ -5,32 +5,34 @@ //go:build integration // +build integration -//nolint:unused // some unused code may be added to more tests package fleet import ( "context" + "errors" "fmt" - "io" + "net" + "os" + "strings" "sync" "testing" "time" + "github.com/elastic/elastic-agent-client/v7/pkg/client" + "github.com/elastic/elastic-agent-client/v7/pkg/client/mock" + "github.com/elastic/elastic-agent-client/v7/pkg/proto" + "github.com/elastic/go-ucfg" "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "github.com/elastic/elastic-agent-client/v7/pkg/proto" - "github.com/elastic/elastic-agent-libs/logp" - "github.com/elastic/elastic-agent/pkg/core/logger" - "github.com/elastic/elastic-agent/pkg/core/server" - "github.com/elastic/go-ucfg" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/protobuf/types/known/structpb" "github.com/elastic/fleet-server/v7/internal/pkg/build" "github.com/elastic/fleet-server/v7/internal/pkg/dl" "github.com/elastic/fleet-server/v7/internal/pkg/model" ftesting "github.com/elastic/fleet-server/v7/internal/pkg/testing" - "github.com/elastic/fleet-server/v7/internal/pkg/testing/suite" ) var biInfo = build.Info{ @@ -40,6 +42,11 @@ var biInfo = build.Info{ var policyData = []byte(` { + "outputs": { + "default": { + "type": "elasticsearch" + } + }, "inputs": [ { "type": "fleet-server" @@ -48,38 +55,7 @@ var policyData = []byte(` } `) -var initialCfgData = ` -output: - elasticsearch: - hosts: '${ELASTICSEARCH_HOSTS:localhost:9200}' - service_token: '${ELASTICSEARCH_SERVICE_TOKEN}' -` - -var agentIDCfgData = ` -output: - elasticsearch: - hosts: '${ELASTICSEARCH_HOSTS:localhost:9200}' - service_token: '${ELASTICSEARCH_SERVICE_TOKEN}' -fleet: - agent: - id: 1e4954ce-af37-4731-9f4a-407b08e69e42 -` - -var badCfgData = ` -output: - elasticsearch: - hosts: 'localhost:63542' - service_token: '${ELASTICSEARCH_SERVICE_TOKEN}' -fleet: - agent: - id: 1e4954ce-af37-4731-9f4a-407b08e69e42 -` - -type agentSuite struct { - suite.RunningSuite -} - -func (s *agentSuite) TestAgentMode(t *testing.T) { +func TestAgentMode(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -105,128 +81,322 @@ func (s *agentSuite) TestAgentMode(t *testing.T) { }) require.NoError(t, err) - app := &StubApp{} - control := createAndStartControlServer(t, app) - defer control.Stop() - appState, err := control.Register(app, initialCfgData) + inputSource, err := structpb.NewStruct(map[string]interface{}{ + "id": "fleet-server", + "type": "fleet-server", + "name": "fleet-server", + "revision": 1, + }) require.NoError(t, err) - - r, w := io.Pipe() + outputSource, err := structpb.NewStruct(map[string]interface{}{ + "id": "default", + "type": "elasticsearch", + "name": "elasticsearch", + "revision": 1, + "hosts": getESHosts(), + "service_token": getESServiceToken(), + }) + require.NoError(t, err) + expected := makeExpected("", 1, inputSource, 1, outputSource) + control := createAndStartControlServer(t, expected) + defer control.Stop() var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() - agent, err := NewAgentMode(ucfg.New(), r, biInfo) - require.NoError(t, err) - err = agent.Run(ctx) + + a := &AgentMode{ + cliCfg: ucfg.New(), + bi: biInfo, + } + a.agent = client.NewV2(fmt.Sprintf("localhost:%d", control.Port()), control.Token(), client.VersionInfo{ + Name: "fleet-server", + Version: "1.0.0", + }, grpc.WithTransportCredentials(insecure.NewCredentials())) + err = a.Run(ctx) assert.NoError(t, err) }() - err = appState.WriteConnInfo(w) - require.NoError(t, err) - // wait for fleet-server to report as degraded (starting mode without agent.id) ftesting.Retry(t, ctx, func(ctx context.Context) error { - status := app.Status() - if status != proto.StateObserved_DEGRADED { - return fmt.Errorf("should be reported as degraded; instead its %s", status) + state := getUnitState(control, proto.UnitType_INPUT, "fleet-server-default-fleet-server") + if state != proto.State_DEGRADED { + return fmt.Errorf("should be reported as degraded; instead its %s", state) } return nil }, ftesting.RetrySleep(100*time.Millisecond), ftesting.RetryCount(120)) // reconfigure with agent ID set - err = appState.UpdateConfig(agentIDCfgData) + agentID := uuid.Must(uuid.NewV4()).String() + expected = makeExpected(agentID, 1, inputSource, 1, outputSource) + control.Expected(expected) require.NoError(t, err) // wait for fleet-server to report as healthy ftesting.Retry(t, ctx, func(ctx context.Context) error { - status := app.Status() - if status != proto.StateObserved_HEALTHY { - return fmt.Errorf("should be reported as healthy; instead its %s", status) + state := getUnitState(control, proto.UnitType_INPUT, "fleet-server-default-fleet-server") + if state != proto.State_HEALTHY { + return fmt.Errorf("should be reported as healthy; instead its %s", state) } return nil }, ftesting.RetrySleep(100*time.Millisecond), ftesting.RetryCount(120)) // trigger update with bad configuration - err = appState.UpdateConfig(badCfgData) + badSource, err := structpb.NewStruct(map[string]interface{}{ + "id": "default", + "type": "elasticsearch", + "name": "elasticsearch", + "revision": 1, + "hosts": []interface{}{"localhost:63542"}, + "service_token": getESServiceToken(), + }) require.NoError(t, err) + expected = makeExpected(agentID, 1, inputSource, 2, badSource) + control.Expected(expected) // wait for fleet-server to report as failed ftesting.Retry(t, ctx, func(ctx context.Context) error { - status := app.Status() - if status != proto.StateObserved_FAILED { - return fmt.Errorf("should be reported as failed; instead its %s", status) + state := getUnitState(control, proto.UnitType_INPUT, "fleet-server-default-fleet-server") + if state != proto.State_FAILED { + return fmt.Errorf("should be reported as failed; instead its %s", state) } return nil }, ftesting.RetrySleep(100*time.Millisecond), ftesting.RetryCount(120)) // reconfigure to good config - err = appState.UpdateConfig(agentIDCfgData) + goodSource, err := structpb.NewStruct(map[string]interface{}{ + "id": "default", + "type": "elasticsearch", + "name": "elasticsearch", + "revision": 1, + "hosts": getESHosts(), + "service_token": getESServiceToken(), + }) require.NoError(t, err) + expected = makeExpected(agentID, 1, inputSource, 3, goodSource) + control.Expected(expected) // wait for fleet-server to report as healthy ftesting.Retry(t, ctx, func(ctx context.Context) error { - status := app.Status() - if status != proto.StateObserved_HEALTHY { - return fmt.Errorf("should be reported as healthy; instead its %s", status) + state := getUnitState(control, proto.UnitType_INPUT, "fleet-server-default-fleet-server") + if state != proto.State_HEALTHY { + return fmt.Errorf("should be reported as healthy; instead its %s", state) } return nil }, ftesting.RetrySleep(100*time.Millisecond), ftesting.RetryCount(120)) // trigger stop - err = appState.Stop(10 * time.Second) - assert.NoError(t, err) + expected = makeExpected(agentID, 1, inputSource, 3, outputSource) + expected.Units[0].State = proto.State_STOPPED + expected.Units[1].State = proto.State_STOPPED + control.Expected(expected) + + // wait for fleet-server to report as stopped + ftesting.Retry(t, ctx, func(ctx context.Context) error { + state := getUnitState(control, proto.UnitType_INPUT, "fleet-server-default-fleet-server") + if state != proto.State_STOPPED { + return fmt.Errorf("should be reported as stopped; instead its %s", state) + } + return nil + }, ftesting.RetrySleep(100*time.Millisecond), ftesting.RetryCount(120)) - // wait for go routine to exit + // stop the agent and wait for go routine to exit + cancel() wg.Wait() } -func newDebugLogger(t *testing.T) *logger.Logger { +func createAndStartControlServer(t *testing.T, expected *proto.CheckinExpected) *StubV2Control { t.Helper() - loggerCfg := logger.DefaultLoggingConfig() - loggerCfg.Level = logp.DebugLevel + srv := NewStubV2Control(expected) + require.NoError(t, srv.Start()) + return srv +} + +type StubV2Control struct { + proto.UnimplementedElasticAgentServer - log, err := logger.NewFromConfig("", loggerCfg, false) - require.NoError(t, err) - return log + token string + port int + + server *grpc.Server + + mx sync.Mutex + observed *proto.CheckinObserved + expected *proto.CheckinExpected + forceSend chan struct{} } -func createAndStartControlServer(t *testing.T, handler server.Handler, extraConfigs ...func(*server.Server)) *server.Server { - t.Helper() - srv, err := server.New(newDebugLogger(t), "localhost:0", handler, nil) - require.NoError(t, err) - for _, extra := range extraConfigs { - extra(srv) +func NewStubV2Control(expected *proto.CheckinExpected) *StubV2Control { + token := mock.NewID() + s := &StubV2Control{ + token: token, + expected: expected, + forceSend: make(chan struct{}), } - require.NoError(t, srv.Start()) - return srv + return s } -type StubApp struct { - lock sync.RWMutex - status proto.StateObserved_Status - message string - payload map[string]interface{} +func (s *StubV2Control) Token() string { + return s.token } -func (a *StubApp) Status() proto.StateObserved_Status { - a.lock.RLock() - defer a.lock.RUnlock() - return a.status +func (s *StubV2Control) Port() int { + return s.port } -func (a *StubApp) Message() string { - a.lock.RLock() - defer a.lock.RUnlock() - return a.message +func (s *StubV2Control) Start(opt ...grpc.ServerOption) error { + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + return err + } + s.port = lis.Addr().(*net.TCPAddr).Port + srv := grpc.NewServer(opt...) + s.server = srv + proto.RegisterElasticAgentServer(s.server, s) + go func() { + _ = srv.Serve(lis) + }() + return nil } -func (a *StubApp) OnStatusChange(_ *server.ApplicationState, status proto.StateObserved_Status, message string, payload map[string]interface{}) { - a.lock.Lock() - defer a.lock.Unlock() - a.status = status - a.message = message - a.payload = payload +func (s *StubV2Control) Stop() { + if s.server != nil { + s.server.Stop() + s.server = nil + } +} + +func (s *StubV2Control) Expected(expected *proto.CheckinExpected) { + s.mx.Lock() + s.expected = expected + s.mx.Unlock() + s.forceSend <- struct{}{} +} + +func (s *StubV2Control) Observed() *proto.CheckinObserved { + s.mx.Lock() + defer s.mx.Unlock() + return s.observed +} + +// Checkin is the checkin implementation for the mock server +func (s *StubV2Control) Checkin(server proto.ElasticAgent_CheckinServer) error { + return errors.New("no V1 support") +} + +// CheckinV2 is the V2 checkin implementation for the mock server +func (s *StubV2Control) CheckinV2(server proto.ElasticAgent_CheckinV2Server) error { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + go func() { + for { + select { + case <-ctx.Done(): + return + case <-s.forceSend: + s.mx.Lock() + expected := s.expected + s.mx.Unlock() + _ = server.Send(expected) + } + } + }() + + for { + checkin, err := server.Recv() + if err != nil { + return err + } + if checkin.Token != s.token { + return errors.New("invalid token") + } + + s.mx.Lock() + s.observed = checkin + expected := s.expected + s.mx.Unlock() + + err = server.Send(expected) + if err != nil { + return err + } + } +} + +// Actions is the action implementation for the mock server +func (s *StubV2Control) Actions(server proto.ElasticAgent_ActionsServer) error { + return nil +} + +func getESHosts() []interface{} { + hosts := os.Getenv("ELASTICSEARCH_HOSTS") + if hosts == "" { + return []interface{}{"localhost:9200"} + } + hostsSplit := strings.Split(hosts, ",") + rawHosts := make([]interface{}, 0, len(hostsSplit)) + for _, host := range hostsSplit { + rawHosts = append(rawHosts, host) + } + return rawHosts +} + +func getESServiceToken() string { + return os.Getenv("ELASTICSEARCH_SERVICE_TOKEN") +} + +func getUnitState(control *StubV2Control, unitType proto.UnitType, unitID string) proto.State { + obs := control.Observed() + if obs == nil { + return proto.State_STARTING + } + for _, unit := range obs.Units { + if unit.Type == unitType && unit.Id == unitID { + return unit.State + } + } + return proto.State_STARTING +} + +func makeExpected(agentID string, inputConfigIdx uint64, inputSource *structpb.Struct, outputConfigIdx uint64, outputSource *structpb.Struct) *proto.CheckinExpected { + return &proto.CheckinExpected{ + AgentInfo: &proto.CheckinAgentInfo{ + Id: agentID, + Version: "8.5.0", + Snapshot: true, + }, + Units: []*proto.UnitExpected{ + { + Id: "fleet-server-default-fleet-server", + Type: proto.UnitType_INPUT, + State: proto.State_HEALTHY, + ConfigStateIdx: inputConfigIdx, + Config: &proto.UnitExpectedConfig{ + Source: inputSource, + Id: "fleet-server", + Type: "fleet-server", + Name: "Fleet Server", + Revision: 1, + }, + LogLevel: proto.UnitLogLevel_INFO, + }, + { + Id: "fleet-server-default", + Type: proto.UnitType_OUTPUT, + State: proto.State_HEALTHY, + ConfigStateIdx: outputConfigIdx, + Config: &proto.UnitExpectedConfig{ + Source: outputSource, + Id: "default", + Type: "elasticsearch", + Name: "elasticsearch", + Revision: 1, + }, + LogLevel: proto.UnitLogLevel_INFO, + }, + }, + } } diff --git a/cmd/fleet/server_integration_test.go b/cmd/fleet/server_integration_test.go index 76c279009..c34ae2c12 100644 --- a/cmd/fleet/server_integration_test.go +++ b/cmd/fleet/server_integration_test.go @@ -30,9 +30,11 @@ import ( "github.com/elastic/fleet-server/v7/internal/pkg/api" "github.com/elastic/fleet-server/v7/internal/pkg/build" "github.com/elastic/fleet-server/v7/internal/pkg/config" + "github.com/elastic/fleet-server/v7/internal/pkg/dl" "github.com/elastic/fleet-server/v7/internal/pkg/logger" + "github.com/elastic/fleet-server/v7/internal/pkg/model" "github.com/elastic/fleet-server/v7/internal/pkg/sleep" - "github.com/elastic/fleet-server/v7/internal/pkg/status" + "github.com/elastic/fleet-server/v7/internal/pkg/state" ftesting "github.com/elastic/fleet-server/v7/internal/pkg/testing" ) @@ -62,7 +64,9 @@ func (s *tserver) waitExit() error { return s.g.Wait() } -func startTestServer(ctx context.Context) (*tserver, error) { +func startTestServer(t *testing.T, ctx context.Context) (*tserver, error) { + t.Helper() + cfg, err := config.LoadFile("../../fleet-server.yml") if err != nil { return nil, fmt.Errorf("config load error: %w", err) @@ -70,6 +74,30 @@ func startTestServer(ctx context.Context) (*tserver, error) { logger.Init(cfg, "fleet-server") //nolint:errcheck // test logging setup + bulker := ftesting.SetupBulk(ctx, t) + + policyID := uuid.Must(uuid.NewV4()).String() + _, err = dl.CreatePolicy(ctx, bulker, model.Policy{ + PolicyID: policyID, + RevisionIdx: 1, + DefaultFleetServer: true, + Data: policyData, + }) + if err != nil { + return nil, err + } + + _, err = dl.CreateEnrollmentAPIKey(ctx, bulker, model.EnrollmentAPIKey{ + Name: "Default", + APIKey: "keyvalue", + APIKeyID: "keyid", + PolicyID: policyID, + Active: true, + }) + if err != nil { + return nil, err + } + port, err := ftesting.FreePort() if err != nil { return nil, fmt.Errorf("unable to find port: %w", err) @@ -82,7 +110,7 @@ func startTestServer(ctx context.Context) (*tserver, error) { cfg.Inputs[0].Server = *srvcfg log.Info().Uint16("port", port).Msg("Test fleet server") - srv, err := NewFleetServer(cfg, build.Info{Version: serverVersion}, status.NewLog()) + srv, err := NewFleetServer(build.Info{Version: serverVersion}, state.NewLog()) if err != nil { return nil, fmt.Errorf("unable to create server: %w", err) } @@ -90,7 +118,7 @@ func startTestServer(ctx context.Context) (*tserver, error) { g, ctx := errgroup.WithContext(ctx) g.Go(func() error { - return srv.Run(ctx) + return srv.Run(ctx, cfg) }) tsrv := &tserver{cfg: cfg, g: g, srv: srv} @@ -140,7 +168,7 @@ func TestServerUnauthorized(t *testing.T) { defer cancel() // Start test server - srv, err := startTestServer(ctx) + srv, err := startTestServer(t, ctx) require.NoError(t, err) agentID := uuid.Must(uuid.NewV4()).String() @@ -244,7 +272,7 @@ func TestServerInstrumentation(t *testing.T) { defer server.Close() // Start test server - srv, err := startTestServer(ctx) + srv, err := startTestServer(t, ctx) require.NoError(t, err) newInstrumentationCfg := func(cfg config.Config, instr config.Instrumentation) { //nolint:govet // mutex should not be copied in operation (hopefully) diff --git a/go.mod b/go.mod index e5e6d48ce..c8b2c920d 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.17 require ( github.com/Pallinder/go-randomdata v1.2.0 github.com/dgraph-io/ristretto v0.1.0 - github.com/elastic/elastic-agent-client/v7 v7.0.0-20210922110810-e6f1f402a9ed + github.com/elastic/elastic-agent-client/v7 v7.0.0-20220804181728-b0328d2fe484 github.com/elastic/elastic-agent-libs v0.2.3 github.com/elastic/elastic-agent-system-metrics v0.3.0 github.com/elastic/go-elasticsearch/v7 v7.16.0 @@ -30,6 +30,7 @@ require ( go.uber.org/zap v1.21.0 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac + google.golang.org/protobuf v1.28.0 ) require ( @@ -43,10 +44,8 @@ require ( github.com/elastic/go-sysinfo v1.7.1 // indirect github.com/elastic/go-windows v1.0.1 // indirect github.com/elastic/gosigar v0.14.2 // indirect - github.com/gofrs/flock v0.8.1 // indirect github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -57,7 +56,6 @@ require ( github.com/santhosh-tekuri/jsonschema v1.2.4 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.2.0 // indirect - go.elastic.co/apm/module/apmgrpc v1.15.0 // indirect go.elastic.co/apm/module/apmhttp v1.15.0 // indirect go.elastic.co/apm/module/apmhttp/v2 v2.0.0 // indirect go.elastic.co/apm/v2 v2.0.0 // indirect @@ -67,7 +65,6 @@ require ( golang.org/x/mod v0.5.1 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect - google.golang.org/protobuf v1.27.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) @@ -84,11 +81,11 @@ require ( go.elastic.co/ecszap v1.0.1 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.8.0 // indirect - golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect - golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64 // indirect + golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect + golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect golang.org/x/tools v0.1.9 // indirect - google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect - google.golang.org/grpc v1.43.0 // indirect + google.golang.org/genproto v0.0.0-20220426171045-31bebdecfb46 // indirect + google.golang.org/grpc v1.46.0 howett.net/plist v1.0.0 // indirect ) diff --git a/go.sum b/go.sum index 46eee0fb8..b5fe728e6 100644 --- a/go.sum +++ b/go.sum @@ -425,8 +425,8 @@ github.com/elastic/elastic-agent v0.0.0-20220510120738-63b682fefc61/go.mod h1:xv github.com/elastic/elastic-agent-autodiscover v0.0.0-20220404145827-89887023c1ab h1:Jk6Mfk5BF8gtfE7X0bNCiDGBtwJVxRI79b4wLCAsP+A= github.com/elastic/elastic-agent-autodiscover v0.0.0-20220404145827-89887023c1ab/go.mod h1:Gg1fsQI+rVms9FJ2DefBSojfPIzgkV8xlyG8fPG0DE8= github.com/elastic/elastic-agent-client/v7 v7.0.0-20210727140539-f0905d9377f6/go.mod h1:uh/Gj9a0XEbYoM4NYz4LvaBVARz3QXLmlNjsrKY9fTc= -github.com/elastic/elastic-agent-client/v7 v7.0.0-20210922110810-e6f1f402a9ed h1:H5si6Yglir/pIyYQur/Es/ByTkQAoNDqidI8gBB2IGs= -github.com/elastic/elastic-agent-client/v7 v7.0.0-20210922110810-e6f1f402a9ed/go.mod h1:uh/Gj9a0XEbYoM4NYz4LvaBVARz3QXLmlNjsrKY9fTc= +github.com/elastic/elastic-agent-client/v7 v7.0.0-20220804181728-b0328d2fe484 h1:uJIMfLgCenJvxsVmEjBjYGxt0JddCgw2IxgoNfcIXOk= +github.com/elastic/elastic-agent-client/v7 v7.0.0-20220804181728-b0328d2fe484/go.mod h1:fkvyUfFwyAG5OnMF0h+FV9sC0Xn9YLITwQpSuwungQs= github.com/elastic/elastic-agent-libs v0.0.0-20220303160015-5b4e674da3dd/go.mod h1://82M1l73IHx0wDbS2Tzkq6Fx9fkmytS1KgkIyzvNTM= github.com/elastic/elastic-agent-libs v0.1.3-0.20220413130536-4b45f2742994/go.mod h1:1xDLBhIqBIjhJ7lr2s+xRFFkQHpitSp8q2zzv1Dqg+s= github.com/elastic/elastic-agent-libs v0.2.2/go.mod h1:1xDLBhIqBIjhJ7lr2s+xRFFkQHpitSp8q2zzv1Dqg+s= @@ -468,8 +468,9 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.1 h1:cgDRLG7bs59Zd+apAWuzLQL95obVYAymNJek76W3mgw= github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 h1:xvqufLtNVwAhN8NMyWklVgxnWohi+wtMGQMhtxexlm0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.2 h1:JiO+kJTpmYGjEodY7O1Zk8oZcNz1+f30UtwtXoFUPzE= github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= @@ -725,7 +726,6 @@ github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= @@ -1078,7 +1078,6 @@ github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mo github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= -github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= @@ -1558,8 +1557,9 @@ golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1715,8 +1715,9 @@ golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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-20220405052023-b1e9470b6e64 h1:D1v9ucDTYBtbz5vNuBbAhIMAGhQhJ6Ym5ah3maMVNX4= golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1937,8 +1938,9 @@ google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220426171045-31bebdecfb46 h1:G1IeWbjrqEq9ChWxEuRPJu6laA67+XgTFHVSAvepr38= +google.golang.org/genproto v0.0.0-20220426171045-31bebdecfb46/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1971,8 +1973,9 @@ google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM= -google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0 h1:oCjezcn6g6A75TGoKYBPgKmVBLexhYLM6MebdrPApP8= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/examples v0.0.0-20220304170021-431ea809a767 h1:r16FSFCMhn7+LU8CzbtAIKppYeU6NUPJVdvXeIqVIq8= @@ -1989,8 +1992,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= diff --git a/internal/pkg/api/handleStatus.go b/internal/pkg/api/handleStatus.go index 8c242058c..917eca05c 100644 --- a/internal/pkg/api/handleStatus.go +++ b/internal/pkg/api/handleStatus.go @@ -11,6 +11,7 @@ import ( "net/http" "time" + "github.com/elastic/elastic-agent-client/v7/pkg/client" "github.com/elastic/fleet-server/v7/internal/pkg/apikey" "github.com/elastic/fleet-server/v7/internal/pkg/build" "github.com/elastic/fleet-server/v7/internal/pkg/bulk" @@ -20,7 +21,6 @@ import ( "github.com/elastic/fleet-server/v7/internal/pkg/logger" "github.com/julienschmidt/httprouter" - "github.com/elastic/elastic-agent-client/v7/pkg/proto" "github.com/rs/zerolog" "github.com/rs/zerolog/log" ) @@ -68,7 +68,7 @@ func (st StatusT) authenticate(r *http.Request) (*apikey.APIKey, error) { return authAPIKey(r, st.bulk, st.cache) } -func (st StatusT) handleStatus(_ *zerolog.Logger, r *http.Request, rt *Router) (resp StatusResponse, status proto.StateObserved_Status, err error) { +func (st StatusT) handleStatus(_ *zerolog.Logger, r *http.Request, rt *Router) (resp StatusResponse, state client.UnitState, err error) { limitF, err := st.limit.Acquire() // When failing to acquire a limiter send an error response. if err != nil { @@ -82,10 +82,10 @@ func (st StatusT) handleStatus(_ *zerolog.Logger, r *http.Request, rt *Router) ( authed = false } - status = rt.sm.Status() + state = rt.sm.State() resp = StatusResponse{ Name: build.ServiceName, - Status: status.String(), + Status: state.String(), } if authed { @@ -96,7 +96,7 @@ func (st StatusT) handleStatus(_ *zerolog.Logger, r *http.Request, rt *Router) ( } } - return resp, status, nil + return resp, state, nil } @@ -113,7 +113,7 @@ func (rt Router) handleStatus(w http.ResponseWriter, r *http.Request, _ httprout Str("mod", kStatusMod). Logger() - resp, status, err := rt.st.handleStatus(&zlog, r, &rt) + resp, state, err := rt.st.handleStatus(&zlog, r, &rt) if err != nil { cntStatus.IncError(err) resp := NewHTTPErrResp(err) @@ -140,7 +140,7 @@ func (rt Router) handleStatus(w http.ResponseWriter, r *http.Request, _ httprout } code := http.StatusServiceUnavailable - if status == proto.StateObserved_DEGRADED || status == proto.StateObserved_HEALTHY { + if state == client.UnitStateDegraded || state == client.UnitStateHealthy { code = http.StatusOK } w.WriteHeader(code) diff --git a/internal/pkg/api/handleStatus_test.go b/internal/pkg/api/handleStatus_test.go index 474ab2a2d..19359cd79 100644 --- a/internal/pkg/api/handleStatus_test.go +++ b/internal/pkg/api/handleStatus_test.go @@ -15,6 +15,7 @@ import ( "testing" "time" + "github.com/elastic/elastic-agent-client/v7/pkg/client" "github.com/elastic/elastic-agent-client/v7/pkg/proto" "github.com/elastic/fleet-server/v7/internal/pkg/apikey" fbuild "github.com/elastic/fleet-server/v7/internal/pkg/build" @@ -35,15 +36,15 @@ func withAuthFunc(authfn AuthFunc) OptFunc { } type mockPolicyMonitor struct { - status proto.StateObserved_Status + state client.UnitState } func (pm *mockPolicyMonitor) Run(ctx context.Context) error { return nil } -func (pm *mockPolicyMonitor) Status() proto.StateObserved_Status { - return pm.status +func (pm *mockPolicyMonitor) State() client.UnitState { + return pm.state } func TestHandleStatus(t *testing.T) { @@ -80,13 +81,13 @@ func TestHandleStatus(t *testing.T) { // Test table, with inner loop on all available statuses for _, tc := range tests { t.Run(tc.Name, func(t *testing.T) { - for k, v := range proto.StateObserved_Status_name { + for k, v := range proto.State_name { t.Run(v, func(t *testing.T) { - status := proto.StateObserved_Status(k) + state := client.UnitState(k) r := Router{ ctx: ctx, st: NewStatusT(cfg, nil, c, withAuthFunc(tc.AuthFn)), - sm: &mockPolicyMonitor{status}, + sm: &mockPolicyMonitor{state}, bi: fbuild.Info{ Version: "8.1.0", Commit: "4eff928", @@ -102,7 +103,7 @@ func TestHandleStatus(t *testing.T) { hr.ServeHTTP(w, req) expectedCode := http.StatusServiceUnavailable - if status == proto.StateObserved_DEGRADED || status == proto.StateObserved_HEALTHY { + if state == client.UnitStateDegraded || state == client.UnitStateHealthy { expectedCode = http.StatusOK } @@ -119,7 +120,7 @@ func TestHandleStatus(t *testing.T) { t.Error(diff) } - if diff := cmp.Diff(res.Status, status.String()); diff != "" { + if diff := cmp.Diff(res.Status, state.String()); diff != "" { t.Error(diff) } diff --git a/internal/pkg/logger/logger.go b/internal/pkg/logger/logger.go index c3b87e14b..9f6d79caa 100644 --- a/internal/pkg/logger/logger.go +++ b/internal/pkg/logger/logger.go @@ -99,7 +99,7 @@ func changed(a *config.Config, b *config.Config) bool { if al != bl { return true } - if (aFiles == nil && bFiles != nil) || (aFiles != nil && bFiles == nil) || (*aFiles != *bFiles) { + if (aFiles == nil && bFiles != nil) || (aFiles != nil && bFiles == nil) || ((aFiles != nil && bFiles != nil) && *aFiles != *bFiles) { return true } return false diff --git a/internal/pkg/policy/policy_output_test.go b/internal/pkg/policy/policy_output_test.go index 1e90cee57..be8f8105d 100644 --- a/internal/pkg/policy/policy_output_test.go +++ b/internal/pkg/policy/policy_output_test.go @@ -121,7 +121,7 @@ func TestPolicyOutputESPrepare(t *testing.T) { logger := testlog.SetLogger(t) bulker := ftesting.NewMockBulk() bulker.On("Update", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() - bulker.On("APIKeyCreate", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&bulk.APIKey{"abc", "new-key"}, nil).Once() //nolint:govet // test case + bulker.On("APIKeyCreate", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&bulk.APIKey{ID: "abc", Key: "new-key"}, nil).Once() //nolint:govet // test case po := PolicyOutput{ Type: OutputTypeElasticsearch, @@ -155,7 +155,7 @@ func TestPolicyOutputESPrepare(t *testing.T) { logger := testlog.SetLogger(t) bulker := ftesting.NewMockBulk() bulker.On("Update", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() - bulker.On("APIKeyCreate", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&bulk.APIKey{"abc", "new-key"}, nil).Once() //nolint:govet // test case + bulker.On("APIKeyCreate", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&bulk.APIKey{ID: "abc", Key: "new-key"}, nil).Once() //nolint:govet // test case po := PolicyOutput{ Type: OutputTypeElasticsearch, diff --git a/internal/pkg/policy/self.go b/internal/pkg/policy/self.go index 468f0fef8..295879e5e 100644 --- a/internal/pkg/policy/self.go +++ b/internal/pkg/policy/self.go @@ -9,10 +9,10 @@ import ( "encoding/json" "errors" "fmt" + "github.com/elastic/elastic-agent-client/v7/pkg/client" "sync" "time" - "github.com/elastic/elastic-agent-client/v7/pkg/proto" "github.com/rs/zerolog" "github.com/rs/zerolog/log" @@ -22,7 +22,7 @@ import ( "github.com/elastic/fleet-server/v7/internal/pkg/es" "github.com/elastic/fleet-server/v7/internal/pkg/model" "github.com/elastic/fleet-server/v7/internal/pkg/monitor" - "github.com/elastic/fleet-server/v7/internal/pkg/status" + "github.com/elastic/fleet-server/v7/internal/pkg/state" ) // DefaultCheckTime is the default interval for self to check for its policy. @@ -33,8 +33,8 @@ type enrollmentTokenFetcher func(ctx context.Context, bulker bulk.Bulk, policyID type SelfMonitor interface { // Run runs the monitor. Run(ctx context.Context) error - // Status gets current status of monitor. - Status() proto.StateObserved_Status + // State gets current state of monitor. + State() client.UnitState } type selfMonitorT struct { @@ -46,8 +46,8 @@ type selfMonitorT struct { monitor monitor.Monitor policyID string - status proto.StateObserved_Status - reporter status.Reporter + state client.UnitState + reporter state.Reporter policy *model.Policy @@ -63,14 +63,14 @@ type selfMonitorT struct { // // Ensures that the policy that this Fleet Server attached to exists and that it // has a Fleet Server input defined. -func NewSelfMonitor(fleet config.Fleet, bulker bulk.Bulk, monitor monitor.Monitor, policyID string, reporter status.Reporter) SelfMonitor { +func NewSelfMonitor(fleet config.Fleet, bulker bulk.Bulk, monitor monitor.Monitor, policyID string, reporter state.Reporter) SelfMonitor { return &selfMonitorT{ log: log.With().Str("ctx", "policy self monitor").Logger(), fleet: fleet, bulker: bulker, monitor: monitor, policyID: policyID, - status: proto.StateObserved_STARTING, + state: client.UnitStateStarting, reporter: reporter, policyF: dl.QueryLatestPolicies, policiesIndex: dl.FleetPolicies, @@ -101,12 +101,12 @@ LOOP: case <-ctx.Done(): break LOOP case <-cT.C: - status, err := m.process(ctx) + state, err := m.process(ctx) if err != nil { return err } cT.Reset(m.checkTime) - if status == proto.StateObserved_HEALTHY { + if state == client.UnitStateHealthy { // running; can stop break LOOP } @@ -118,11 +118,11 @@ LOOP: return err } } - status, err := m.processPolicies(ctx, policies) + state, err := m.processPolicies(ctx, policies) if err != nil { return err } - if status == proto.StateObserved_HEALTHY { + if state == client.UnitStateHealthy { // running; can stop break LOOP } @@ -132,10 +132,10 @@ LOOP: return nil } -func (m *selfMonitorT) Status() proto.StateObserved_Status { +func (m *selfMonitorT) State() client.UnitState { m.mut.Lock() defer m.mut.Unlock() - return m.status + return m.state } func (m *selfMonitorT) waitStart(ctx context.Context) error { //nolint:unused // not sure if this is used in tests @@ -147,24 +147,24 @@ func (m *selfMonitorT) waitStart(ctx context.Context) error { //nolint:unused // return nil } -func (m *selfMonitorT) process(ctx context.Context) (proto.StateObserved_Status, error) { +func (m *selfMonitorT) process(ctx context.Context) (client.UnitState, error) { policies, err := m.policyF(ctx, m.bulker, dl.WithIndexName(m.policiesIndex)) if err != nil { if !errors.Is(err, es.ErrIndexNotFound) { - return proto.StateObserved_FAILED, nil + return client.UnitStateFailed, nil } m.log.Debug().Str("index", m.policiesIndex).Msg(es.ErrIndexNotFound.Error()) } if len(policies) == 0 { - return m.updateStatus(ctx) + return m.updateState(ctx) } return m.processPolicies(ctx, policies) } -func (m *selfMonitorT) processPolicies(ctx context.Context, policies []model.Policy) (proto.StateObserved_Status, error) { +func (m *selfMonitorT) processPolicies(ctx context.Context, policies []model.Policy) (client.UnitState, error) { if len(policies) == 0 { // nothing to do - return proto.StateObserved_STARTING, nil + return client.UnitStateStarting, nil } latest := m.groupByLatest(policies) for i := range latest { @@ -177,78 +177,78 @@ func (m *selfMonitorT) processPolicies(ctx context.Context, policies []model.Pol break } } - return m.updateStatus(ctx) + return m.updateState(ctx) } func (m *selfMonitorT) groupByLatest(policies []model.Policy) map[string]model.Policy { return groupByLatest(policies) } -func (m *selfMonitorT) updateStatus(ctx context.Context) (proto.StateObserved_Status, error) { +func (m *selfMonitorT) updateState(ctx context.Context) (client.UnitState, error) { m.mut.Lock() defer m.mut.Unlock() if m.policy == nil { // no policy found - m.status = proto.StateObserved_STARTING + m.state = client.UnitStateStarting if m.policyID == "" { - m.reporter.Status(proto.StateObserved_STARTING, "Waiting on default policy with Fleet Server integration", nil) //nolint:errcheck // not clear what to do in failure cases + m.reporter.UpdateState(client.UnitStateStarting, "Waiting on default policy with Fleet Server integration", nil) //nolint:errcheck // not clear what to do in failure cases } else { - m.reporter.Status(proto.StateObserved_STARTING, fmt.Sprintf("Waiting on policy with Fleet Server integration: %s", m.policyID), nil) //nolint:errcheck // not clear what to do in failure cases + m.reporter.UpdateState(client.UnitStateStarting, fmt.Sprintf("Waiting on policy with Fleet Server integration: %s", m.policyID), nil) //nolint:errcheck // not clear what to do in failure cases } - return proto.StateObserved_STARTING, nil + return client.UnitStateStarting, nil } var data policyData err := json.Unmarshal(m.policy.Data, &data) if err != nil { - return proto.StateObserved_FAILED, err + return client.UnitStateFailed, err } if !data.HasType("fleet-server") { // no fleet-server input - m.status = proto.StateObserved_STARTING + m.state = client.UnitStateStarting if m.policyID == "" { - m.reporter.Status(proto.StateObserved_STARTING, "Waiting on fleet-server input to be added to default policy", nil) //nolint:errcheck // not clear what to do in failure cases + m.reporter.UpdateState(client.UnitStateStarting, "Waiting on fleet-server input to be added to default policy", nil) //nolint:errcheck // not clear what to do in failure cases } else { - m.reporter.Status(proto.StateObserved_STARTING, fmt.Sprintf("Waiting on fleet-server input to be added to policy: %s", m.policyID), nil) //nolint:errcheck // not clear what to do in failure cases + m.reporter.UpdateState(client.UnitStateStarting, fmt.Sprintf("Waiting on fleet-server input to be added to policy: %s", m.policyID), nil) //nolint:errcheck // not clear what to do in failure cases } - return proto.StateObserved_STARTING, nil + return client.UnitStateStarting, nil } - status := proto.StateObserved_HEALTHY + state := client.UnitStateHealthy extendMsg := "" var payload map[string]interface{} if m.fleet.Agent.ID == "" { - status = proto.StateObserved_DEGRADED + state = client.UnitStateDegraded extendMsg = "; missing config fleet.agent.id (expected during bootstrap process)" // Elastic Agent has not been enrolled; Fleet Server passes back the enrollment token so the Elastic Agent // can perform enrollment. tokens, err := m.enrollmentTokenF(ctx, m.bulker, m.policy.PolicyID) if err != nil { - return proto.StateObserved_FAILED, err + return client.UnitStateFailed, err } tokens = filterActiveTokens(tokens) if len(tokens) == 0 { // no tokens created for the policy, still starting if m.policyID == "" { - m.reporter.Status(proto.StateObserved_STARTING, "Waiting on active enrollment keys to be created in default policy with Fleet Server integration", nil) //nolint:errcheck // not clear what to do in failure cases + m.reporter.UpdateState(client.UnitStateStarting, "Waiting on active enrollment keys to be created in default policy with Fleet Server integration", nil) //nolint:errcheck // not clear what to do in failure cases } else { - m.reporter.Status(proto.StateObserved_STARTING, fmt.Sprintf("Waiting on active enrollment keys to be created in policy with Fleet Server integration: %s", m.policyID), nil) //nolint:errcheck // not clear what to do in failure cases + m.reporter.UpdateState(client.UnitStateStarting, fmt.Sprintf("Waiting on active enrollment keys to be created in policy with Fleet Server integration: %s", m.policyID), nil) //nolint:errcheck // not clear what to do in failure cases } - return proto.StateObserved_STARTING, nil + return client.UnitStateStarting, nil } payload = map[string]interface{}{ "enrollment_token": tokens[0].APIKey, } } - m.status = status + m.state = state if m.policyID == "" { - m.reporter.Status(status, fmt.Sprintf("Running on default policy with Fleet Server integration%s", extendMsg), payload) //nolint:errcheck // not clear what to do in failure cases + m.reporter.UpdateState(state, fmt.Sprintf("Running on default policy with Fleet Server integration%s", extendMsg), payload) //nolint:errcheck // not clear what to do in failure cases } else { - m.reporter.Status(status, fmt.Sprintf("Running on policy with Fleet Server integration: %s%s", m.policyID, extendMsg), payload) //nolint:errcheck // not clear what to do in failure cases + m.reporter.UpdateState(state, fmt.Sprintf("Running on policy with Fleet Server integration: %s%s", m.policyID, extendMsg), payload) //nolint:errcheck // not clear what to do in failure cases } - return status, nil + return state, nil } type policyData struct { diff --git a/internal/pkg/policy/self_test.go b/internal/pkg/policy/self_test.go index ef2df4813..e87ba56b5 100644 --- a/internal/pkg/policy/self_test.go +++ b/internal/pkg/policy/self_test.go @@ -15,7 +15,7 @@ import ( "testing" "time" - "github.com/elastic/elastic-agent-client/v7/pkg/proto" + "github.com/elastic/elastic-agent-client/v7/pkg/client" "github.com/gofrs/uuid" "github.com/rs/xid" "github.com/stretchr/testify/mock" @@ -69,9 +69,9 @@ func TestSelfMonitor_DefaultPolicy(t *testing.T) { // should be set to starting ftesting.Retry(t, ctx, func(ctx context.Context) error { - status, msg, _ := reporter.Current() - if status != proto.StateObserved_STARTING { - return fmt.Errorf("should be reported as starting; instead its %s", status) + state, msg, _ := reporter.Current() + if state != client.UnitStateStarting { + return fmt.Errorf("should be reported as starting; instead its %s", state) } if msg != "Waiting on default policy with Fleet Server integration" { return fmt.Errorf("should be matching with default policy") @@ -110,9 +110,9 @@ func TestSelfMonitor_DefaultPolicy(t *testing.T) { // should still be set to starting ftesting.Retry(t, ctx, func(ctx context.Context) error { - status, msg, _ := reporter.Current() - if status != proto.StateObserved_STARTING { - return fmt.Errorf("should be reported as starting; instead its %s", status) + state, msg, _ := reporter.Current() + if state != client.UnitStateStarting { + return fmt.Errorf("should be reported as starting; instead its %s", state) } if msg != "Waiting on fleet-server input to be added to default policy" { return fmt.Errorf("should be matching with default policy") @@ -154,9 +154,9 @@ func TestSelfMonitor_DefaultPolicy(t *testing.T) { // should now be set to healthy ftesting.Retry(t, ctx, func(ctx context.Context) error { - status, msg, _ := reporter.Current() - if status != proto.StateObserved_HEALTHY { - return fmt.Errorf("should be reported as healthy; instead its %s", status) + state, msg, _ := reporter.Current() + if state != client.UnitStateHealthy { + return fmt.Errorf("should be reported as healthy; instead its %s", state) } if msg != "Running on default policy with Fleet Server integration" { return fmt.Errorf("should be matching with default policy") @@ -225,9 +225,9 @@ func TestSelfMonitor_DefaultPolicy_Degraded(t *testing.T) { // should be set to starting ftesting.Retry(t, ctx, func(ctx context.Context) error { - status, msg, _ := reporter.Current() - if status != proto.StateObserved_STARTING { - return fmt.Errorf("should be reported as starting; instead its %s", status) + state, msg, _ := reporter.Current() + if state != client.UnitStateStarting { + return fmt.Errorf("should be reported as starting; instead its %s", state) } if msg != "Waiting on default policy with Fleet Server integration" { return fmt.Errorf("should be matching with default policy") @@ -291,9 +291,9 @@ func TestSelfMonitor_DefaultPolicy_Degraded(t *testing.T) { // should be set to starting because of missing active enrollment keys ftesting.Retry(t, ctx, func(ctx context.Context) error { - status, msg, _ := reporter.Current() - if status != proto.StateObserved_STARTING { - return fmt.Errorf("should be reported as starting; instead its %s", status) + state, msg, _ := reporter.Current() + if state != client.UnitStateStarting { + return fmt.Errorf("should be reported as starting; instead its %s", state) } if msg != "Waiting on active enrollment keys to be created in default policy with Fleet Server integration" { return fmt.Errorf("should be matching with default policy") @@ -318,9 +318,9 @@ func TestSelfMonitor_DefaultPolicy_Degraded(t *testing.T) { // should now be set to degraded ftesting.Retry(t, ctx, func(ctx context.Context) error { - status, msg, payload := reporter.Current() - if status != proto.StateObserved_DEGRADED { - return fmt.Errorf("should be reported as degraded; instead its %s", status) + state, msg, payload := reporter.Current() + if state != client.UnitStateDegraded { + return fmt.Errorf("should be reported as degraded; instead its %s", state) } if msg != "Running on default policy with Fleet Server integration; missing config fleet.agent.id (expected during bootstrap process)" { return fmt.Errorf("should be matching with default policy") @@ -386,9 +386,9 @@ func TestSelfMonitor_SpecificPolicy(t *testing.T) { // should be set to starting ftesting.Retry(t, ctx, func(ctx context.Context) error { - status, msg, _ := reporter.Current() - if status != proto.StateObserved_STARTING { - return fmt.Errorf("should be reported as starting; instead its %s", status) + state, msg, _ := reporter.Current() + if state != client.UnitStateStarting { + return fmt.Errorf("should be reported as starting; instead its %s", state) } if msg != fmt.Sprintf("Waiting on policy with Fleet Server integration: %s", policyID) { return fmt.Errorf("should be matching with specific policy") @@ -426,9 +426,9 @@ func TestSelfMonitor_SpecificPolicy(t *testing.T) { // should still be set to starting ftesting.Retry(t, ctx, func(ctx context.Context) error { - status, msg, _ := reporter.Current() - if status != proto.StateObserved_STARTING { - return fmt.Errorf("should be reported as starting; instead its %s", status) + state, msg, _ := reporter.Current() + if state != client.UnitStateStarting { + return fmt.Errorf("should be reported as starting; instead its %s", state) } if msg != fmt.Sprintf("Waiting on fleet-server input to be added to policy: %s", policyID) { return fmt.Errorf("should be matching with specific policy") @@ -470,9 +470,9 @@ func TestSelfMonitor_SpecificPolicy(t *testing.T) { // should now be set to healthy ftesting.Retry(t, ctx, func(ctx context.Context) error { - status, msg, _ := reporter.Current() - if status != proto.StateObserved_HEALTHY { - return fmt.Errorf("should be reported as healthy; instead its %s", status) + state, msg, _ := reporter.Current() + if state != client.UnitStateHealthy { + return fmt.Errorf("should be reported as healthy; instead its %s", state) } if msg != fmt.Sprintf("Running on policy with Fleet Server integration: %s", policyID) { return fmt.Errorf("should be matching with specific policy") @@ -542,9 +542,9 @@ func TestSelfMonitor_SpecificPolicy_Degraded(t *testing.T) { // should be set to starting ftesting.Retry(t, ctx, func(ctx context.Context) error { - status, msg, _ := reporter.Current() - if status != proto.StateObserved_STARTING { - return fmt.Errorf("should be reported as starting; instead its %s", status) + state, msg, _ := reporter.Current() + if state != client.UnitStateStarting { + return fmt.Errorf("should be reported as starting; instead its %s", state) } if msg != fmt.Sprintf("Waiting on policy with Fleet Server integration: %s", policyID) { return fmt.Errorf("should be matching with specific policy") @@ -607,9 +607,9 @@ func TestSelfMonitor_SpecificPolicy_Degraded(t *testing.T) { // should be set to starting because of missing active enrollment keys ftesting.Retry(t, ctx, func(ctx context.Context) error { - status, msg, _ := reporter.Current() - if status != proto.StateObserved_STARTING { - return fmt.Errorf("should be reported as starting; instead its %s", status) + state, msg, _ := reporter.Current() + if state != client.UnitStateStarting { + return fmt.Errorf("should be reported as starting; instead its %s", state) } if msg != fmt.Sprintf("Waiting on active enrollment keys to be created in policy with Fleet Server integration: %s", policyID) { return fmt.Errorf("should be matching with specific policy") @@ -634,9 +634,9 @@ func TestSelfMonitor_SpecificPolicy_Degraded(t *testing.T) { // should now be set to degraded ftesting.Retry(t, ctx, func(ctx context.Context) error { - status, msg, payload := reporter.Current() - if status != proto.StateObserved_DEGRADED { - return fmt.Errorf("should be reported as degraded; instead its %s", status) + state, msg, payload := reporter.Current() + if state != client.UnitStateDegraded { + return fmt.Errorf("should be reported as degraded; instead its %s", state) } if msg != fmt.Sprintf("Running on policy with Fleet Server integration: %s; missing config fleet.agent.id (expected during bootstrap process)", policyID) { return fmt.Errorf("should be matching with specific policy") @@ -663,22 +663,22 @@ func TestSelfMonitor_SpecificPolicy_Degraded(t *testing.T) { type FakeReporter struct { lock sync.Mutex - status proto.StateObserved_Status + state client.UnitState msg string payload map[string]interface{} } -func (r *FakeReporter) Status(status proto.StateObserved_Status, message string, payload map[string]interface{}) error { +func (r *FakeReporter) UpdateState(state client.UnitState, message string, payload map[string]interface{}) error { r.lock.Lock() defer r.lock.Unlock() - r.status = status + r.state = state r.msg = message r.payload = payload return nil } -func (r *FakeReporter) Current() (proto.StateObserved_Status, string, map[string]interface{}) { +func (r *FakeReporter) Current() (client.UnitState, string, map[string]interface{}) { r.lock.Lock() defer r.lock.Unlock() - return r.status, r.msg, r.payload + return r.state, r.msg, r.payload } diff --git a/internal/pkg/state/reporter.go b/internal/pkg/state/reporter.go new file mode 100644 index 000000000..e2224c80f --- /dev/null +++ b/internal/pkg/state/reporter.go @@ -0,0 +1,51 @@ +// 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 state wraps elastic-agent-client's unit.UpdateState rpc calls. +package state + +import ( + "github.com/elastic/elastic-agent-client/v7/pkg/client" + "github.com/rs/zerolog/log" +) + +// Reporter is interface that reports updated state on. +type Reporter interface { + // UpdateState triggers updating the state. + UpdateState(state client.UnitState, message string, payload map[string]interface{}) error +} + +// Log will write state' to log. +type Log struct{} + +// NewLog creates a Log. +func NewLog() *Log { + return &Log{} +} + +// UpdateState triggers updating the state. +func (l *Log) UpdateState(state client.UnitState, message string, _ map[string]interface{}) error { + log.Info().Str("state", state.String()).Msg(message) + return nil +} + +// Chained calls State on all the provided reporters in the provided order. +type Chained struct { + reporters []Reporter +} + +// NewChained creates a Chained with provided reporters. +func NewChained(reporters ...Reporter) *Chained { + return &Chained{reporters} +} + +// UpdateState triggers updating the state. +func (l *Chained) UpdateState(state client.UnitState, message string, payload map[string]interface{}) error { + for _, reporter := range l.reporters { + if err := reporter.UpdateState(state, message, payload); err != nil { + return err + } + } + return nil +} diff --git a/internal/pkg/status/reporter.go b/internal/pkg/status/reporter.go deleted file mode 100644 index ac823ea17..000000000 --- a/internal/pkg/status/reporter.go +++ /dev/null @@ -1,53 +0,0 @@ -// 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 status wraps elastic-agent-client's Status rpc calls. -// The Status calls update fleet-server's status (RUNNING, ERROR, etc) elastic-agent. -package status - -import ( - "github.com/rs/zerolog/log" - - "github.com/elastic/elastic-agent-client/v7/pkg/proto" -) - -// Reporter is interface that reports updated status on. -type Reporter interface { - // Status triggers updating the status. - Status(status proto.StateObserved_Status, message string, payload map[string]interface{}) error -} - -// Log will write status' to log. -type Log struct{} - -// NewLog creates a Log. -func NewLog() *Log { - return &Log{} -} - -// Status triggers updating the status. -func (l *Log) Status(status proto.StateObserved_Status, message string, _ map[string]interface{}) error { - log.Info().Str("status", status.String()).Msg(message) - return nil -} - -// Chained calls Status on all the provided reporters in the provided order. -type Chained struct { - reporters []Reporter -} - -// NewChained creates a Chained with provided reporters. -func NewChained(reporters ...Reporter) *Chained { - return &Chained{reporters} -} - -// Status triggers updating the status. -func (l *Chained) Status(status proto.StateObserved_Status, message string, payload map[string]interface{}) error { - for _, reporter := range l.reporters { - if err := reporter.Status(status, message, payload); err != nil { - return err - } - } - return nil -}