diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index af7954520b9..200d0b9277a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,11 +1,11 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.0.1 + rev: v4.4.0 hooks: - id: check-merge-conflict - repo: https://github.com/elastic/apm-pipeline-library.git - rev: current + rev: v1.1.397 hooks: - id: check-jenkins-pipelines files: ^(.ci/(.*\.groovy|Jenkinsfile)|Jenkinsfile)$ diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index 1f15de0d418..83b5f50e7e9 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -10,7 +10,6 @@ https://github.com/elastic/beats/compare/v8.7.1\...main[Check the HEAD diff] *Affecting all Beats* - *Auditbeat* @@ -228,7 +227,7 @@ automatic splitting at root level, if root level element is an array. {pull}3415 - Add Hetzner Cloud as a provider for `add_cloud_metadata`. {pull}35456[35456] - Reload Beat when TLS certificates or key files are modified. {issue}34408[34408] {pull}34416[34416] - Upgrade version of elastic-agent-autodiscover to v0.6.1 for improved memory consumption on k8s. {pull}35483[35483] - +- Added `orchestrator.cluster.id` and `orchestrator.cluster.name` fields to the add_cloud_metadata processor, AWS cloud provider. {pull}35182[35182] *Auditbeat* diff --git a/NOTICE.txt b/NOTICE.txt index 028e5edcb3d..3d8dedd1ade 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -5566,6 +5566,218 @@ Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/crede limitations under the License. +-------------------------------------------------------------------------------- +Dependency : github.com/aws/aws-sdk-go-v2/feature/ec2/imds +Version: v1.12.7 +Licence type (autodetected): Apache-2.0 +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/feature/ec2/imds@v1.12.7/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/aws/aws-sdk-go-v2/feature/s3/manager Version: v1.11.17 @@ -31647,218 +31859,6 @@ Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/aws/p limitations under the License. --------------------------------------------------------------------------------- -Dependency : github.com/aws/aws-sdk-go-v2/feature/ec2/imds -Version: v1.12.7 -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/feature/ec2/imds@v1.12.7/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/aws/aws-sdk-go-v2/internal/configsources Version: v1.1.33 diff --git a/dev-tools/kubernetes/Tiltfile b/dev-tools/kubernetes/Tiltfile index edfef02550e..0a373ceb05f 100644 --- a/dev-tools/kubernetes/Tiltfile +++ b/dev-tools/kubernetes/Tiltfile @@ -47,6 +47,18 @@ def build( default_registry(docker_registry) print("Docker registry: {}".format(docker_registry)) + if k8s_env == "aws": + # In order to push to AWS you need to run: + # aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin XXXXX.dkr.ecr.us-east-2.amazonaws.com/metricbeat-debug + # + # More info at https://docs.aws.amazon.com/AmazonECR/latest/userguide/docker-push-ecr-image.html + docker_registry = "XXXXX.dkr.ecr.us-east-2.amazonaws.com".format( + docker_image) + + default_registry(docker_registry) + print("Docker registry: {}".format(docker_registry)) + + print("Docker image: {}".format(docker_image)) docker_file = '{}/Dockerfile.{}'.format(beat, mode) @@ -149,7 +161,7 @@ def beat( if arch not in ["arm64", "amd64"]: print("Invalid arch: {}".format(arch)) exit(-1) - if k8s_env not in ["kind", "gcp"]: + if k8s_env not in ["kind", "gcp", "aws"]: print("Invalid k8s_env: {}".format(k8s_env)) exit(-1) if k8s_cluster not in ["single", "multi"]: @@ -191,10 +203,10 @@ def beat( k8s_expose(beat=beat, mode=mode, k8s_cluster=k8s_cluster) -beat(beat="heartbeat", - mode="debug", - # mode="run", - arch="arm64", - k8s_env="kind", +beat(beat="metricbeat", + # mode="debug", + mode="run", + arch="amd64", + k8s_env="aws", k8s_cluster="single", ) diff --git a/go.mod b/go.mod index 18d88ea45ef..cbb172ee357 100644 --- a/go.mod +++ b/go.mod @@ -189,6 +189,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1 github.com/Azure/go-autorest/autorest/adal v0.9.14 github.com/apache/arrow/go/v11 v11.0.0 + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.7 github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.17 github.com/aws/aws-sdk-go-v2/service/cloudformation v1.20.4 github.com/aws/aws-sdk-go-v2/service/kinesis v1.15.8 @@ -242,7 +243,6 @@ require ( github.com/armon/go-radix v1.0.0 // indirect github.com/aws/aws-sdk-go v1.38.60 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.7 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.14 // indirect diff --git a/libbeat/processors/add_cloud_metadata/generic_fetcher.go b/libbeat/processors/add_cloud_metadata/generic_fetcher.go new file mode 100644 index 00000000000..9a1fa95fb88 --- /dev/null +++ b/libbeat/processors/add_cloud_metadata/generic_fetcher.go @@ -0,0 +1,55 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package add_cloud_metadata + +import ( + "context" + "net/http" + + cfg "github.com/elastic/elastic-agent-libs/config" + "github.com/elastic/elastic-agent-libs/mapstr" +) + +type genericFetcher struct { + provider string + schema schemaConv + fetchRawProviderMetadata func(context.Context, http.Client, *result) +} + +func newGenericMetadataFetcher( + c *cfg.C, + provider string, + conv schemaConv, + genericFetcherMeta func(context.Context, http.Client, *result), +) (*genericFetcher, error) { + + gFetcher := &genericFetcher{provider, conv, genericFetcherMeta} + return gFetcher, nil +} + +func (g *genericFetcher) fetchMetadata(ctx context.Context, client http.Client) result { + res := result{provider: g.provider, metadata: mapstr.M{}} + g.fetchRawProviderMetadata(ctx, client, &res) + if res.err != nil { + return res + } + res.metadata = g.schema(res.metadata) + _, _ = res.metadata.Put("cloud.provider", g.provider) + + return res +} diff --git a/libbeat/processors/add_cloud_metadata/provider_aws_ec2.go b/libbeat/processors/add_cloud_metadata/provider_aws_ec2.go index 54ac4eaf9b2..9918654728e 100644 --- a/libbeat/processors/add_cloud_metadata/provider_aws_ec2.go +++ b/libbeat/processors/add_cloud_metadata/provider_aws_ec2.go @@ -18,125 +18,134 @@ package add_cloud_metadata import ( + "context" "fmt" - "io" - "io/ioutil" - "net" "net/http" + awssdk "github.com/aws/aws-sdk-go-v2/aws" + awscfg "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/feature/ec2/imds" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" + "github.com/elastic/elastic-agent-libs/logp" "github.com/elastic/elastic-agent-libs/mapstr" - s "github.com/elastic/beats/v7/libbeat/common/schema" - c "github.com/elastic/beats/v7/libbeat/common/schema/mapstriface" conf "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/transport/tlscommon" -) - -const ( - ec2InstanceIdentityURI = "/2014-02-25/dynamic/instance-identity/document" - ec2InstanceIMDSv2TokenValueHeader = "X-aws-ec2-metadata-token" - ec2InstanceIMDSv2TokenTTLHeader = "X-aws-ec2-metadata-token-ttl-seconds" - ec2InstanceIMDSv2TokenTTLValue = "21600" - ec2InstanceIMDSv2TokenURI = "/latest/api/token" ) -// fetches IMDSv2 token, returns empty one on errors -func getIMDSv2Token(c *conf.C) string { - logger := logp.NewLogger("add_cloud_metadata") +type IMDSClient interface { + GetInstanceIdentityDocument(ctx context.Context, params *imds.GetInstanceIdentityDocumentInput, optFns ...func(*imds.Options)) (*imds.GetInstanceIdentityDocumentOutput, error) +} - config := defaultConfig() - if err := c.Unpack(&config); err != nil { - logger.Warnf("error when load config for getting IMDSv2 token: %s. No token in the metadata request will be used.", err) - return "" - } +var NewIMDSClient func(cfg awssdk.Config) IMDSClient = func(cfg awssdk.Config) IMDSClient { + return imds.NewFromConfig(cfg) +} - tlsConfig, err := tlscommon.LoadTLSConfig(config.TLS) - if err != nil { - logger.Warnf("error when load TLS config for getting IMDSv2 token: %s. No token in the metadata request will be used.", err) - return "" - } +type EC2Client interface { + DescribeTags(ctx context.Context, params *ec2.DescribeTagsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeTagsOutput, error) +} - client := http.Client{ - Timeout: config.Timeout, - Transport: &http.Transport{ - DisableKeepAlives: true, - DialContext: (&net.Dialer{ - Timeout: config.Timeout, - KeepAlive: 0, - }).DialContext, - TLSClientConfig: tlsConfig.ToConfig(), - }, - } +var NewEC2Client func(cfg awssdk.Config) EC2Client = func(cfg awssdk.Config) EC2Client { + return ec2.NewFromConfig(cfg) +} - tokenReq, err := http.NewRequest("PUT", fmt.Sprintf("http://%s%s", metadataHost, ec2InstanceIMDSv2TokenURI), nil) - if err != nil { - logger.Warnf("error when make token request for getting IMDSv2 token: %s. No token in the metadata request will be used.", err) - return "" - } +// AWS EC2 Metadata Service +var ec2MetadataFetcher = provider{ + Name: "aws-ec2", - tokenReq.Header.Add(ec2InstanceIMDSv2TokenTTLHeader, ec2InstanceIMDSv2TokenTTLValue) - rsp, err := client.Do(tokenReq) - if rsp == nil { - logger.Warnf("read token request for getting IMDSv2 token returns empty: %s. No token in the metadata request will be used.", err) - return "" - } + Local: true, - defer func(body io.ReadCloser) { - if body != nil { - body.Close() + Create: func(_ string, config *conf.C) (metadataFetcher, error) { + ec2Schema := func(m map[string]interface{}) mapstr.M { + m["service"] = mapstr.M{ + "name": "EC2", + } + return mapstr.M{"cloud": m} } - }(rsp.Body) + fetcher, err := newGenericMetadataFetcher(config, "aws", ec2Schema, fetchRawProviderMetadata) + return fetcher, err + }, +} + +// fetchRaw queries raw metadata from a hosting provider's metadata service. +func fetchRawProviderMetadata( + ctx context.Context, + client http.Client, + result *result, +) { + logger := logp.NewLogger("add_cloud_metadata") + + // LoadDefaultConfig loads the EC2 role credentials + awsConfig, err := awscfg.LoadDefaultConfig(context.TODO(), awscfg.WithHTTPClient(&client)) if err != nil { - logger.Warnf("error when read token request for getting IMDSv2 token: %s. No token in the metadata request will be used.", err) - return "" + logger.Warnf("error loading AWS default configuration: %s.", err) + result.err = fmt.Errorf("failed loading AWS default configuration: %w", err) + return } + awsClient := NewIMDSClient(awsConfig) - if rsp.StatusCode != http.StatusOK { - logger.Warnf("error when check request status for getting IMDSv2 token: http request status %d. No token in the metadata request will be used.", rsp.StatusCode) - return "" + instanceIdentity, err := awsClient.GetInstanceIdentityDocument(context.TODO(), &imds.GetInstanceIdentityDocumentInput{}) + if err != nil { + logger.Warnf("error fetching EC2 Identity Document: %s.", err) + result.err = fmt.Errorf("failed fetching EC2 Identity Document: %w", err) + return } - all, err := ioutil.ReadAll(rsp.Body) + // AWS Region must be set to be able to get EC2 Tags + awsRegion := instanceIdentity.InstanceIdentityDocument.Region + awsConfig.Region = awsRegion + + clusterName, err := fetchEC2ClusterNameTag(awsConfig, instanceIdentity.InstanceIdentityDocument.InstanceID) if err != nil { - logger.Warnf("error when reading token request for getting IMDSv2 token: %s. No token in the metadata request will be used.", err) - return "" + logger.Warnf("error fetching cluster name metadata: %s.", err) } - return string(all) -} + accountID := instanceIdentity.InstanceIdentityDocument.AccountID -// AWS EC2 Metadata Service -var ec2MetadataFetcher = provider{ - Name: "aws-ec2", + _, _ = result.metadata.Put("instance.id", instanceIdentity.InstanceIdentityDocument.InstanceID) + _, _ = result.metadata.Put("machine.type", instanceIdentity.InstanceIdentityDocument.InstanceType) + _, _ = result.metadata.Put("region", awsRegion) + _, _ = result.metadata.Put("availability_zone", instanceIdentity.InstanceIdentityDocument.AvailabilityZone) + _, _ = result.metadata.Put("account.id", accountID) + _, _ = result.metadata.Put("image.id", instanceIdentity.InstanceIdentityDocument.ImageID) - Local: true, + // for AWS cluster ID is used cluster ARN: arn:partition:service:region:account-id:resource-type/resource-id, example: + // arn:aws:eks:us-east-2:627286350134:cluster/cluster-name + if clusterName != "" { + clusterARN := fmt.Sprintf("arn:aws:eks:%s:%s:cluster/%v", awsRegion, accountID, clusterName) - Create: func(_ string, config *conf.C) (metadataFetcher, error) { - ec2Schema := func(m map[string]interface{}) mapstr.M { - m["serviceName"] = "EC2" - out, _ := s.Schema{ - "instance": s.Object{"id": c.Str("instanceId")}, - "machine": s.Object{"type": c.Str("instanceType")}, - "region": c.Str("region"), - "availability_zone": c.Str("availabilityZone"), - "service": s.Object{ - "name": c.Str("serviceName"), - }, - "account": s.Object{"id": c.Str("accountId")}, - "image": s.Object{"id": c.Str("imageId")}, - }.Apply(m) - return mapstr.M{"cloud": out} - } + _, _ = result.metadata.Put("orchestrator.cluster.id", clusterARN) + _, _ = result.metadata.Put("orchestrator.cluster.name", clusterName) + } +} - headers := make(map[string]string, 1) - token := getIMDSv2Token(config) - if len(token) > 0 { - headers[ec2InstanceIMDSv2TokenValueHeader] = token - } +func fetchEC2ClusterNameTag(awsConfig awssdk.Config, instanceID string) (string, error) { + svc := NewEC2Client(awsConfig) + input := &ec2.DescribeTagsInput{ + Filters: []types.Filter{ + { + Name: awssdk.String("resource-id"), + Values: []string{ + instanceID, + }, + }, + { + Name: awssdk.String("key"), + Values: []string{ + "eks:cluster-name", + }, + }, + }, + } - fetcher, err := newMetadataFetcher(config, "aws", headers, metadataHost, ec2Schema, ec2InstanceIdentityURI) - return fetcher, err - }, + tagsResult, err := svc.DescribeTags(context.TODO(), input) + if err != nil { + return "", fmt.Errorf("error fetching EC2 Tags: %w", err) + } + if len(tagsResult.Tags) == 1 { + return *tagsResult.Tags[0].Value, nil + } + return "", nil } diff --git a/libbeat/processors/add_cloud_metadata/provider_aws_ec2_test.go b/libbeat/processors/add_cloud_metadata/provider_aws_ec2_test.go index b167917a97b..a66ac00546c 100644 --- a/libbeat/processors/add_cloud_metadata/provider_aws_ec2_test.go +++ b/libbeat/processors/add_cloud_metadata/provider_aws_ec2_test.go @@ -18,12 +18,15 @@ package add_cloud_metadata import ( + "context" "fmt" - "net/http" - "net/http/httptest" "os" "testing" + awssdk "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/feature/ec2/imds" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/stretchr/testify/assert" "github.com/elastic/beats/v7/libbeat/beat" @@ -32,78 +35,112 @@ import ( "github.com/elastic/elastic-agent-libs/mapstr" ) -func createEC2MockAPI(responseMap map[string]string) *httptest.Server { - h := func(w http.ResponseWriter, r *http.Request) { - if res, ok := responseMap[r.RequestURI]; ok { - w.Write([]byte(res)) - return - } - http.Error(w, "not found", http.StatusNotFound) - } - return httptest.NewServer(http.HandlerFunc(h)) +type MockIMDSClient struct { + GetInstanceIdentityDocumentFunc func(ctx context.Context, params *imds.GetInstanceIdentityDocumentInput, optFns ...func(*imds.Options)) (*imds.GetInstanceIdentityDocumentOutput, error) +} + +func (m *MockIMDSClient) GetInstanceIdentityDocument(ctx context.Context, params *imds.GetInstanceIdentityDocumentInput, optFns ...func(*imds.Options)) (*imds.GetInstanceIdentityDocumentOutput, error) { + return m.GetInstanceIdentityDocumentFunc(ctx, params, optFns...) +} + +type MockEC2Client struct { + DescribeTagsFunc func(ctx context.Context, params *ec2.DescribeTagsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeTagsOutput, error) +} + +func (e *MockEC2Client) DescribeTags(ctx context.Context, params *ec2.DescribeTagsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeTagsOutput, error) { + return e.DescribeTagsFunc(ctx, params, optFns...) } func TestMain(m *testing.M) { - logp.TestingSetup() + _ = logp.TestingSetup() code := m.Run() os.Exit(code) - } func TestRetrieveAWSMetadataEC2(t *testing.T) { - - const ( + var ( // not the best way to use a response template // but this should serve until we need to test // documents containing very different values accountIDDoc1 = "111111111111111" regionDoc1 = "us-east-1" availabilityZoneDoc1 = "us-east-1c" - instanceIDDoc1 = "i-11111111" imageIDDoc1 = "ami-abcd1234" instanceTypeDoc1 = "t2.medium" - - instanceIDDoc2 = "i-22222222" - - templateDoc = `{ - "accountId" : "%s", - "region" : "%s", - "availabilityZone" : "%s", - "instanceId" : "%s", - "imageId" : "%s", - "instanceType" : "%s", - "devpayProductCodes" : null, - "privateIp" : "10.0.0.1", - "version" : "2010-08-31", - "billingProducts" : null, - "pendingTime" : "2016-09-20T15:43:02Z", - "architecture" : "x86_64", - "kernelId" : null, - "ramdiskId" : null - }` - ) - - sampleEC2Doc1 := fmt.Sprintf( - templateDoc, - accountIDDoc1, - regionDoc1, - availabilityZoneDoc1, - instanceIDDoc1, - imageIDDoc1, - instanceTypeDoc1, + instanceIDDoc2 = "i-22222222" + clusterNameKey = "eks:cluster-name" + clusterNameValue = "test" + instanceIDDoc1 = "i-11111111" ) - var testCases = []struct { - testName string - ec2ResponseMap map[string]string - processorOverwrite bool - previousEvent mapstr.M - - expectedEvent mapstr.M + var tests = []struct { + testName string + mockGetInstanceIdentity func(ctx context.Context, params *imds.GetInstanceIdentityDocumentInput, optFns ...func(*imds.Options)) (*imds.GetInstanceIdentityDocumentOutput, error) + mockEc2Tags func(ctx context.Context, params *ec2.DescribeTagsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeTagsOutput, error) + processorOverwrite bool + previousEvent mapstr.M + expectedEvent mapstr.M }{ { - testName: "all fields from processor", - ec2ResponseMap: map[string]string{ec2InstanceIdentityURI: sampleEC2Doc1}, + testName: "valid instance identity document, no cluster tags", + mockGetInstanceIdentity: func(ctx context.Context, params *imds.GetInstanceIdentityDocumentInput, optFns ...func(*imds.Options)) (*imds.GetInstanceIdentityDocumentOutput, error) { + return &imds.GetInstanceIdentityDocumentOutput{ + InstanceIdentityDocument: imds.InstanceIdentityDocument{ + AvailabilityZone: availabilityZoneDoc1, + Region: regionDoc1, + InstanceID: instanceIDDoc1, + InstanceType: instanceTypeDoc1, + AccountID: accountIDDoc1, + ImageID: imageIDDoc1, + }, + }, nil + }, + mockEc2Tags: func(ctx context.Context, params *ec2.DescribeTagsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeTagsOutput, error) { + return &ec2.DescribeTagsOutput{ + Tags: []types.TagDescription{}, + }, nil + }, + processorOverwrite: false, + previousEvent: mapstr.M{}, + expectedEvent: mapstr.M{ + "cloud": mapstr.M{ + "provider": "aws", + "account": mapstr.M{"id": accountIDDoc1}, + "instance": mapstr.M{"id": instanceIDDoc1}, + "machine": mapstr.M{"type": instanceTypeDoc1}, + "image": mapstr.M{"id": imageIDDoc1}, + "region": regionDoc1, + "availability_zone": availabilityZoneDoc1, + "service": mapstr.M{"name": "EC2"}, + }, + }, + }, + { + testName: "all fields from processor", + mockGetInstanceIdentity: func(ctx context.Context, params *imds.GetInstanceIdentityDocumentInput, optFns ...func(*imds.Options)) (*imds.GetInstanceIdentityDocumentOutput, error) { + return &imds.GetInstanceIdentityDocumentOutput{ + InstanceIdentityDocument: imds.InstanceIdentityDocument{ + AvailabilityZone: availabilityZoneDoc1, + Region: regionDoc1, + InstanceID: instanceIDDoc1, + InstanceType: instanceTypeDoc1, + AccountID: accountIDDoc1, + ImageID: imageIDDoc1, + }, + }, nil + }, + mockEc2Tags: func(ctx context.Context, params *ec2.DescribeTagsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeTagsOutput, error) { + return &ec2.DescribeTagsOutput{ + Tags: []types.TagDescription{ + { + Key: &clusterNameKey, + ResourceId: &instanceIDDoc1, + ResourceType: "instance", + Value: &clusterNameValue, + }, + }, + }, nil + }, processorOverwrite: false, previousEvent: mapstr.M{}, expectedEvent: mapstr.M{ @@ -115,16 +152,42 @@ func TestRetrieveAWSMetadataEC2(t *testing.T) { "image": mapstr.M{"id": imageIDDoc1}, "region": regionDoc1, "availability_zone": availabilityZoneDoc1, - "service": mapstr.M{ - "name": "EC2", + "service": mapstr.M{"name": "EC2"}, + "orchestrator": mapstr.M{ + "cluster": mapstr.M{ + "name": clusterNameValue, + "id": fmt.Sprintf("arn:aws:eks:%s:%s:cluster/%s", regionDoc1, accountIDDoc1, clusterNameValue), + }, }, }, }, }, - { - testName: "instanceId pre-informed, no overwrite", - ec2ResponseMap: map[string]string{ec2InstanceIdentityURI: sampleEC2Doc1}, + testName: "instanceId pre-informed, no overwrite", + mockGetInstanceIdentity: func(ctx context.Context, params *imds.GetInstanceIdentityDocumentInput, optFns ...func(*imds.Options)) (*imds.GetInstanceIdentityDocumentOutput, error) { + return &imds.GetInstanceIdentityDocumentOutput{ + InstanceIdentityDocument: imds.InstanceIdentityDocument{ + AvailabilityZone: availabilityZoneDoc1, + Region: regionDoc1, + InstanceID: instanceIDDoc1, + InstanceType: instanceTypeDoc1, + AccountID: accountIDDoc1, + ImageID: imageIDDoc1, + }, + }, nil + }, + mockEc2Tags: func(ctx context.Context, params *ec2.DescribeTagsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeTagsOutput, error) { + return &ec2.DescribeTagsOutput{ + Tags: []types.TagDescription{ + { + Key: &clusterNameKey, + ResourceId: &instanceIDDoc1, + ResourceType: "instance", + Value: &clusterNameValue, + }, + }, + }, nil + }, processorOverwrite: false, previousEvent: mapstr.M{ "cloud": mapstr.M{ @@ -137,13 +200,35 @@ func TestRetrieveAWSMetadataEC2(t *testing.T) { }, }, }, - { // NOTE: In this case, add_cloud_metadata will overwrite cloud fields because // it won't detect cloud.provider as a cloud field. This is not the behavior we // expect and will find a better solution later in issue 11697. - testName: "only cloud.provider pre-informed, no overwrite", - ec2ResponseMap: map[string]string{ec2InstanceIdentityURI: sampleEC2Doc1}, + testName: "only cloud.provider pre-informed, no overwrite", + mockGetInstanceIdentity: func(ctx context.Context, params *imds.GetInstanceIdentityDocumentInput, optFns ...func(*imds.Options)) (*imds.GetInstanceIdentityDocumentOutput, error) { + return &imds.GetInstanceIdentityDocumentOutput{ + InstanceIdentityDocument: imds.InstanceIdentityDocument{ + AvailabilityZone: availabilityZoneDoc1, + Region: regionDoc1, + InstanceID: instanceIDDoc1, + InstanceType: instanceTypeDoc1, + AccountID: accountIDDoc1, + ImageID: imageIDDoc1, + }, + }, nil + }, + mockEc2Tags: func(ctx context.Context, params *ec2.DescribeTagsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeTagsOutput, error) { + return &ec2.DescribeTagsOutput{ + Tags: []types.TagDescription{ + { + Key: &clusterNameKey, + ResourceId: &instanceIDDoc1, + ResourceType: "instance", + Value: &clusterNameValue, + }, + }, + }, nil + }, processorOverwrite: false, previousEvent: mapstr.M{ "cloud.provider": "aws", @@ -158,37 +243,35 @@ func TestRetrieveAWSMetadataEC2(t *testing.T) { "image": mapstr.M{"id": imageIDDoc1}, "region": regionDoc1, "availability_zone": availabilityZoneDoc1, - "service": mapstr.M{ - "name": "EC2", + "service": mapstr.M{"name": "EC2"}, + "orchestrator": mapstr.M{ + "cluster": mapstr.M{ + "name": clusterNameValue, + "id": fmt.Sprintf("arn:aws:eks:%s:%s:cluster/%s", regionDoc1, accountIDDoc1, clusterNameValue), + }, }, }, }, }, - { - testName: "all fields from processor, overwrite", - ec2ResponseMap: map[string]string{ec2InstanceIdentityURI: sampleEC2Doc1}, - processorOverwrite: true, - previousEvent: mapstr.M{}, - expectedEvent: mapstr.M{ - "cloud": mapstr.M{ - "provider": "aws", - "account": mapstr.M{"id": accountIDDoc1}, - "instance": mapstr.M{"id": instanceIDDoc1}, - "machine": mapstr.M{"type": instanceTypeDoc1}, - "image": mapstr.M{"id": imageIDDoc1}, - "region": regionDoc1, - "availability_zone": availabilityZoneDoc1, - "service": mapstr.M{ - "name": "EC2", + testName: "instanceId pre-informed, overwrite", + mockGetInstanceIdentity: func(ctx context.Context, params *imds.GetInstanceIdentityDocumentInput, optFns ...func(*imds.Options)) (*imds.GetInstanceIdentityDocumentOutput, error) { + return &imds.GetInstanceIdentityDocumentOutput{ + InstanceIdentityDocument: imds.InstanceIdentityDocument{ + AvailabilityZone: availabilityZoneDoc1, + Region: regionDoc1, + InstanceID: instanceIDDoc1, + InstanceType: instanceTypeDoc1, + AccountID: accountIDDoc1, + ImageID: imageIDDoc1, }, - }, + }, nil + }, + mockEc2Tags: func(ctx context.Context, params *ec2.DescribeTagsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeTagsOutput, error) { + return &ec2.DescribeTagsOutput{ + Tags: []types.TagDescription{}, + }, nil }, - }, - - { - testName: "instanceId pre-informed, overwrite", - ec2ResponseMap: map[string]string{ec2InstanceIdentityURI: sampleEC2Doc1}, processorOverwrite: true, previousEvent: mapstr.M{ "cloud": mapstr.M{ @@ -204,16 +287,29 @@ func TestRetrieveAWSMetadataEC2(t *testing.T) { "image": mapstr.M{"id": imageIDDoc1}, "region": regionDoc1, "availability_zone": availabilityZoneDoc1, - "service": mapstr.M{ - "name": "EC2", - }, + "service": mapstr.M{"name": "EC2"}, }, }, }, - { - testName: "only cloud.provider pre-informed, overwrite", - ec2ResponseMap: map[string]string{ec2InstanceIdentityURI: sampleEC2Doc1}, + testName: "only cloud.provider pre-informed, overwrite", + mockGetInstanceIdentity: func(ctx context.Context, params *imds.GetInstanceIdentityDocumentInput, optFns ...func(*imds.Options)) (*imds.GetInstanceIdentityDocumentOutput, error) { + return &imds.GetInstanceIdentityDocumentOutput{ + InstanceIdentityDocument: imds.InstanceIdentityDocument{ + AvailabilityZone: availabilityZoneDoc1, + Region: regionDoc1, + InstanceID: instanceIDDoc1, + InstanceType: instanceTypeDoc1, + AccountID: accountIDDoc1, + ImageID: imageIDDoc1, + }, + }, nil + }, + mockEc2Tags: func(ctx context.Context, params *ec2.DescribeTagsInput, optFns ...func(*ec2.Options)) (*ec2.DescribeTagsOutput, error) { + return &ec2.DescribeTagsOutput{ + Tags: []types.TagDescription{}, + }, nil + }, processorOverwrite: false, previousEvent: mapstr.M{ "cloud.provider": "aws", @@ -228,27 +324,35 @@ func TestRetrieveAWSMetadataEC2(t *testing.T) { "image": mapstr.M{"id": imageIDDoc1}, "region": regionDoc1, "availability_zone": availabilityZoneDoc1, - "service": mapstr.M{ - "name": "EC2", - }, + "service": mapstr.M{"name": "EC2"}, }, }, }, } - for _, tc := range testCases { + for _, tc := range tests { t.Run(tc.testName, func(t *testing.T) { - server := createEC2MockAPI(tc.ec2ResponseMap) - defer server.Close() + + NewIMDSClient = func(cfg awssdk.Config) IMDSClient { + return &MockIMDSClient{ + GetInstanceIdentityDocumentFunc: tc.mockGetInstanceIdentity, + } + } + defer func() { NewIMDSClient = func(cfg awssdk.Config) IMDSClient { return imds.NewFromConfig(cfg) } }() + + NewEC2Client = func(cfg awssdk.Config) EC2Client { + return &MockEC2Client{ + DescribeTagsFunc: tc.mockEc2Tags, + } + } + defer func() { NewEC2Client = func(cfg awssdk.Config) EC2Client { return ec2.NewFromConfig(cfg) } }() config, err := conf.NewConfigFrom(map[string]interface{}{ - "host": server.Listener.Addr().String(), "overwrite": tc.processorOverwrite, }) if err != nil { t.Fatalf("error creating config from map: %s", err.Error()) } - cmp, err := New(config) if err != nil { t.Fatalf("error creating new metadata processor: %s", err.Error())