diff --git a/.buildkite/packaging.pipeline.yml b/.buildkite/packaging.pipeline.yml index ecf2dca5cc0f..ec85d9accd45 100644 --- a/.buildkite/packaging.pipeline.yml +++ b/.buildkite/packaging.pipeline.yml @@ -111,7 +111,6 @@ steps: - x-pack/auditbeat - x-pack/dockerlogbeat - x-pack/filebeat - - x-pack/functionbeat - x-pack/heartbeat - x-pack/metricbeat - x-pack/osquerybeat @@ -200,7 +199,6 @@ steps: - x-pack/auditbeat - x-pack/dockerlogbeat - x-pack/filebeat - - x-pack/functionbeat - x-pack/heartbeat - x-pack/metricbeat - x-pack/osquerybeat @@ -269,7 +267,7 @@ steps: - packaging-snapshot - dashboards-snapshot command: | - buildkite-agent artifact download "build/**/*" . + buildkite-agent artifact download "build/**/*" . .buildkite/scripts/packaging/prepare-release-manager.sh snapshot .buildkite/scripts/dra.sh agents: diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 8f060dc48cf3..1a8fd0a00882 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -26,9 +26,9 @@ CHANGELOG* /.github/CODEOWNERS @elastic/beats-tech-leads /auditbeat/ @elastic/sec-linux-platform /deploy/ @elastic/elastic-agent-data-plane -/deploy/kubernetes @elastic/elastic-agent-data-plane @elastic/obs-cloudnative-monitoring +/deploy/kubernetes @elastic/elastic-agent-data-plane @elastic/elastic-agent-control-plane /dev-tools/ @elastic/elastic-agent-data-plane -/dev-tools/kubernetes @elastic/obs-ds-hosted-services +/dev-tools/kubernetes @elastic/elastic-agent-data-plane @elastic/elastic-agent-control-plane /docs/ @elastic/elastic-agent-data-plane /filebeat @elastic/elastic-agent-data-plane /filebeat/docs/ # Listed without an owner to avoid maintaining doc ownership for each input and module. @@ -57,10 +57,11 @@ CHANGELOG* /heartbeat/ @elastic/obs-ds-hosted-services /journalbeat @elastic/elastic-agent-data-plane /libbeat/ @elastic/elastic-agent-data-plane +/libbeat/autodiscover/providers/kubernetes @elastic/elastic-agent-data-plane @elastic/elastic-agent-control-plane /libbeat/docs/processors-list.asciidoc @elastic/ingest-docs /libbeat/management @elastic/elastic-agent-control-plane -/libbeat/processors/add_cloud_metadata @elastic/obs-cloud-monitoring -/libbeat/processors/add_kubernetes_metadata @elastic/obs-cloudnative-monitoring +/libbeat/processors/add_cloud_metadata @elastic/obs-ds-hosted-services +/libbeat/processors/add_kubernetes_metadata @elastic/elastic-agent-data-plane /libbeat/processors/cache/ @elastic/security-service-integrations /libbeat/processors/community_id/ @elastic/sec-deployment-and-devices /libbeat/processors/decode_xml/ @elastic/security-service-integrations @@ -105,7 +106,6 @@ CHANGELOG* /metricbeat/module/system/ @elastic/elastic-agent-data-plane /metricbeat/module/vsphere @elastic/obs-infraobs-integrations /metricbeat/module/zookeeper @elastic/obs-infraobs-integrations -/metricbeat/tests @elastic/ingest-eng-prod /packetbeat/ @elastic/sec-linux-platform /script/ @elastic/elastic-agent-data-plane /testing/ @elastic/elastic-agent-data-plane @@ -116,10 +116,10 @@ CHANGELOG* /x-pack/filebeat @elastic/elastic-agent-data-plane /x-pack/filebeat/docs/ # Listed without an owner to avoid maintaining doc ownership for each input and module. /x-pack/filebeat/docs/inputs/input-salesforce.asciidoc @elastic/obs-infraobs-integrations -/x-pack/filebeat/input/awscloudwatch/ @elastic/obs-cloud-monitoring -/x-pack/filebeat/input/awss3/ @elastic/obs-cloud-monitoring +/x-pack/filebeat/input/awscloudwatch/ @elastic/obs-ds-hosted-services +/x-pack/filebeat/input/awss3/ @elastic/obs-ds-hosted-services /x-pack/filebeat/input/azureblobstorage/ @elastic/security-service-integrations -/x-pack/filebeat/input/azureeventhub/ @elastic/obs-cloud-monitoring +/x-pack/filebeat/input/azureeventhub/ @elastic/obs-ds-hosted-services /x-pack/filebeat/input/cel/ @elastic/security-service-integrations /x-pack/filebeat/input/cometd/ @elastic/obs-infraobs-integrations /x-pack/filebeat/input/entityanalytics/ @elastic/security-service-integrations @@ -137,9 +137,9 @@ CHANGELOG* /x-pack/filebeat/input/salesforce @elastic/obs-infraobs-integrations /x-pack/filebeat/input/streaming/ @elastic/security-service-integrations /x-pack/filebeat/module/activemq @elastic/obs-infraobs-integrations -/x-pack/filebeat/module/aws @elastic/obs-cloud-monitoring -/x-pack/filebeat/module/awsfargate @elastic/obs-cloud-monitoring -/x-pack/filebeat/module/azure @elastic/obs-cloud-monitoring +/x-pack/filebeat/module/aws @elastic/obs-ds-hosted-services +/x-pack/filebeat/module/awsfargate @elastic/obs-ds-hosted-services +/x-pack/filebeat/module/azure @elastic/obs-ds-hosted-services /x-pack/filebeat/module/barracuda @elastic/security-service-integrations /x-pack/filebeat/module/bluecoat @elastic/sec-deployment-and-devices /x-pack/filebeat/module/cef @elastic/sec-deployment-and-devices @@ -223,6 +223,7 @@ CHANGELOG* /x-pack/metricbeat/module/iis @elastic/obs-infraobs-integrations /x-pack/metricbeat/module/istio/ @elastic/obs-cloudnative-monitoring /x-pack/metricbeat/module/mssql @elastic/obs-infraobs-integrations +/x-pack/metricbeat/module/openai @elastic/obs-infraobs-integrations /x-pack/metricbeat/module/oracle @elastic/obs-infraobs-integrations /x-pack/metricbeat/module/panw @elastic/obs-infraobs-integrations /x-pack/metricbeat/module/prometheus/ @elastic/obs-cloudnative-monitoring diff --git a/.github/workflows/check-xpack-functionbeat.yml b/.github/workflows/check-xpack-functionbeat.yml deleted file mode 100644 index d51a18ea1a56..000000000000 --- a/.github/workflows/check-xpack-functionbeat.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: check-x-pack-functionbeat - -on: - pull_request: - paths: - - '.github/workflows/check-xpack-functionbeat.yml' - - 'x-pack/functionbeat/**' - - 'functionbeat/**' - -env: - BEAT_MODULE: 'x-pack/functionbeat' - -permissions: - contents: read - -jobs: - check: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 - with: - go-version-file: .go-version - - name: Run check/update - run: | - go install github.com/magefile/mage - make -C ${{ env.BEAT_MODULE }} check update - make check-no-changes diff --git a/.github/workflows/updatecli.d/bump-golang-7.17.yml b/.github/workflows/updatecli.d/bump-golang-7.17.yml index 34a60b31c4d4..8c1ba9b42055 100644 --- a/.github/workflows/updatecli.d/bump-golang-7.17.yml +++ b/.github/workflows/updatecli.d/bump-golang-7.17.yml @@ -157,16 +157,6 @@ targets: keyword: "FROM" matcher: "golang" file: ./packetbeat/Dockerfile - update-functionbeat-dockerfile: - name: "Update Functionbeat Dockerfile" - sourceid: latestGoVersion - scmid: githubConfig - kind: dockerfile - spec: - instruction: - keyword: "FROM" - matcher: "golang" - file: ./x-pack/functionbeat/Dockerfile update-nats-module-dockerfile: name: "Update NATS module Dockerfile" sourceid: latestGoVersion diff --git a/.github/workflows/updatecli.d/bump-golang.yml b/.github/workflows/updatecli.d/bump-golang.yml index f03c5471e631..70c831b68baf 100644 --- a/.github/workflows/updatecli.d/bump-golang.yml +++ b/.github/workflows/updatecli.d/bump-golang.yml @@ -166,16 +166,6 @@ targets: keyword: "FROM" matcher: "golang" file: ./packetbeat/Dockerfile - update-functionbeat-dockerfile: - name: "Update Functionbeat Dockerfile" - sourceid: latestGoVersion - scmid: githubConfig - kind: dockerfile - spec: - instruction: - keyword: "FROM" - matcher: "golang" - file: ./x-pack/functionbeat/Dockerfile update-nats-module-dockerfile: name: "Update NATS module Dockerfile" sourceid: latestGoVersion diff --git a/.gitignore b/.gitignore index 70941e281497..b3c2bdc0d986 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ *beat/logs *beat/data **/ironbank/build/ -x-pack/functionbeat/pkg # Files .DS_Store @@ -24,8 +23,6 @@ beat.db *.keystore go_env.properties mage_output_file.go -x-pack/functionbeat/*/fields.yml -x-pack/functionbeat/provider/*/functionbeat-* x-pack/dockerlogbeat/temproot.tar # Editor swap files diff --git a/.mergify.yml b/.mergify.yml index f44b0439484b..ac8644c7ba1a 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -381,3 +381,16 @@ pull_request_rules: labels: - "backport" title: "[{{ destination_branch }}](backport #{{ number }}) {{ title }}" + - name: backport patches to 8.17 branch + conditions: + - merged + - label=backport-8.17 + actions: + backport: + assignees: + - "{{ author }}" + branches: + - "8.17" + labels: + - "backport" + title: "[{{ destination_branch }}](backport #{{ number }}) {{ title }}" diff --git a/CHANGELOG-developer.next.asciidoc b/CHANGELOG-developer.next.asciidoc index 0998beb9f7d6..15b46777965f 100644 --- a/CHANGELOG-developer.next.asciidoc +++ b/CHANGELOG-developer.next.asciidoc @@ -213,6 +213,7 @@ The list below covers the major changes between 7.0.0-rc2 and main only. - Add field redaction package. {pull}40997[40997] - Add support for marked redaction to x-pack/filebeat/input/internal/private {pull}41212[41212] - Add support for collecting Okta role and factor data for users with filebeat entityanalytics input. {pull}41044[41044] +- Add CEL input program evaluation coverage collection support. {pull}41884[41884] ==== Deprecated diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 6cffeb658f76..7af434990cfb 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -3,6 +3,153 @@ :issue: https://github.com/elastic/beats/issues/ :pull: https://github.com/elastic/beats/pull/ +[[release-notes-8.16.1]] +=== Beats version 8.16.1 +https://github.com/elastic/beats/compare/v8.16.0\...v8.16.1[View commits] + +==== Breaking changes + +*Packetbeat* + +- Expire source port mappings. {pull}41581[41581] + +==== Bugfixes + +*Filebeat* + +- Fix AWS region in aws-s3 input S3 polling mode. {pull}41572[41572] + + +[[release-notes-8.16.0]] +=== Beats version 8.16.0 +https://github.com/elastic/beats/compare/v8.15.4\...v8.16.0[View commits] + +==== Known issues + +*Filebeat* + +- The AWS S3 input polling mode is not working when the S3 bucket is not in the `us-east-1` default region. This also impacts all AWS integrations and any custom AWS log integration which uses the `aws-s3` input polling mode. When using Filebeat, please add a `default_region` configuration with the region of the S3 bucket. For example: ++ +["source","yaml"] +---- +filebeat.inputs: +- type: aws-s3 + enabled: true + credential_profile_name: elastic-observability + default_region: us-east-2 + number_of_workers: 5 + bucket_arn: 'arn:aws:s3:::test1' +---- + +==== Breaking changes + +*Affecting all Beats* + +- Fix FQDN being lowercased when used as `host.hostname`. {issue}39993[39993] +- Beats won't log start up information when running under the Elastic Agent. {pull}40390[40390] +- Filebeat now needs `dup3`, `faccessat2`, `prctl` and `setrlimit` syscalls to run the journald input. If this input is not being used, the syscalls are not needed. All Beats have those syscalls allowed now because the default seccomp policy is global to all Beats. {pull}40061[40061] +- Beats will rate limit the logs about errors when indexing events on Elasticsearch, logging a summary every 10s. The logs sent to the event log is unchanged. {issue}40157[40157] + +*Filebeat* + +- Filebeat, when running with Elastic-Agent, reports status for Filestream input. {pull}40121[40121] +- Added support for hyphens in extension keys in `decode_cef` Filebeat processor. {pull}40427[40427] +- Journald: removed configuration options `include_matches.or`, `include_matches.and`, `backoff`, `max_backoff`, `cursor_seek_fallback`. {pull}40061[40061] +- Journald: `include_matches.match` now behaves in the same way as matchers in `journalctl`. Users should carefully update their input configuration. {pull}40061[40061] +- Journald: `seek` and `since` behaviour have been simplified, if there is a cursor (state) `seek` and `since` are ignored and the cursor is used. {pull}40061[40061] +- Redis: Added replication role as a field to submitted slowlogs. +- Added `container.image.name` to `journald` Filebeat input's Docker-specific translated fields. {pull}40450[40450] +- Remove deprecated awscloudwatch field from Filebeat. {pull}41089[41089] +- The performance of ingesting SQS data with the S3 input has improved by up to 60x for queues with many small events. `max_number_of_messages` config for SQS mode is now ignored, as the new design no longer needs a manual cap on messages. Instead, use `number_of_workers` to scale ingestion rate in both S3 and SQS modes. The increased efficiency may increase network bandwidth consumption, which can be throttled by lowering `number_of_workers`. It may also increase number of events stored in memory, which can be throttled by lowering the configured size of the internal queue. {pull}40699[40699] + +*Metricbeat* + +- Add support for specifying a custom endpoint for GCP service clients. {issue}40848[40848] {pull}40918[40918] + +==== Bugfixes + +*Auditbeat* + +- Request status from a separate socket to avoid data congestion. {pull}41207[41207] + +*Filebeat* + +- Fix crashes in the journald input. {pull}40061[40061] +- Fix long filepaths in diagnostics exceeding max path limits on Windows. {pull}40909[40909] +- Fix a bug in Salesforce input to only handle responses with 200 status code. {pull}41015[41015] +- Fixed failed job handling and removed false-positive error logs in the GCS input. {pull}41142[41142] +- Bump github.com/elastic/go-sfdc dependency used by x-pack/filebeat/input/salesforce. {pull}41192[41192] +- Journald input now can read events from all boots {issue}41083[41083] {pull}41244[41244] +- Fix errors in SQS host resolution in the `aws-s3` input when using custom (non-AWS) endpoints. {pull}41504[41504] + +*Metricbeat* + +- Add GCP 'instance_id' resource label in ECS cloud fields. {issue}40033[40033] {pull}40062[40062] +- Remove excessive info-level logs in cgroups setup. {pull}40491[40491] +- Fix http server helper SSL config. {pull}39405[39405] + +==== Added + +*Filebeat* + +- Implement Elastic Agent status and health reporting for Netflow Filebeat input. {pull}40080[40080] +- Add SSL and username support for Redis input, now the input includes support for Redis 6.0+. {pull}40111[40111] +- Add scaling up support for Netflow input. {issue}37761[37761] {pull}40122[40122] +- Update CEL mito extensions to v1.15.0. {pull}40294[40294] +- Improve logging in Okta Entity Analytics provider. {issue}40106[40106] {pull}40347[40347] +- Document `winlog` input. {issue}40074[40074] {pull}40462[40462] +- Added retry logic to websocket connections in the streaming input. {issue}40271[40271] {pull}40601[40601] +- Disable event normalization for netflow input. {pull}40635[40635] +- Allow attribute selection in the Active Directory entity analytics provider. {issue}40482[40482] {pull}40662[40662] +- Improve error quality when CEL program does not correctly return an events array. {pull}40580[40580] +- Added support for Microsoft Entra ID RBAC authentication. {issue}40434[40434] {pull}40879[40879] +- Add `use_kubeadm` config option for filebeat (both filbeat.input and autodiscovery) in order to toggle kubeadm-config api requests. {pull}40301[40301] +- Make HTTP library function inclusion non-conditional in CEL input. {pull}40912[40912] +- Add support for Crowdstrike streaming API to the streaming input. {issue}40264[40264] {pull}40838[40838] +- Add support to CEL for reading host environment variables. {issue}40762[40762] {pull}40779[40779] +- Add CSV decoder to awss3 input. {pull}40896[40896] +- Change request trace logging to include headers instead of complete request. {pull}41072[41072] +- Improved GCS input documentation. {pull}41143[41143] +- Add CSV decoding capacity to azureblobstorage input. {pull}40978[40978] +- Add CSV decoding capacity to gcs input. {pull}40979[40979] +- Add support to source AWS cloudwatch logs from linked accounts. {pull}41188[41188] +- Jounrald input now supports filtering by facilities. {pull}41061[41061] +- Add support to include AWS cloudwatch linked accounts when using log_group_name_prefix to define log group names. {pull}41206[41206] + +*Heartbeat* + +- Add journey duration to synthetics browser events. {pull}40230[40230] + +*Metricbeat* + +- Add new metrics fot datastore and minor changes to overall vSphere metrics. {pull}40766[40766] +- Add new metricset datastorecluster for vSphere module. {pull}40634[40634] {pull}40694[40694] +- Add AWS Cloudwatch capability to retrieve tags from AWS/ApiGateway resources. {pull}40755[40755] +- Add new metrics for the vSphere Virtualmachine metricset. {pull}40485[40485] +- Add `metrics_count` to Prometheus module if `metrics_count: true` is set. {pull}40411[40411] + + +[[release-notes-8.15.5]] +=== Beats version 8.15.5 +https://github.com/elastic/beats/compare/v8.15.4\...v8.15.5[View commits] + +==== Breaking changes + +*Packetbeat* + +- Expire source port mappings. {pull}41581[41581] + +==== Bugfixes + +*Affecting all Beats* + +- Fix metrics not being ingested, due to "Limit of total fields [10000] has been exceeded while adding new fields [...]". The total fields limit has been increased to 12500. No significant performance impact on Elasticsearch is anticipated. {pull}41640[41640] + +*Filebeat* + +- Fix AWS region in `aws-s3` input S3 polling mode. {pull}41572[41572] + + [[release-notes-8.15.4]] === Beats version 8.15.4 https://github.com/elastic/beats/compare/v8.15.3\...v8.15.4[View commits] @@ -192,6 +339,18 @@ https://github.com/elastic/beats/compare/v8.14.3\...v8.15.0[View commits] - The Azure EventHub input in Filebeat is not found when running on Windows. Please refrain from upgrading to 8.15. See {issue}40608[40608] for details. - Memory usage is not correctly limited by the number of events actively in the memory queue, but rather the maximum size of the memory queue regardless of usage. {issue}41355[41355] +- The AWS S3 input polling mode is not working when the S3 bucket is not in the `us-east-1` default region. This also impacts all AWS integrations and any custom AWS log integration which uses the `aws-s3` input polling mode. When using Filebeat, please add a `default_region` configuration with the region of the S3 bucket. For example: ++ +["source","yaml"] +---- +filebeat.inputs: +- type: aws-s3 + enabled: true + credential_profile_name: elastic-observability + default_region: us-east-2 + number_of_workers: 5 + bucket_arn: 'arn:aws:s3:::test1' +---- ==== Breaking changes @@ -282,6 +441,11 @@ https://github.com/elastic/beats/compare/v8.14.3\...v8.15.0[View commits] === Beats version 8.14.3 https://github.com/elastic/beats/compare/v8.14.2\...v8.14.3[View commits] +==== Known Issues + +*Filebeat* + - Filestream input will resend files that have been inactive for 30min or more. Workaround: set `clean_inactive` to a very high value, like 5 years: `clean_inactive: 43800h0m0s`. {issue}40178[40178] + ==== Bugfixes *Filebeat* @@ -312,6 +476,11 @@ https://github.com/elastic/beats/compare/v8.14.2\...v8.14.3[View commits] === Beats version 8.14.2 https://github.com/elastic/beats/compare/v8.14.1\...v8.14.2[View commits] +==== Known Issues + +*Filebeat* + - Filestream input will resend files that have been inactive for 30min or more. Workaround: set `clean_inactive` to a very high value, like 5 years: `clean_inactive: 43800h0m0s`. {issue}40178[40178] + ==== Breaking changes *Filebeat* @@ -348,6 +517,11 @@ https://github.com/elastic/beats/compare/v8.14.1\...v8.14.2[View commits] === Beats version 8.14.1 https://github.com/elastic/beats/compare/v8.14.0\...v8.14.1[View commits] +==== Known Issues + +*Filebeat* + - Filestream input will resend files that have been inactive for 30min or more. Workaround: set `clean_inactive` to a very high value, like 5 years: `clean_inactive: 43800h0m0s`. {issue}40178[40178] + ==== Bugfixes *Heartbeat* @@ -359,6 +533,11 @@ https://github.com/elastic/beats/compare/v8.14.0\...v8.14.1[View commits] === Beats version 8.14.0 https://github.com/elastic/beats/compare/v8.13.4\...v8.14.0[View commits] +==== Known Issues + +*Filebeat* + - Filestream input will resend files that have been inactive for 30min or more. Workaround: set `clean_inactive` to a very high value, like 5 years: `clean_inactive: 43800h0m0s`. {issue}40178[40178] + ==== Breaking changes *Filebeat* @@ -2752,6 +2931,7 @@ https://github.com/elastic/beats/compare/v7.17.0\...v8.0.0[View commits] - Add `while_pattern` type to multiline reader. {pull}19662[19662] - auditd dataset: Use `process.args` to store program arguments instead of `auditd.log.aNNN` fields. {pull}29601[29601] - Remove deprecated old `awscloudwatch` input name. {pull}29844[29844] +- Remove `docker` input. Please use `filestream` input with `container` parser or `container` input. {pull}28817[28817] *Metricbeat* diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index d0631f156b0f..f0964ce15452 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -16,6 +16,7 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] - Beats will rate limit the logs about errors when indexing events on Elasticsearch, logging a summary every 10s. The logs sent to the event log is unchanged. {issue}40157[40157] - Drop support for Debian 10 and upgrade statically linked glibc from 2.28 to 2.31 {pull}41402[41402] - Fix metrics not being ingested, due to "Limit of total fields [10000] has been exceeded while adding new fields [...]". The total fields limit has been increased to 12500. No significant performance impact on Elasticsearch is anticipated. {pull}41640[41640] +- Set default kafka version to 2.1.0 in kafka output and filebeat. {pull}41662[41662] *Auditbeat* @@ -37,7 +38,6 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] - Fix high IO and handling of a corrupted registry log file. {pull}35893[35893] - Enable file ingestion to report detailed status to Elastic Agent {pull}40075[40075] - Filebeat, when running with Elastic-Agent, reports status for Filestream input. {pull}40121[40121] -- Implement Elastic Agent status and health reporting for Winlog Filebeat input. {pull}40163[40163] - Fix filestream's registry GC: registry entries will never be removed if clean_inactive is set to "-1". {pull}40258[40258] - Added `ignore_empty_values` flag in `decode_cef` Filebeat processor. {pull}40268[40268] - Added support for hyphens in extension keys in `decode_cef` Filebeat processor. {pull}40427[40427] @@ -50,8 +50,8 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] - Remove deprecated awscloudwatch field from Filebeat. {pull}41089[41089] - The performance of ingesting SQS data with the S3 input has improved by up to 60x for queues with many small events. `max_number_of_messages` config for SQS mode is now ignored, as the new design no longer needs a manual cap on messages. Instead, use `number_of_workers` to scale ingestion rate in both S3 and SQS modes. The increased efficiency may increase network bandwidth consumption, which can be throttled by lowering `number_of_workers`. It may also increase number of events stored in memory, which can be throttled by lowering the configured size of the internal queue. {pull}40699[40699] - Fixes filestream logging the error "filestream input with ID 'ID' already exists, this will lead to data duplication[...]" on Kubernetes when using autodiscover. {pull}41585[41585] - - Add kafka compression support for ZSTD. +- Filebeat fails to start if there is any input with a duplicated ID. It logs the duplicated IDs and the offending inputs configurations. {pull}41731[41731] *Heartbeat* @@ -59,14 +59,13 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] *Metricbeat* - Setting period for counter cache for Prometheus remote_write at least to 60sec {pull}38553[38553] -- Add support of Graphite series 1.1.0+ tagging extension for statsd module. {pull}39619[39619] -- Allow metricsets to report their status via control v2 protocol. {pull}40025[40025] - Remove fallback to the node limit for the `kubernetes.pod.cpu.usage.limit.pct` and `kubernetes.pod.memory.usage.limit.pct` metrics calculation - Add support for Kibana status metricset in v8 format {pull}40275[40275] - Mark system process metricsets as running if metrics are partially available {pull}40565[40565] - Added back `elasticsearch.node.stats.jvm.mem.pools.*` to the `node_stats` metricset {pull}40571[40571] - Add GCP organization and project details to ECS cloud fields. {pull}40461[40461] - Add support for specifying a custom endpoint for GCP service clients. {issue}40848[40848] {pull}40918[40918] +- Fix incorrect handling of types in SQL module. {issue}40090[40090] {pull}41607[41607] *Osquerybeat* @@ -80,6 +79,8 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] *Packetbeat* +- Use base-16 for reporting `serial_number` value in TLS fields in line with the ECS recommendation. {pull}41542[41542] + - Expire source port mappings. {pull}41581[41581] *Winlogbeat* @@ -114,10 +115,20 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] - Ensure Elasticsearch output can always recover from network errors {pull}40794[40794] - Add `translate_ldap_attribute` processor. {pull}41472[41472] - Remove unnecessary debug logs during idle connection teardown {issue}40824[40824] +- Remove unnecessary reload for Elastic Agent managed beats when apm tracing config changes from nil to nil {pull}41794[41794] +- Fix incorrect cloud provider identification in add_cloud_metadata processor using provider priority mechanism {pull}41636[41636] +- Prevent panic if libbeat processors are loaded more than once. {issue}41475[41475] {pull}41857[51857] +- Allow network condition to handle field values that are arrays of IP addresses. {pull}41918[41918] +- Fix a bug where log files are rotated on startup when interval is configured and rotateonstartup is disabled {issue}41894[41894] {pull}41895[41895] *Auditbeat* -- Request status from a separate socket to avoid data congestion {pull}41207[41207] +- auditd: Request status from a separate socket to avoid data congestion {pull}41207[41207] +- auditd: Use ECS `event.type: end` instead of `stop` for SERVICE_STOP, DAEMON_ABORT, and DAEMON_END messages. {pull}41558[41558] +- auditd: Update syscall names for Linux 6.11. {pull}41558[41558] +- hasher: Geneneral improvements and fixes. {pull}41863[41863] +- hasher: Add a cached hasher for upcoming backend. {pull}41952[41952] +- Split common tty definitions. {pull}42004[42004] *Filebeat* @@ -145,10 +156,7 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] - Updated Websocket input title to align with existing inputs {pull}39006[39006] - Restore netflow input on Windows {pull}39024[39024] - Upgrade azure-event-hubs-go and azure-storage-blob-go dependencies. {pull}38861[38861] -- Fix concurrency/error handling bugs in the AWS S3 input that could drop data and prevent ingestion of large buckets. {pull}39131[39131] -- Fix EntraID query handling. {issue}39419[39419] {pull}39420[39420] - Fix request trace filename handling in http_endpoint input. {pull}39410[39410] -- Fix filestream not correctly tracking the offset of a file when using the `include_message` parser. {pull}39873[39873] {issue}39653[39653] - Upgrade github.com/hashicorp/go-retryablehttp to mitigate CVE-2024-6104 {pull}40036[40036] - Fix for Google Workspace duplicate events issue by adding canonical sorting over fingerprint keys array to maintain key order. {pull}40055[40055] {issue}39859[39859] - Fix handling of deeply nested numeric values in HTTP Endpoint CEL programs. {pull}40115[40115] @@ -177,7 +185,16 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] - Fix double encoding of client_secret in the Entity Analytics input's Azure Active Directory provider {pull}41393[41393] - Fix aws region in aws-s3 input s3 polling mode. {pull}41572[41572] - Fix errors in SQS host resolution in the `aws-s3` input when using custom (non-AWS) endpoints. {pull}41504[41504] +- Fix double encoding of client_secret in the Entity Analytics input's Azure Active Directory provider {pull}41393[41393] - The azure-eventhub input now correctly reports its status to the Elastic Agent on fatal errors {pull}41469[41469] +- Add support for Access Points in the `aws-s3` input. {pull}41495[41495] +- Fix the "No such input type exist: 'salesforce'" error on the Windows/AIX platform. {pull}41664[41664] +- Fix missing key in streaming input logging. {pull}41600[41600] +- Improve S3 object size metric calculation to support situations where Content-Length is not available. {pull}41755[41755] +- Fix handling of http_endpoint request exceeding memory limits. {issue}41764[41764] {pull}41765[41765] +- Rate limiting fixes in the Okta provider of the Entity Analytics input. {issue}40106[40106] {pull}41583[41583] +- Redact authorization headers in HTTPJSON debug logs. {pull}41920[41920] +- Further rate limiting fix in the Okta provider of the Entity Analytics input. {issue}40106[40106] {pull}41977[41977] *Heartbeat* @@ -193,8 +210,6 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] - Fix handling of access errors when reading process metrics {pull}39627[39627] - Fix behavior of cgroups path discovery when monitoring the host system from within a container {pull}39627[39627] - Fix issue where beats may report incorrect metrics for its own process when running inside a container {pull}39627[39627] -- Fix for MySQL/Performance - Query failure for MySQL versions below v8.0.1, for performance metric `quantile_95`. {pull}38710[38710] -- Fix Prometheus helper text parser to store each metric family type. {pull}39743[39743] - Normalize AWS RDS CPU Utilization values before making the metadata API call. {pull}39664[39664] - Fix behavior of pagetypeinfo metrics {pull}39985[39985] - Fix query logic for temp and non-temp tablespaces in Oracle module. {issue}38051[38051] {pull}39787[39787] @@ -212,6 +227,7 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] - Fix Kubernetes metadata sometimes not being present after startup {pull}41216[41216] - Do not report non-existant 0 values for RSS metrics in docker/memory {pull}41449[41449] - Log Cisco Meraki `getDevicePerformanceScores` errors without stopping metrics collection. {pull}41622[41622] +- Don't skip first bucket value in GCP metrics metricset for distribution type metrics {pull}41822[41822] *Osquerybeat* @@ -222,6 +238,8 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] *Winlogbeat* +- Fix message handling in the experimental api. {issue}19338[19338] {pull}41730[41730] + *Elastic Logging Plugin* @@ -246,6 +264,7 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] - Reduce memory consumption of k8s autodiscovery and the add_kubernetes_metadata processor when Deployment metadata is enabled - Add `lowercase` processor. {issue}22254[22254] {pull}41424[41424] - Add `uppercase` processor. {issue}22254[22254] {pull}41535[41535] +- Replace `compress/gzip` with https://github.com/klauspost/compress/gzip library for gzip compression {pull}41584[41584] *Auditbeat* @@ -253,9 +272,13 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] - Add linux capabilities to processes in the system/process. {pull}37453[37453] - Add linux capabilities to processes in the system/process. {pull}37453[37453] - Add process.entity_id, process.group.name and process.group.id in add_process_metadata processor. Make fim module with kprobes backend to always add an appropriately configured add_process_metadata processor to enrich file events {pull}38776[38776] +- Split module/system/process into common and provider bits. {pull}41868[41868] *Auditbeat* +- Improve logging in system/socket {pull}41571[41571] + + *Auditbeat* @@ -287,14 +310,7 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] - Parse more fields from Elasticsearch slowlogs {pull}38295[38295] - added benchmark input {pull}37437[37437] - added benchmark input and discard output {pull}37437[37437] -- Ensure all responses sent by HTTP Endpoint are HTML-escaped. {pull}39329[39329] - Update CEL mito extensions to v1.11.0 to improve type checking. {pull}39460[39460] -- Improve logging of request and response with request trace logging in error conditions. {pull}39455[39455] -- Implement Elastic Agent status and health reporting for CEL Filebeat input. {pull}39209[39209] -- Add HTTP metrics to CEL input. {issue}39501[39501] {pull}39503[39503] -- Add default user-agent to CEL HTTP requests. {issue}39502[39502] {pull}39587[39587] -- Improve reindexing support in security module pipelines. {issue}38224[38224] {pull}39588[39588] -- Make HTTP Endpoint input GA. {issue}38979[38979] {pull}39410[39410] - Update CEL mito extensions to v1.12.2. {pull}39755[39755] - Add support for base64-encoded HMAC headers to HTTP Endpoint. {pull}39655[39655] - Add user group membership support to Okta entity analytics provider. {issue}39814[39814] {pull}39815[39815] @@ -337,7 +353,22 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] - Add support to include AWS cloudwatch linked accounts when using log_group_name_prefix to define log group names. {pull}41206[41206] - Improved Azure Blob Storage input documentation. {pull}41252[41252] - Make ETW input GA. {pull}41389[41389] +- Added input metrics to GCS input. {issue}36640[36640] {pull}41505[41505] - Add support for Okta entity analytics provider to collect role and factor data for users. {pull}41460[41460] +- Add support for Journald in the System module. {pull}41555[41555] +- Add ability to remove request trace logs from http_endpoint input. {pull}40005[40005] +- Add ability to remove request trace logs from entityanalytics input. {pull}40004[40004] +- Refactor & cleanup with updates to default values and documentation. {pull}41834[41834] +- Update CEL mito extensions to v1.16.0. {pull}41727[41727] +- Add `unifiedlogs` input for MacOS. {pull}41791[41791] +- Add evaluation state dump debugging option to CEL input. {pull}41335[41335] +- Added support for retry configuration in GCS input. {issue}11580[11580] {pull}41862[41862] +- Improve S3 polling mode states registry when using list prefix option. {pull}41869[41869] +- Add support for SSL and Proxy configurations for websoket type in streaming input. {pull}41934[41934] +- AWS S3 input registry cleanup for untracked s3 objects. {pull}41694[41694] +- The environment variable `BEATS_AZURE_EVENTHUB_INPUT_TRACING_ENABLED: true` enables internal logs tracer for the azure-eventhub input. {issue}41931[41931] {pull}41932[41932] +- Rate limiting operability improvements in the Okta provider of the Entity Analytics input. {issue}40106[40106] {pull}41977[41977] +- Added default values in the streaming input for websocket retries and put a cap on retry wait time to be lesser than equal to the maximum defined wait time. {pull}42012[42012] *Auditbeat* @@ -351,8 +382,6 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] - Added status to monitor run log report. - Upgrade node to latest LTS v18.20.3. {pull}40038[40038] -- Add journey duration to synthetics browser events. {pull}40230[40230] -- Add monitor status reporter under managed mode. {pull}41077[41077] *Metricbeat* @@ -390,8 +419,12 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] - Bump aerospike-client-go to version v7.7.1 and add support for basic auth in Aerospike module {pull}41233[41233] - Only watch metadata for ReplicaSets in metricbeat k8s module {pull}41289[41289] - Add support for region/zone for Vertex AI service in GCP module {pull}41551[41551] +- Add support for location label as an optional configuration parameter in GCP metrics metricset. {issue}41550[41550] {pull}41626[41626] +- Added `tier_preference`, `creation_date` and `version` fields to the `elasticsearch.index` metricset. {pull}41944[41944] +- Add `use_performance_counters` to collect CPU metrics using performance counters on Windows for `system/cpu` and `system/core` {pull}41965[41965] *Metricbeat* +- Add benchmark module {pull}41801[41801] *Osquerybeat* @@ -403,11 +436,20 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] *Winlogbeat* - Add handling for missing `EvtVarType`s in experimental api. {issue}19337[19337] {pull}41418[41418] +- Properly set events `UserData` when experimental api is used. {pull}41525[41525] +- Include XML is respected for experimental api {pull}41525[41525] +- Forwarded events use renderedtext info for experimental api {pull}41525[41525] +- Language setting is respected for experimental api {pull}41525[41525] +- Language setting also added to decode xml wineventlog processor {pull}41525[41525] +- Format embedded messages in the experimental api {pull}41525[41525] - Implement exclusion range support for event_id. {issue}38623[38623] {pull}41639[41639] +- Make the experimental API GA and rename it to winlogbeat-raw {issue}39580[39580] {pull}41770[41770] *Functionbeat* +- Removal of functionbeat binaries from CI pipelines {issue}40745[40745] {pull}41506[41506] + *Elastic Log Driver* *Elastic Logging Plugin* @@ -419,6 +461,7 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] *Filebeat* +- Removed `bucket_timeout` config option for GCS input and replaced bucket context with parent program context. {issue}41107[41107] {pull}41970[41970] *Heartbeat* @@ -455,3 +498,9 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] + + + + + + diff --git a/Makefile b/Makefile index b9be661dc25a..2980974dc047 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ BUILD_DIR=$(CURDIR)/build COVERAGE_DIR=$(BUILD_DIR)/coverage -BEATS?=auditbeat filebeat heartbeat metricbeat packetbeat winlogbeat x-pack/agentbeat x-pack/auditbeat x-pack/dockerlogbeat x-pack/filebeat x-pack/functionbeat x-pack/heartbeat x-pack/metricbeat x-pack/osquerybeat x-pack/packetbeat x-pack/winlogbeat +BEATS?=auditbeat filebeat heartbeat metricbeat packetbeat winlogbeat x-pack/agentbeat x-pack/auditbeat x-pack/dockerlogbeat x-pack/filebeat x-pack/heartbeat x-pack/metricbeat x-pack/osquerybeat x-pack/packetbeat x-pack/winlogbeat PROJECTS=libbeat x-pack/libbeat $(BEATS) PROJECTS_ENV=libbeat filebeat metricbeat PYTHON_ENV?=$(BUILD_DIR)/python-env diff --git a/NOTICE.txt b/NOTICE.txt index 415b57dfe689..ae812a0cbccd 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1711,11 +1711,11 @@ Contents of probable licence file $GOMODCACHE/github.com/!azure/azure-event-hubs -------------------------------------------------------------------------------- Dependency : github.com/Azure/azure-sdk-for-go -Version: v65.0.0+incompatible +Version: v68.0.0+incompatible Licence type (autodetected): MIT -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/!azure/azure-sdk-for-go@v65.0.0+incompatible/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/!azure/azure-sdk-for-go@v68.0.0+incompatible/LICENSE.txt: The MIT License (MIT) @@ -2745,36 +2745,6 @@ OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --------------------------------------------------------------------------------- -Dependency : github.com/elastic/sarama -Version: v1.19.1-0.20220310193331-ebc2b0d8eef3 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/elastic/sarama@v1.19.1-0.20220310193331-ebc2b0d8eef3/LICENSE: - -Copyright (c) 2013 Shopify - -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/StackExchange/wmi Version: v1.2.1 @@ -3018,12 +2988,12 @@ Contents of probable licence file $GOMODCACHE/github.com/aerospike/aerospike-cli -------------------------------------------------------------------------------- -Dependency : github.com/apache/arrow/go/v14 -Version: v14.0.2 +Dependency : github.com/apache/arrow/go/v17 +Version: v17.0.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/apache/arrow/go/v14@v14.0.2/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/apache/arrow/go/v17@v17.0.0/LICENSE.txt: Apache License @@ -4848,219 +4818,6 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------------------------------- -Dependency : github.com/aws/aws-lambda-go -Version: v1.44.0 -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/aws/aws-lambda-go@v1.44.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 : github.com/aws/aws-sdk-go-v2 Version: v1.30.5 @@ -6546,12 +6303,12 @@ Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/servi -------------------------------------------------------------------------------- -Dependency : github.com/aws/aws-sdk-go-v2/service/cloudformation -Version: v1.53.5 +Dependency : github.com/aws/aws-sdk-go-v2/service/cloudwatch +Version: v1.40.5 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/cloudformation@v1.53.5/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/cloudwatch@v1.40.5/LICENSE.txt: Apache License @@ -6758,12 +6515,12 @@ Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/servi -------------------------------------------------------------------------------- -Dependency : github.com/aws/aws-sdk-go-v2/service/cloudwatch -Version: v1.40.5 +Dependency : github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs +Version: v1.37.5 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/cloudwatch@v1.40.5/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs@v1.37.5/LICENSE.txt: Apache License @@ -6970,12 +6727,12 @@ Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/servi -------------------------------------------------------------------------------- -Dependency : github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs -Version: v1.37.5 +Dependency : github.com/aws/aws-sdk-go-v2/service/costexplorer +Version: v1.40.4 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs@v1.37.5/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/costexplorer@v1.40.4/LICENSE.txt: Apache License @@ -7182,12 +6939,12 @@ Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/servi -------------------------------------------------------------------------------- -Dependency : github.com/aws/aws-sdk-go-v2/service/costexplorer -Version: v1.40.4 +Dependency : github.com/aws/aws-sdk-go-v2/service/ec2 +Version: v1.176.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/costexplorer@v1.40.4/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/ec2@v1.176.0/LICENSE.txt: Apache License @@ -7394,12 +7151,12 @@ Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/servi -------------------------------------------------------------------------------- -Dependency : github.com/aws/aws-sdk-go-v2/service/ec2 -Version: v1.176.0 +Dependency : github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 +Version: v1.34.2 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/ec2@v1.176.0/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2@v1.34.2/LICENSE.txt: Apache License @@ -7606,12 +7363,12 @@ Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/servi -------------------------------------------------------------------------------- -Dependency : github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 -Version: v1.34.2 +Dependency : github.com/aws/aws-sdk-go-v2/service/health +Version: v1.26.4 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2@v1.34.2/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/health@v1.26.4/LICENSE.txt: Apache License @@ -7818,12 +7575,12 @@ Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/servi -------------------------------------------------------------------------------- -Dependency : github.com/aws/aws-sdk-go-v2/service/health -Version: v1.26.4 +Dependency : github.com/aws/aws-sdk-go-v2/service/iam +Version: v1.35.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/health@v1.26.4/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/iam@v1.35.0/LICENSE.txt: Apache License @@ -8030,12 +7787,12 @@ Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/servi -------------------------------------------------------------------------------- -Dependency : github.com/aws/aws-sdk-go-v2/service/iam -Version: v1.35.0 +Dependency : github.com/aws/aws-sdk-go-v2/service/organizations +Version: v1.30.3 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/iam@v1.35.0/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/organizations@v1.30.3/LICENSE.txt: Apache License @@ -8242,12 +7999,12 @@ Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/servi -------------------------------------------------------------------------------- -Dependency : github.com/aws/aws-sdk-go-v2/service/kinesis -Version: v1.29.5 +Dependency : github.com/aws/aws-sdk-go-v2/service/rds +Version: v1.82.2 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/kinesis@v1.29.5/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/rds@v1.82.2/LICENSE.txt: Apache License @@ -8454,12 +8211,12 @@ Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/servi -------------------------------------------------------------------------------- -Dependency : github.com/aws/aws-sdk-go-v2/service/organizations -Version: v1.30.3 +Dependency : github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi +Version: v1.23.5 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/organizations@v1.30.3/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi@v1.23.5/LICENSE.txt: Apache License @@ -8666,12 +8423,12 @@ Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/servi -------------------------------------------------------------------------------- -Dependency : github.com/aws/aws-sdk-go-v2/service/rds -Version: v1.82.2 +Dependency : github.com/aws/aws-sdk-go-v2/service/s3 +Version: v1.60.1 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/rds@v1.82.2/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/s3@v1.60.1/LICENSE.txt: Apache License @@ -8878,12 +8635,12 @@ Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/servi -------------------------------------------------------------------------------- -Dependency : github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi -Version: v1.23.5 +Dependency : github.com/aws/aws-sdk-go-v2/service/sqs +Version: v1.34.5 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi@v1.23.5/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/sqs@v1.34.5/LICENSE.txt: Apache License @@ -9090,12 +8847,12 @@ Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/servi -------------------------------------------------------------------------------- -Dependency : github.com/aws/aws-sdk-go-v2/service/s3 -Version: v1.60.1 +Dependency : github.com/aws/aws-sdk-go-v2/service/sts +Version: v1.30.5 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/s3@v1.60.1/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/sts@v1.30.5/LICENSE.txt: Apache License @@ -9302,12 +9059,12 @@ Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/servi -------------------------------------------------------------------------------- -Dependency : github.com/aws/aws-sdk-go-v2/service/sqs -Version: v1.34.5 +Dependency : github.com/aws/smithy-go +Version: v1.20.4 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/sqs@v1.34.5/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/aws/smithy-go@v1.20.4/LICENSE: Apache License @@ -9485,256 +9242,145 @@ Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/servi 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/service/sts -Version: v1.30.5 -Licence type (autodetected): Apache-2.0 +Dependency : github.com/blakesmith/ar +Version: v0.0.0-20150311145944-8bd4349a67f2 +Licence type (autodetected): MIT -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/service/sts@v1.30.5/LICENSE.txt: - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. +Contents of probable licence file $GOMODCACHE/github.com/blakesmith/ar@v0.0.0-20150311145944-8bd4349a67f2/COPYING: - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. +Copyright (c) 2013 Blake Smith - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. +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: - "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. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this 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. - "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). +-------------------------------------------------------------------------------- +Dependency : github.com/cavaliergopher/rpm +Version: v1.2.0 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- - "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. +Contents of probable licence file $GOMODCACHE/github.com/cavaliergopher/rpm@v1.2.0/LICENSE: - "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." +Copyright (c) 2017 Ryan Armstrong. All rights reserved. - "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. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: - 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. +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. - 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. +2. 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. - 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: +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and +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 HOLDER 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. - (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 +-------------------------------------------------------------------------------- +Dependency : github.com/cespare/xxhash/v2 +Version: v2.3.0 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- - (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. +Contents of probable licence file $GOMODCACHE/github.com/cespare/xxhash/v2@v2.3.0/LICENSE.txt: - 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. +Copyright (c) 2016 Caleb Spare - 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. +MIT License - 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. +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: - 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. +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. - 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. +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. - 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 +-------------------------------------------------------------------------------- +Dependency : github.com/cloudfoundry-community/go-cfclient +Version: v0.0.0-20190808214049-35bcce23fc5f +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- - APPENDIX: How to apply the Apache License to your work. +Contents of probable licence file $GOMODCACHE/github.com/cloudfoundry-community/go-cfclient@v0.0.0-20190808214049-35bcce23fc5f/LICENSE: - 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. +The MIT License - Copyright [yyyy] [name of copyright owner] +Copyright (c) 2017 Long Nguyen - 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 +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: - http://www.apache.org/licenses/LICENSE-2.0 +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - 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. +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/aws/smithy-go -Version: v1.20.4 +Dependency : github.com/cloudfoundry/noaa +Version: v2.1.0+incompatible Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/aws/smithy-go@v1.20.4/LICENSE: - +Contents of probable licence file $GOMODCACHE/github.com/cloudfoundry/noaa@v2.1.0+incompatible/LICENSE: - Apache License +Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -9909,14 +9555,43 @@ Contents of probable licence file $GOMODCACHE/github.com/aws/smithy-go@v1.20.4/L 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/awslabs/goformation/v7 -Version: v7.14.9 +Dependency : github.com/cloudfoundry/sonde-go +Version: v0.0.0-20171206171820-b33733203bb4 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/awslabs/goformation/v7@v7.14.9/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/cloudfoundry/sonde-go@v0.0.0-20171206171820-b33733203bb4/LICENSE: + Apache License Version 2.0, January 2004 @@ -10095,210 +9770,16 @@ Contents of probable licence file $GOMODCACHE/github.com/awslabs/goformation/v7@ 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/awslabs/kinesis-aggregation/go/v2 -Version: v2.0.0-20220623125934-28468a6701b5 -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- - -No licence file provided. - --------------------------------------------------------------------------------- -Dependency : github.com/blakesmith/ar -Version: v0.0.0-20150311145944-8bd4349a67f2 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/blakesmith/ar@v0.0.0-20150311145944-8bd4349a67f2/COPYING: - -Copyright (c) 2013 Blake Smith - -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/bsm/sarama-cluster -Version: v2.1.14-0.20180625083203-7e67d87a6b3f+incompatible -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/bsm/sarama-cluster@v2.1.14-0.20180625083203-7e67d87a6b3f+incompatible/LICENSE: - -(The MIT License) - -Copyright (c) 2017 Black Square Media Ltd - -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/cavaliergopher/rpm -Version: v1.2.0 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/cavaliergopher/rpm@v1.2.0/LICENSE: - -Copyright (c) 2017 Ryan Armstrong. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. 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. - -3. Neither the name of the copyright holder 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - --------------------------------------------------------------------------------- -Dependency : github.com/cespare/xxhash/v2 -Version: v2.3.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/cespare/xxhash/v2@v2.3.0/LICENSE.txt: - -Copyright (c) 2016 Caleb Spare - -MIT License - -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/cloudfoundry-community/go-cfclient -Version: v0.0.0-20190808214049-35bcce23fc5f -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/cloudfoundry-community/go-cfclient@v0.0.0-20190808214049-35bcce23fc5f/LICENSE: - -The MIT License - -Copyright (c) 2017 Long Nguyen - -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/cloudfoundry/noaa -Version: v2.1.0+incompatible +Dependency : github.com/containerd/fifo +Version: v1.1.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/cloudfoundry/noaa@v2.1.0+incompatible/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/containerd/fifo@v1.1.0/LICENSE: -Apache License + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -10478,7 +9959,7 @@ Apache License 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 "{}" + 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 @@ -10486,7 +9967,7 @@ Apache License same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright {yyyy} {name of copyright owner} + 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. @@ -10501,17 +9982,216 @@ Apache License limitations under the License. - -------------------------------------------------------------------------------- -Dependency : github.com/cloudfoundry/sonde-go -Version: v0.0.0-20171206171820-b33733203bb4 +Dependency : github.com/coreos/go-systemd/v22 +Version: v22.5.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/cloudfoundry/sonde-go@v0.0.0-20171206171820-b33733203bb4/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/coreos/go-systemd/v22@v22.5.0/LICENSE: +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ - Apache License +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: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +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 +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/coreos/pkg +Version: v0.0.0-20180928190104-399ea9e2e55f +Licence type (autodetected): Apache-2.0 +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/coreos/pkg@v0.0.0-20180928190104-399ea9e2e55f/LICENSE: + +Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -10688,14 +10368,71 @@ Contents of probable licence file $GOMODCACHE/github.com/cloudfoundry/sonde-go@v 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/containerd/fifo -Version: v1.1.0 +Dependency : github.com/devigned/tab +Version: v0.1.2-0.20190607222403-0c15cf42f9a2 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/devigned/tab@v0.1.2-0.20190607222403-0c15cf42f9a2/LICENSE: + +MIT License + +Copyright (c) 2019 David Justice + +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/dgraph-io/badger/v4 +Version: v4.4.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/containerd/fifo@v1.1.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/dgraph-io/badger/v4@v4.4.0/LICENSE: Apache License Version 2.0, January 2004 @@ -10874,101 +10611,78 @@ Contents of probable licence file $GOMODCACHE/github.com/containerd/fifo@v1.1.0/ 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/coreos/go-systemd/v22 -Version: v22.5.0 +Dependency : github.com/digitalocean/go-libvirt +Version: v0.0.0-20240709142323-d8406205c752 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/coreos/go-systemd/v22@v22.5.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/digitalocean/go-libvirt@v0.0.0-20240709142323-d8406205c752/LICENSE.md: Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ +============== -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +_Version 2.0, January 2004_ +_<>_ -1. Definitions. +### Terms and Conditions for use, reproduction, and distribution -"License" shall mean the terms and conditions for use, reproduction, and +#### 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 +“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 +“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 +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. +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 +“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 +“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 +“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 +“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 +“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 +“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 +“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." +owner as “Not a Contribution.” -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +“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. +#### 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, @@ -10976,7 +10690,7 @@ 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. +#### 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, @@ -10991,21 +10705,21 @@ 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. +#### 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: -You must give any other recipients of the Work or Derivative Works a copy of +* **(a)** You must give any other recipients of the Work or Derivative Works a copy of this License; and -You must cause any modified files to carry prominent notices stating that You +* **(b)** You must cause any modified files to carry prominent notices stating that You changed the files; and -You must retain, in the Source form of any Derivative Works that You distribute, +* **(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 -If the Work includes a "NOTICE" text file as part of its distribution, then any +* **(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 @@ -11018,13 +10732,14 @@ 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. +#### 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 @@ -11033,17 +10748,17 @@ 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. +#### 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. +#### 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, +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 @@ -11051,7 +10766,7 @@ 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. +#### 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 @@ -11063,7 +10778,7 @@ 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. +#### 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 @@ -11074,44 +10789,46 @@ 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 +_END OF TERMS AND CONDITIONS_ -APPENDIX: How to apply the Apache License to your work +### 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 +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 +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 + 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. - 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/coreos/pkg -Version: v0.0.0-20180928190104-399ea9e2e55f +Dependency : github.com/docker/docker +Version: v27.3.1+incompatible Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/coreos/pkg@v0.0.0-20180928190104-399ea9e2e55f/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/docker/docker@v27.3.1+incompatible/LICENSE: -Apache License + + Apache License Version 2.0, January 2004 - http://www.apache.org/licenses/ + https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -11286,24 +11003,13 @@ Apache License 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} + Copyright 2013-2018 Docker, Inc. 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 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -11312,86 +11018,18 @@ Apache License limitations under the License. - --------------------------------------------------------------------------------- -Dependency : github.com/denisenkom/go-mssqldb -Version: v0.12.3 -Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/denisenkom/go-mssqldb@v0.12.3/LICENSE.txt: - -Copyright (c) 2012 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - --------------------------------------------------------------------------------- -Dependency : github.com/devigned/tab -Version: v0.1.2-0.20190607222403-0c15cf42f9a2 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/devigned/tab@v0.1.2-0.20190607222403-0c15cf42f9a2/LICENSE: - -MIT License - -Copyright (c) 2019 David Justice - -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/dgraph-io/badger/v4 -Version: v4.2.1-0.20240828131336-2725dc8ed5c2 +Dependency : github.com/docker/go-connections +Version: v0.4.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/dgraph-io/badger/v4@v4.2.1-0.20240828131336-2725dc8ed5c2/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/docker/go-connections@v0.4.0/LICENSE: + Apache License Version 2.0, January 2004 - http://www.apache.org/licenses/ + https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -11566,224 +11204,32 @@ Contents of probable licence file $GOMODCACHE/github.com/dgraph-io/badger/v4@v4. END OF TERMS AND CONDITIONS + Copyright 2015 Docker, Inc. --------------------------------------------------------------------------------- -Dependency : github.com/digitalocean/go-libvirt -Version: v0.0.0-20240709142323-d8406205c752 -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/digitalocean/go-libvirt@v0.0.0-20240709142323-d8406205c752/LICENSE.md: - -Apache License -============== - -_Version 2.0, January 2004_ -_<>_ - -### 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. + 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 - 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. + https://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. -------------------------------------------------------------------------------- -Dependency : github.com/docker/docker -Version: v27.3.1+incompatible +Dependency : github.com/docker/go-plugins-helpers +Version: v0.0.0-20181025120712-1e6269c305b8 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/docker/docker@v27.3.1+incompatible/LICENSE: - +Contents of probable licence file $GOMODCACHE/github.com/docker/go-plugins-helpers@v0.0.0-20181025120712-1e6269c305b8/LICENSE: Apache License Version 2.0, January 2004 - https://www.apache.org/licenses/ + http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -11958,13 +11404,24 @@ Contents of probable licence file $GOMODCACHE/github.com/docker/docker@v27.3.1+i END OF TERMS AND CONDITIONS - Copyright 2013-2018 Docker, Inc. + 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 - https://www.apache.org/licenses/LICENSE-2.0 + 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, @@ -11973,426 +11430,14 @@ Contents of probable licence file $GOMODCACHE/github.com/docker/docker@v27.3.1+i limitations under the License. + -------------------------------------------------------------------------------- -Dependency : github.com/docker/go-connections -Version: v0.4.0 +Dependency : github.com/docker/go-units +Version: v0.5.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/docker/go-connections@v0.4.0/LICENSE: - - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2015 Docker, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - --------------------------------------------------------------------------------- -Dependency : github.com/docker/go-plugins-helpers -Version: v0.0.0-20181025120712-1e6269c305b8 -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/docker/go-plugins-helpers@v0.0.0-20181025120712-1e6269c305b8/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 : github.com/docker/go-units -Version: v0.5.0 -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/docker/go-units@v0.5.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/docker/go-units@v0.5.0/LICENSE: Apache License @@ -12880,11 +11925,11 @@ SOFTWARE. -------------------------------------------------------------------------------- Dependency : github.com/eapache/go-resiliency -Version: v1.2.0 +Version: v1.7.0 Licence type (autodetected): MIT -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/eapache/go-resiliency@v1.2.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/eapache/go-resiliency@v1.7.0/LICENSE: The MIT License (MIT) @@ -13443,11 +12488,11 @@ SOFTWARE -------------------------------------------------------------------------------- Dependency : github.com/elastic/elastic-agent-libs -Version: v0.17.3 +Version: v0.17.4 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/elastic/elastic-agent-libs@v0.17.3/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/elastic/elastic-agent-libs@v0.17.4/LICENSE: Apache License Version 2.0, January 2004 @@ -13654,11 +12699,11 @@ Contents of probable licence file $GOMODCACHE/github.com/elastic/elastic-agent-l -------------------------------------------------------------------------------- Dependency : github.com/elastic/elastic-agent-system-metrics -Version: v0.11.4 +Version: v0.11.5 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/elastic/elastic-agent-system-metrics@v0.11.4/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/elastic/elastic-agent-system-metrics@v0.11.5/LICENSE.txt: Apache License Version 2.0, January 2004 @@ -14287,11 +13332,11 @@ Contents of probable licence file $GOMODCACHE/github.com/elastic/go-elasticsearc -------------------------------------------------------------------------------- Dependency : github.com/elastic/go-libaudit/v2 -Version: v2.5.0 +Version: v2.6.1 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/elastic/go-libaudit/v2@v2.5.0/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/elastic/go-libaudit/v2@v2.6.1/LICENSE.txt: Apache License @@ -15134,11 +14179,11 @@ Contents of probable licence file $GOMODCACHE/github.com/elastic/go-lumber@v0.1. -------------------------------------------------------------------------------- Dependency : github.com/elastic/go-perf -Version: v0.0.0-20191212140718-9c656876f595 +Version: v0.0.0-20241029065020-30bec95324b8 Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/elastic/go-perf@v0.0.0-20191212140718-9c656876f595/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/elastic/go-perf@v0.0.0-20241029065020-30bec95324b8/LICENSE: Copyright (c) 2009 The Go Authors. All rights reserved. @@ -15383,11 +14428,11 @@ Contents of probable licence file $GOMODCACHE/github.com/elastic/go-quark@v0.2.0 -------------------------------------------------------------------------------- Dependency : github.com/elastic/go-seccomp-bpf -Version: v1.4.0 +Version: v1.5.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/elastic/go-seccomp-bpf@v1.4.0/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/elastic/go-seccomp-bpf@v1.5.0/LICENSE.txt: Apache License @@ -15837,11 +14882,11 @@ Contents of probable licence file $GOMODCACHE/github.com/elastic/go-structform@v -------------------------------------------------------------------------------- Dependency : github.com/elastic/go-sysinfo -Version: v1.14.2 +Version: v1.15.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/elastic/go-sysinfo@v1.14.2/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/elastic/go-sysinfo@v1.15.0/LICENSE.txt: Apache License @@ -16471,11 +15516,11 @@ limitations under the License. -------------------------------------------------------------------------------- Dependency : github.com/elastic/mito -Version: v1.15.0 +Version: v1.16.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/elastic/mito@v1.15.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/elastic/mito@v1.16.0/LICENSE: Apache License @@ -16704,6 +15749,40 @@ See the License for the specific language governing permissions and limitations under the License. +-------------------------------------------------------------------------------- +Dependency : github.com/elastic/sarama +Version: v1.19.1-0.20241120141909-c7eabfcee7e5 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/elastic/sarama@v1.19.1-0.20241120141909-c7eabfcee7e5/LICENSE.md: + +# MIT License + +Copyright (c) 2013 Shopify + +Copyright (c) 2023 IBM Corporation + +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/elastic/tk-btf Version: v0.1.0 @@ -18235,448 +17314,236 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI -------------------------------------------------------------------------------- -Dependency : github.com/golang/mock -Version: v1.6.0 +Dependency : github.com/golang/snappy +Version: v0.0.4 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/golang/snappy@v0.0.4/LICENSE: + +Copyright (c) 2011 The Snappy-Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +-------------------------------------------------------------------------------- +Dependency : github.com/gomodule/redigo +Version: v1.8.3 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/golang/mock@v1.6.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 : github.com/golang/snappy -Version: v0.0.4 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/golang/snappy@v0.0.4/LICENSE: - -Copyright (c) 2011 The Snappy-Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - --------------------------------------------------------------------------------- -Dependency : github.com/gomodule/redigo -Version: v1.8.3 -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/gomodule/redigo@v1.8.3/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 - - --------------------------------------------------------------------------------- -Dependency : github.com/google/cel-go -Version: v0.19.0 -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/google/cel-go@v0.19.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/gomodule/redigo@v1.8.3/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 + + +-------------------------------------------------------------------------------- +Dependency : github.com/google/cel-go +Version: v0.19.0 +Licence type (autodetected): Apache-2.0 +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/google/cel-go@v0.19.0/LICENSE: Apache License @@ -18915,11 +17782,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- Dependency : github.com/google/flatbuffers -Version: v23.5.26+incompatible +Version: v24.3.25+incompatible Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/google/flatbuffers@v23.5.26+incompatible/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/google/flatbuffers@v24.3.25+incompatible/LICENSE: Apache License @@ -19960,12 +18827,12 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice -------------------------------------------------------------------------------- -Dependency : github.com/hashicorp/golang-lru -Version: v0.6.0 +Dependency : github.com/hashicorp/golang-lru/v2 +Version: v2.0.7 Licence type (autodetected): MPL-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/hashicorp/golang-lru@v0.6.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/hashicorp/golang-lru/v2@v2.0.7/LICENSE: Copyright (c) 2014 HashiCorp, Inc. @@ -20798,303 +19665,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- -Dependency : github.com/joeshaw/multierror -Version: v0.0.0-20140124173710-69b34d4ec901 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/joeshaw/multierror@v0.0.0-20140124173710-69b34d4ec901/LICENSE: - -The MIT License (MIT) - -Copyright (c) 2014 Joe Shaw - -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/jonboulle/clockwork -Version: v0.2.2 -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/jonboulle/clockwork@v0.2.2/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 : github.com/josephspurrier/goversioninfo -Version: v0.0.0-20190209210621-63e6d1acd3dd -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/josephspurrier/goversioninfo@v0.0.0-20190209210621-63e6d1acd3dd/LICENSE: - -The MIT License (MIT) - -Copyright (c) 2016 Joseph Spurrier - -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/lib/pq -Version: v1.10.3 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/lib/pq@v1.10.3/LICENSE.md: - -Copyright (c) 2011-2013, 'pq' Contributors -Portions Copyright (C) 2011 Blake Mizerany - -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/magefile/mage -Version: v1.15.0 +Dependency : github.com/jcmturner/gokrb5/v8 +Version: v8.4.4 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/magefile/mage@v1.15.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/jcmturner/gokrb5/v8@v8.4.4/LICENSE: Apache License Version 2.0, January 2004 @@ -21284,7 +19860,7 @@ Contents of probable licence file $GOMODCACHE/github.com/magefile/mage@v1.15.0/L same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2017 the Mage authors + 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. @@ -21300,16 +19876,16 @@ Contents of probable licence file $GOMODCACHE/github.com/magefile/mage@v1.15.0/L -------------------------------------------------------------------------------- -Dependency : github.com/mattn/go-colorable -Version: v0.1.13 +Dependency : github.com/joeshaw/multierror +Version: v0.0.0-20140124173710-69b34d4ec901 Licence type (autodetected): MIT -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/mattn/go-colorable@v0.1.13/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/joeshaw/multierror@v0.0.0-20140124173710-69b34d4ec901/LICENSE: The MIT License (MIT) -Copyright (c) 2016 Yasuhiro Matsumoto +Copyright (c) 2014 Joe Shaw Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -21318,493 +19894,510 @@ 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 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. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. -------------------------------------------------------------------------------- -Dependency : github.com/tommyers-elastic/dashboard-api-go/v3 -Version: v3.0.0-20240913150833-a945473a8f25 -Licence type (autodetected): MIT +Dependency : github.com/jonboulle/clockwork +Version: v0.2.2 +Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/tommyers-elastic/dashboard-api-go/v3@v3.0.0-20240913150833-a945473a8f25/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/jonboulle/clockwork@v0.2.2/LICENSE: -MIT License +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -Copyright (c) 2019-2020 Cisco Systems + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -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: + 1. Definitions. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. -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. + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. --------------------------------------------------------------------------------- -Dependency : github.com/miekg/dns -Version: v1.1.61 -Licence type (autodetected): BSD --------------------------------------------------------------------------------- + "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. -Contents of probable licence file $GOMODCACHE/github.com/miekg/dns@v1.1.61/COPYRIGHT: + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. -Copyright 2009 The Go Authors. All rights reserved. Use of this source code -is governed by a BSD-style license that can be found in the LICENSE file. -Extensions of the original work are copyright (c) 2011 Miek Gieben + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. -Copyright 2011 Miek Gieben. All rights reserved. Use of this source code is -governed by a BSD-style license that can be found in the LICENSE file. + "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. -Copyright 2014 CloudFlare. All rights reserved. Use of this source code is -governed by a BSD-style license that can be found in the LICENSE file. + "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. --------------------------------------------------------------------------------- -Dependency : github.com/mitchellh/gox -Version: v1.0.1 -Licence type (autodetected): MPL-2.0 --------------------------------------------------------------------------------- + "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." -Contents of probable licence file $GOMODCACHE/github.com/mitchellh/gox@v1.0.1/LICENSE: + "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. -Mozilla Public License Version 2.0 -================================== + 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. -1. Definitions --------------- + 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. -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. + 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: -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and -1.3. "Contribution" - means Covered Software of a particular Contributor. + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. + (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 -1.5. "Incompatible With Secondary Licenses" - means + (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. - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or + 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. - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary 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. -1.6. "Executable Form" - means any form of the work other than Source Code Form. + 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. -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. + 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. -1.8. "License" - means this document. + 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. -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. + 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. -1.10. "Modifications" - means any of the following: + END OF TERMS AND CONDITIONS - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or + APPENDIX: How to apply the Apache License to your work. - (b) any new file in Source Code Form that contains any Covered - Software. + 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. -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. + Copyright {yyyy} {name of copyright owner} -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. + 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 -1.13. "Source Code Form" - means the form of the work preferred for making modifications. + http://www.apache.org/licenses/LICENSE-2.0 -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. + 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. -2. License Grants and Conditions --------------------------------- -2.1. Grants +-------------------------------------------------------------------------------- +Dependency : github.com/josephspurrier/goversioninfo +Version: v0.0.0-20190209210621-63e6d1acd3dd +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: +Contents of probable licence file $GOMODCACHE/github.com/josephspurrier/goversioninfo@v0.0.0-20190209210621-63e6d1acd3dd/LICENSE: -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and +The MIT License (MIT) -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. +Copyright (c) 2016 Joseph Spurrier -2.2. Effective Date +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 licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -2.3. Limitations on Grant Scope +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. -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: -(a) for any code that a Contributor has removed from Covered Software; - or +-------------------------------------------------------------------------------- +Dependency : github.com/klauspost/compress +Version: v1.17.11 +Licence type (autodetected): Apache-2.0 +-------------------------------------------------------------------------------- -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or +Contents of probable licence file $GOMODCACHE/github.com/klauspost/compress@v1.17.11/LICENSE: -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. +Copyright (c) 2012 The Go Authors. All rights reserved. +Copyright (c) 2019 Klaus Post. All rights reserved. -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: -2.4. Subsequent Licenses + * 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. -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). +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. -2.5. Representation +------------------ -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. +Files: gzhttp/* -2.6. Fair Use + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -2.7. Conditions + 1. Definitions. -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. -3. Responsibilities -------------------- + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. -3.1. Distribution of Source Form + "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. -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. -3.2. Distribution of Executable Form + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. -If You distribute Covered Software in Executable Form then: + "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. -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and + "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). -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. + "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. -3.3. Distribution of a Larger Work + "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." -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). + "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. -3.4. Notices + 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. -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. + 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. -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses + 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: -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and -Exhibit A - Source Code Form License Notice -------------------------------------------- + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. + (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 -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. + (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 additional accurate notices of copyright ownership. + 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. -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- + 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. - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. + 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. --------------------------------------------------------------------------------- -Dependency : github.com/mitchellh/hashstructure -Version: v1.1.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- + 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. -Contents of probable licence file $GOMODCACHE/github.com/mitchellh/hashstructure@v1.1.0/LICENSE: + END OF TERMS AND CONDITIONS -The MIT License (MIT) + APPENDIX: How to apply the Apache License to your work. -Copyright (c) 2016 Mitchell Hashimoto + 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. -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: + Copyright 2016-2017 The New York Times Company -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. + 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 -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. + 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/mitchellh/mapstructure -Version: v1.5.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- +------------------ -Contents of probable licence file $GOMODCACHE/github.com/mitchellh/mapstructure@v1.5.0/LICENSE: +Files: s2/cmd/internal/readahead/* The MIT License (MIT) -Copyright (c) 2013 Mitchell Hashimoto +Copyright (c) 2015 Klaus Post Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -21813,58 +20406,54 @@ 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 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/olekukonko/tablewriter -Version: v0.0.5 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/olekukonko/tablewriter@v0.0.5/LICENSE.md: - -Copyright (C) 2014 by Oleku Konko +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. -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: +--------------------- +Files: snappy/* +Files: internal/snapref/* -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +Copyright (c) 2011 The Snappy-Go Authors. All rights reserved. -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. +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. --------------------------------------------------------------------------------- -Dependency : github.com/osquery/osquery-go -Version: v0.0.0-20231108163517-e3cde127e724 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- +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. -Contents of probable licence file $GOMODCACHE/github.com/osquery/osquery-go@v0.0.0-20231108163517-e3cde127e724/LICENSE: +----------------- -MIT License +Files: s2/cmd/internal/filepathx/* -Copyright 2017 Kolide Inc. +Copyright 2016 The filepathx Authors 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: @@ -21872,84 +20461,17 @@ The above copyright notice and this permission notice shall be included in all c 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/otiai10/copy -Version: v1.12.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/otiai10/copy@v1.12.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/pierrec/lz4/v4 -Version: v4.1.18 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/pierrec/lz4/v4@v4.1.18/LICENSE: - -Copyright (c) 2015, Pierre Curto -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 xxHash 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 HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -------------------------------------------------------------------------------- -Dependency : github.com/pierrre/gotestcover -Version: v0.0.0-20160517101806-924dca7d15f0 +Dependency : github.com/lib/pq +Version: v1.10.3 Licence type (autodetected): MIT -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/pierrre/gotestcover@v0.0.0-20160517101806-924dca7d15f0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/lib/pq@v1.10.3/LICENSE.md: -Copyright (C) 2015 Pierre Durand +Copyright (c) 2011-2013, 'pq' Contributors +Portions Copyright (C) 2011 Blake Mizerany 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: @@ -21957,81 +20479,14 @@ The above copyright notice and this permission notice shall be included in all c 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/pkg/errors -Version: v0.9.1 -Licence type (autodetected): BSD-2-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/pkg/errors@v0.9.1/LICENSE: - -Copyright (c) 2015, Dave Cheney -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. - -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 HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - --------------------------------------------------------------------------------- -Dependency : github.com/pkg/xattr -Version: v0.4.9 -Licence type (autodetected): BSD-2-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/pkg/xattr@v0.4.9/LICENSE: - -Copyright (c) 2012 Dave Cheney. All rights reserved. -Copyright (c) 2014 Kuba Podgórski. 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. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -------------------------------------------------------------------------------- -Dependency : github.com/prometheus/client_model -Version: v0.6.1 +Dependency : github.com/magefile/mage +Version: v1.15.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/prometheus/client_model@v0.6.1/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/magefile/mage@v1.15.0/LICENSE: Apache License Version 2.0, January 2004 @@ -22213,7 +20668,7 @@ Contents of probable licence file $GOMODCACHE/github.com/prometheus/client_model 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 "[]" + 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 @@ -22221,7 +20676,7 @@ Contents of probable licence file $GOMODCACHE/github.com/prometheus/client_model same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2017 the Mage authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22237,755 +20692,744 @@ Contents of probable licence file $GOMODCACHE/github.com/prometheus/client_model -------------------------------------------------------------------------------- -Dependency : github.com/prometheus/common -Version: v0.57.0 -Licence type (autodetected): Apache-2.0 +Dependency : github.com/mattn/go-colorable +Version: v0.1.13 +Licence type (autodetected): MIT -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/prometheus/common@v0.57.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/mattn/go-colorable@v0.1.13/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) 2016 Yasuhiro Matsumoto - 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. +-------------------------------------------------------------------------------- +Dependency : github.com/tommyers-elastic/dashboard-api-go/v3 +Version: v3.0.0-20240913150833-a945473a8f25 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. +Contents of probable licence file $GOMODCACHE/github.com/tommyers-elastic/dashboard-api-go/v3@v3.0.0-20240913150833-a945473a8f25/LICENSE: - "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. +MIT License - "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). +Copyright (c) 2019-2020 Cisco Systems - "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. +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: - "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." +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. - "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. +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. - 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. +-------------------------------------------------------------------------------- +Dependency : github.com/microsoft/go-mssqldb +Version: v1.7.2 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- - 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. +Contents of probable licence file $GOMODCACHE/github.com/microsoft/go-mssqldb@v1.7.2/LICENSE.txt: - 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: +Copyright (c) 2012 The Go Authors. All rights reserved. +Copyright (c) Microsoft Corporation. - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and + * 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. - (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 +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. - (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. +-------------------------------------------------------------------------------- +Dependency : github.com/miekg/dns +Version: v1.1.61 +Licence type (autodetected): BSD +-------------------------------------------------------------------------------- - 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. +Contents of probable licence file $GOMODCACHE/github.com/miekg/dns@v1.1.61/COPYRIGHT: - 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. +Copyright 2009 The Go Authors. All rights reserved. Use of this source code +is governed by a BSD-style license that can be found in the LICENSE file. +Extensions of the original work are copyright (c) 2011 Miek Gieben - 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. +Copyright 2011 Miek Gieben. All rights reserved. Use of this source code is +governed by a BSD-style license that can be found in the LICENSE file. - 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. +Copyright 2014 CloudFlare. All rights reserved. Use of this source code is +governed by a BSD-style license that can be found in the LICENSE file. - 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 +-------------------------------------------------------------------------------- +Dependency : github.com/mitchellh/gox +Version: v1.0.1 +Licence type (autodetected): MPL-2.0 +-------------------------------------------------------------------------------- - APPENDIX: How to apply the Apache License to your work. +Contents of probable licence file $GOMODCACHE/github.com/mitchellh/gox@v1.0.1/LICENSE: - 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. +Mozilla Public License Version 2.0 +================================== - Copyright [yyyy] [name of copyright owner] +1. Definitions +-------------- - 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 +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. - http://www.apache.org/licenses/LICENSE-2.0 +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. - 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. +1.3. "Contribution" + means Covered Software of a particular Contributor. +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. --------------------------------------------------------------------------------- -Dependency : github.com/prometheus/procfs -Version: v0.15.1 -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- +1.5. "Incompatible With Secondary Licenses" + means -Contents of probable licence file $GOMODCACHE/github.com/prometheus/procfs@v0.15.1/LICENSE: + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +1.6. "Executable Form" + means any form of the work other than Source Code Form. - 1. Definitions. +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. +1.8. "License" + means this document. - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this 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. +1.10. "Modifications" + means any of the following: - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. + (b) any new file in Source Code Form that contains any Covered + Software. - "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. +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. - "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). +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. - "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. +1.13. "Source Code Form" + means the form of the work preferred for making modifications. - "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." +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. - "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. License Grants and Conditions +-------------------------------- - 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. +2.1. Grants - 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. +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: - 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) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and +2.2. Effective Date - (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 +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. - (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. +2.3. Limitations on Grant Scope - 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. +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: - 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. +(a) for any code that a Contributor has removed from Covered Software; + or - 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. +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or - 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. +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. - 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. +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). - 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. +2.4. Subsequent Licenses - END OF TERMS AND CONDITIONS +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). - APPENDIX: How to apply the Apache License to your work. +2.5. Representation - 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. +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. - Copyright [yyyy] [name of copyright owner] +2.6. Fair Use - 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 +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. - http://www.apache.org/licenses/LICENSE-2.0 +2.7. Conditions - 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. +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. +3. Responsibilities +------------------- --------------------------------------------------------------------------------- -Dependency : github.com/prometheus/prometheus -Version: v0.54.1 -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- +3.1. Distribution of Source Form -Contents of probable licence file $GOMODCACHE/github.com/prometheus/prometheus@v0.54.1/LICENSE: +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ +3.2. Distribution of Executable Form - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +If You distribute Covered Software in Executable Form then: - 1. Definitions. +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. +3.3. Distribution of a Larger Work - "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 may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. +3.4. Notices - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. - "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. +3.5. Application of Additional Terms - "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). +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. - "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. +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- - "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." +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. - "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. +5. Termination +-------------- - 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. +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. - 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. +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. - 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: +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ - (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 +8. Litigation +------------- - (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. +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. - 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. +9. Miscellaneous +---------------- - 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. +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. - 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. +10. Versions of the License +--------------------------- - 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. +10.1. New Versions - 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. +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. - 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. +10.2. Effect of New Versions - END OF TERMS AND CONDITIONS +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. - APPENDIX: How to apply the Apache License to your work. +10.3. Modified Versions - 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. +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). - Copyright [yyyy] [name of copyright owner] +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses - 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 +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. - http://www.apache.org/licenses/LICENSE-2.0 +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 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/rcrowley/go-metrics -Version: v0.0.0-20201227073835-cf1acfcdf475 -Licence type (autodetected): BSD-2-Clause-FreeBSD +Dependency : github.com/mitchellh/hashstructure +Version: v1.1.0 +Licence type (autodetected): MIT -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/rcrowley/go-metrics@v0.0.0-20201227073835-cf1acfcdf475/LICENSE: - -Copyright 2012 Richard Crowley. All rights reserved. +Contents of probable licence file $GOMODCACHE/github.com/mitchellh/hashstructure@v1.1.0/LICENSE: -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: +The MIT License (MIT) - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. +Copyright (c) 2016 Mitchell Hashimoto - 2. 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. +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: -THIS SOFTWARE IS PROVIDED BY RICHARD CROWLEY ``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 RICHARD CROWLEY 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. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. -The views and conclusions contained in the software and documentation -are those of the authors and should not be interpreted as representing -official policies, either expressed or implied, of Richard Crowley. +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/samuel/go-thrift -Version: v0.0.0-20140522043831-2187045faa54 -Licence type (autodetected): BSD-3-Clause +Dependency : github.com/mitchellh/mapstructure +Version: v1.5.0 +Licence type (autodetected): MIT -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/samuel/go-thrift@v0.0.0-20140522043831-2187045faa54/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/mitchellh/mapstructure@v1.5.0/LICENSE: -Copyright (c) 2012, Samuel Stauffer -All rights reserved. +The MIT License (MIT) -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: +Copyright (c) 2013 Mitchell Hashimoto -* Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -* Neither the name of the author nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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: -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 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. +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/shirou/gopsutil/v3 -Version: v3.22.10 -Licence type (autodetected): BSD-3-Clause +Dependency : github.com/olekukonko/tablewriter +Version: v0.0.5 +Licence type (autodetected): MIT -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/shirou/gopsutil/v3@v3.22.10/LICENSE: - -gopsutil is distributed under BSD license reproduced below. - -Copyright (c) 2014, WAKAYAMA Shirou -All rights reserved. +Contents of probable licence file $GOMODCACHE/github.com/olekukonko/tablewriter@v0.0.5/LICENSE.md: -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: +Copyright (C) 2014 by Oleku Konko - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of the gopsutil authors nor the names of its contributors - may be used to endorse or promote products derived from this software without - specific prior written permission. +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: -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. +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. -------- -internal/common/binary.go in the gopsutil is copied and modified from golang/encoding/binary.go. +-------------------------------------------------------------------------------- +Dependency : github.com/osquery/osquery-go +Version: v0.0.0-20231108163517-e3cde127e724 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/osquery/osquery-go@v0.0.0-20231108163517-e3cde127e724/LICENSE: +MIT License -Copyright (c) 2009 The Go Authors. All rights reserved. +Copyright 2017 Kolide Inc. + +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/otiai10/copy +Version: v1.12.0 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/otiai10/copy@v1.12.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/pierrec/lz4/v4 +Version: v4.1.21 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/pierrec/lz4/v4@v4.1.21/LICENSE: + +Copyright (c) 2015, Pierre Curto +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 xxHash 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 HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +Dependency : github.com/pierrre/gotestcover +Version: v0.0.0-20160517101806-924dca7d15f0 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/pierrre/gotestcover@v0.0.0-20160517101806-924dca7d15f0/LICENSE: + +Copyright (C) 2015 Pierre Durand + +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/pkg/errors +Version: v0.9.1 +Licence type (autodetected): BSD-2-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/pkg/errors@v0.9.1/LICENSE: + +Copyright (c) 2015, Dave Cheney +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. + +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 HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +-------------------------------------------------------------------------------- +Dependency : github.com/pkg/xattr +Version: v0.4.9 +Licence type (autodetected): BSD-2-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/pkg/xattr@v0.4.9/LICENSE: + +Copyright (c) 2012 Dave Cheney. All rights reserved. +Copyright (c) 2014 Kuba Podgórski. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -22997,9 +21441,6 @@ notice, this list of conditions and the following disclaimer. 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 @@ -23013,15 +21454,16 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + -------------------------------------------------------------------------------- -Dependency : github.com/spf13/cobra -Version: v1.8.1 +Dependency : github.com/prometheus/client_model +Version: v0.6.1 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/spf13/cobra@v1.8.1/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/prometheus/client_model@v0.6.1/LICENSE: - Apache License + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -23196,192 +21638,41 @@ Contents of probable licence file $GOMODCACHE/github.com/spf13/cobra@v1.8.1/LICE incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + END OF TERMS AND CONDITIONS --------------------------------------------------------------------------------- -Dependency : github.com/spf13/pflag -Version: v1.0.5 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/spf13/pflag@v1.0.5/LICENSE: - -Copyright (c) 2012 Alex Ogier. All rights reserved. -Copyright (c) 2012 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - --------------------------------------------------------------------------------- -Dependency : github.com/stretchr/testify -Version: v1.9.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/stretchr/testify@v1.9.0/LICENSE: - -MIT License - -Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. - -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/tklauser/go-sysconf -Version: v0.3.12 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/tklauser/go-sysconf@v0.3.12/LICENSE: - -BSD 3-Clause License - -Copyright (c) 2018-2022, Tobias Klauser -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder 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 HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - --------------------------------------------------------------------------------- -Dependency : github.com/tsg/go-daemon -Version: v0.0.0-20200207173439-e704b93fd89b -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/tsg/go-daemon@v0.0.0-20200207173439-e704b93fd89b/LICENSE: - -Copyright (c) 2013-2014 Alexandre Fiori. 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. - * The names of authors or contributors may NOT be used to endorse or -promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - --------------------------------------------------------------------------------- -Dependency : github.com/ugorji/go/codec -Version: v1.1.8 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/ugorji/go/codec@v1.1.8/LICENSE: + APPENDIX: How to apply the Apache License to your work. -The MIT License (MIT) + 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 (c) 2012-2015 Ugorji Nwoke. -All rights reserved. + Copyright [yyyy] [name of copyright owner] -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: + 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 -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + http://www.apache.org/licenses/LICENSE-2.0 -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. + 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/vmware/govmomi -Version: v0.39.0 +Dependency : github.com/prometheus/common +Version: v0.57.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/vmware/govmomi@v0.39.0/LICENSE.txt: - +Contents of probable licence file $GOMODCACHE/github.com/prometheus/common@v0.57.0/LICENSE: Apache License Version 2.0, January 2004 @@ -23587,13 +21878,12 @@ Contents of probable licence file $GOMODCACHE/github.com/vmware/govmomi@v0.39.0/ -------------------------------------------------------------------------------- -Dependency : github.com/xdg-go/scram -Version: v1.1.2 +Dependency : github.com/prometheus/procfs +Version: v0.15.1 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/xdg-go/scram@v1.1.2/LICENSE: - +Contents of probable licence file $GOMODCACHE/github.com/prometheus/procfs@v0.15.1/LICENSE: Apache License Version 2.0, January 2004 @@ -23770,46 +22060,41 @@ Contents of probable licence file $GOMODCACHE/github.com/xdg-go/scram@v1.1.2/LIC incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + END OF TERMS AND CONDITIONS --------------------------------------------------------------------------------- -Dependency : github.com/zyedidia/generic -Version: v1.2.1 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/zyedidia/generic@v1.2.1/LICENSE: + APPENDIX: How to apply the Apache License to your work. -MIT License + 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 (c) 2021: Zachary Yedidia. + Copyright [yyyy] [name of copyright owner] -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: + 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 -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. + http://www.apache.org/licenses/LICENSE-2.0 -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. + 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 : go.elastic.co/apm/module/apmelasticsearch/v2 -Version: v2.6.0 +Dependency : github.com/prometheus/prometheus +Version: v0.54.1 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.elastic.co/apm/module/apmelasticsearch/v2@v2.6.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/prometheus/prometheus@v0.54.1/LICENSE: Apache License Version 2.0, January 2004 @@ -23999,7 +22284,7 @@ Contents of probable licence file $GOMODCACHE/go.elastic.co/apm/module/apmelasti same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2018 Elasticsearch BV + 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. @@ -24015,14 +22300,158 @@ Contents of probable licence file $GOMODCACHE/go.elastic.co/apm/module/apmelasti -------------------------------------------------------------------------------- -Dependency : go.elastic.co/apm/module/apmhttp/v2 -Version: v2.6.0 +Dependency : github.com/rcrowley/go-metrics +Version: v0.0.0-20201227073835-cf1acfcdf475 +Licence type (autodetected): BSD-2-Clause-FreeBSD +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/rcrowley/go-metrics@v0.0.0-20201227073835-cf1acfcdf475/LICENSE: + +Copyright 2012 Richard Crowley. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. 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. + +THIS SOFTWARE IS PROVIDED BY RICHARD CROWLEY ``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 RICHARD CROWLEY 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. + +The views and conclusions contained in the software and documentation +are those of the authors and should not be interpreted as representing +official policies, either expressed or implied, of Richard Crowley. + + +-------------------------------------------------------------------------------- +Dependency : github.com/samuel/go-thrift +Version: v0.0.0-20140522043831-2187045faa54 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/samuel/go-thrift@v0.0.0-20140522043831-2187045faa54/LICENSE: + +Copyright (c) 2012, Samuel Stauffer +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of the author 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 BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +-------------------------------------------------------------------------------- +Dependency : github.com/shirou/gopsutil/v4 +Version: v4.24.7 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/shirou/gopsutil/v4@v4.24.7/LICENSE: + +gopsutil is distributed under BSD license reproduced below. + +Copyright (c) 2014, WAKAYAMA Shirou +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the gopsutil authors nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +------- +internal/common/binary.go in the gopsutil is copied and modified from golang/encoding/binary.go. + + + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------------------------- +Dependency : github.com/spf13/cobra +Version: v1.8.1 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.elastic.co/apm/module/apmhttp/v2@v2.6.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/spf13/cobra@v1.8.1/LICENSE.txt: - Apache License + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -24197,41 +22626,192 @@ Contents of probable licence file $GOMODCACHE/go.elastic.co/apm/module/apmhttp/v 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. +-------------------------------------------------------------------------------- +Dependency : github.com/spf13/pflag +Version: v1.0.5 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- - 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. +Contents of probable licence file $GOMODCACHE/github.com/spf13/pflag@v1.0.5/LICENSE: - Copyright 2018 Elasticsearch BV +Copyright (c) 2012 Alex Ogier. All rights reserved. +Copyright (c) 2012 The Go Authors. All rights reserved. - 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 +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: - http://www.apache.org/licenses/LICENSE-2.0 + * 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. - 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. +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 : go.elastic.co/apm/v2 -Version: v2.6.0 +Dependency : github.com/stretchr/testify +Version: v1.9.0 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/stretchr/testify@v1.9.0/LICENSE: + +MIT License + +Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. + +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/tklauser/go-sysconf +Version: v0.3.12 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/tklauser/go-sysconf@v0.3.12/LICENSE: + +BSD 3-Clause License + +Copyright (c) 2018-2022, Tobias Klauser +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder 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 HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +-------------------------------------------------------------------------------- +Dependency : github.com/tsg/go-daemon +Version: v0.0.0-20200207173439-e704b93fd89b +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/tsg/go-daemon@v0.0.0-20200207173439-e704b93fd89b/LICENSE: + +Copyright (c) 2013-2014 Alexandre Fiori. 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. + * The names of authors or contributors may NOT be used to endorse or +promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +-------------------------------------------------------------------------------- +Dependency : github.com/ugorji/go/codec +Version: v1.1.8 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/ugorji/go/codec@v1.1.8/LICENSE: + +The MIT License (MIT) + +Copyright (c) 2012-2015 Ugorji Nwoke. +All rights reserved. + +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/vmware/govmomi +Version: v0.39.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.elastic.co/apm/v2@v2.6.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/vmware/govmomi@v0.39.0/LICENSE.txt: + Apache License Version 2.0, January 2004 @@ -24421,7 +23001,7 @@ Contents of probable licence file $GOMODCACHE/go.elastic.co/apm/v2@v2.6.0/LICENS same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2018 Elasticsearch BV + 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. @@ -24437,12 +23017,12 @@ Contents of probable licence file $GOMODCACHE/go.elastic.co/apm/v2@v2.6.0/LICENS -------------------------------------------------------------------------------- -Dependency : go.elastic.co/ecszap -Version: v1.0.2 +Dependency : github.com/xdg-go/scram +Version: v1.1.2 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.elastic.co/ecszap@v1.0.2/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/xdg-go/scram@v1.1.2/LICENSE: Apache License @@ -24620,6 +23200,222 @@ Contents of probable licence file $GOMODCACHE/go.elastic.co/ecszap@v1.0.2/LICENS incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +-------------------------------------------------------------------------------- +Dependency : github.com/zyedidia/generic +Version: v1.2.1 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/zyedidia/generic@v1.2.1/LICENSE: + +MIT License + +Copyright (c) 2021: Zachary Yedidia. + +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 : go.elastic.co/apm/module/apmelasticsearch/v2 +Version: v2.6.0 +Licence type (autodetected): Apache-2.0 +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/go.elastic.co/apm/module/apmelasticsearch/v2@v2.6.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. @@ -24633,7 +23429,7 @@ Contents of probable licence file $GOMODCACHE/go.elastic.co/ecszap@v1.0.2/LICENS same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2020 Elastic and contributors + Copyright 2018 Elasticsearch BV Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24647,14 +23443,14 @@ Contents of probable licence file $GOMODCACHE/go.elastic.co/ecszap@v1.0.2/LICENS See the License for the specific language governing permissions and limitations under the License. + -------------------------------------------------------------------------------- -Dependency : go.elastic.co/go-licence-detector -Version: v0.7.0 +Dependency : go.elastic.co/apm/module/apmhttp/v2 +Version: v2.6.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.elastic.co/go-licence-detector@v0.7.0/LICENSE: - +Contents of probable licence file $GOMODCACHE/go.elastic.co/apm/module/apmhttp/v2@v2.6.0/LICENSE: Apache License Version 2.0, January 2004 @@ -24844,7 +23640,7 @@ Contents of probable licence file $GOMODCACHE/go.elastic.co/go-licence-detector@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2018 Elasticsearch BV Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24860,42 +23656,12 @@ Contents of probable licence file $GOMODCACHE/go.elastic.co/go-licence-detector@ -------------------------------------------------------------------------------- -Dependency : go.etcd.io/bbolt -Version: v1.3.10 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/go.etcd.io/bbolt@v1.3.10/LICENSE: - -The MIT License (MIT) - -Copyright (c) 2013 Ben Johnson - -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 : go.mongodb.org/mongo-driver -Version: v1.14.0 +Dependency : go.elastic.co/apm/v2 +Version: v2.6.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.mongodb.org/mongo-driver@v1.14.0/LICENSE: +Contents of probable licence file $GOMODCACHE/go.elastic.co/apm/v2@v2.6.0/LICENSE: Apache License Version 2.0, January 2004 @@ -25085,7 +23851,7 @@ Contents of probable licence file $GOMODCACHE/go.mongodb.org/mongo-driver@v1.14. same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2018 Elasticsearch BV Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25101,12 +23867,223 @@ Contents of probable licence file $GOMODCACHE/go.mongodb.org/mongo-driver@v1.14. -------------------------------------------------------------------------------- -Dependency : go.opentelemetry.io/collector/component -Version: v0.109.0 +Dependency : go.elastic.co/ecszap +Version: v1.0.2 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/component@v0.109.0/LICENSE: +Contents of probable licence file $GOMODCACHE/go.elastic.co/ecszap@v1.0.2/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 2020 Elastic and contributors + + 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 : go.elastic.co/go-licence-detector +Version: v0.7.0 +Licence type (autodetected): Apache-2.0 +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/go.elastic.co/go-licence-detector@v0.7.0/LICENSE: Apache License @@ -25313,13 +24290,42 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/comp -------------------------------------------------------------------------------- -Dependency : go.opentelemetry.io/collector/consumer -Version: v0.109.0 -Licence type (autodetected): Apache-2.0 +Dependency : go.etcd.io/bbolt +Version: v1.3.10 +Licence type (autodetected): MIT -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/consumer@v0.109.0/LICENSE: +Contents of probable licence file $GOMODCACHE/go.etcd.io/bbolt@v1.3.10/LICENSE: + +The MIT License (MIT) + +Copyright (c) 2013 Ben Johnson + +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 : go.mongodb.org/mongo-driver +Version: v1.14.0 +Licence type (autodetected): Apache-2.0 +-------------------------------------------------------------------------------- +Contents of probable licence file $GOMODCACHE/go.mongodb.org/mongo-driver@v1.14.0/LICENSE: Apache License Version 2.0, January 2004 @@ -25525,12 +24531,12 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/cons -------------------------------------------------------------------------------- -Dependency : go.opentelemetry.io/collector/pdata -Version: v1.15.0 +Dependency : go.opentelemetry.io/collector/component +Version: v0.109.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/pdata@v1.15.0/LICENSE: +Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/component@v0.109.0/LICENSE: Apache License @@ -25737,12 +24743,12 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/pdat -------------------------------------------------------------------------------- -Dependency : go.opentelemetry.io/collector/receiver +Dependency : go.opentelemetry.io/collector/consumer Version: v0.109.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/receiver@v0.109.0/LICENSE: +Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/consumer@v0.109.0/LICENSE: Apache License @@ -25949,477 +24955,12 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/rece -------------------------------------------------------------------------------- -Dependency : go.uber.org/multierr -Version: v1.11.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/go.uber.org/multierr@v1.11.0/LICENSE.txt: - -Copyright (c) 2017-2021 Uber Technologies, Inc. - -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 : go.uber.org/zap -Version: v1.27.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/go.uber.org/zap@v1.27.0/LICENSE: - -Copyright (c) 2016-2017 Uber Technologies, Inc. - -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 : golang.org/x/crypto -Version: v0.27.0 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/golang.org/x/crypto@v0.27.0/LICENSE: - -Copyright 2009 The Go Authors. - -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 LLC 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 : golang.org/x/mod -Version: v0.21.0 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/golang.org/x/mod@v0.21.0/LICENSE: - -Copyright 2009 The Go Authors. - -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 LLC 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 : golang.org/x/net -Version: v0.29.0 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/golang.org/x/net@v0.29.0/LICENSE: - -Copyright 2009 The Go Authors. - -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 LLC 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 : golang.org/x/oauth2 -Version: v0.22.0 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/golang.org/x/oauth2@v0.22.0/LICENSE: - -Copyright 2009 The Go Authors. - -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 LLC 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 : golang.org/x/sync -Version: v0.8.0 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/golang.org/x/sync@v0.8.0/LICENSE: - -Copyright 2009 The Go Authors. - -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 LLC 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 : golang.org/x/sys -Version: v0.25.0 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/golang.org/x/sys@v0.25.0/LICENSE: - -Copyright 2009 The Go Authors. - -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 LLC 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 : golang.org/x/term -Version: v0.24.0 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/golang.org/x/term@v0.24.0/LICENSE: - -Copyright 2009 The Go Authors. - -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 LLC 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 : golang.org/x/text -Version: v0.18.0 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/golang.org/x/text@v0.18.0/LICENSE: - -Copyright 2009 The Go Authors. - -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 LLC 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 : golang.org/x/time -Version: v0.6.0 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/golang.org/x/time@v0.6.0/LICENSE: - -Copyright 2009 The Go Authors. - -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 LLC 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 : golang.org/x/tools -Version: v0.25.0 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/golang.org/x/tools@v0.25.0/LICENSE: - -Copyright 2009 The Go Authors. - -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 LLC 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 : google.golang.org/api -Version: v0.191.0 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/google.golang.org/api@v0.191.0/LICENSE: - -Copyright (c) 2011 Google 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: - - * 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 : google.golang.org/genproto/googleapis/api -Version: v0.0.0-20240725223205-93522f1f2a9f +Dependency : go.opentelemetry.io/collector/pdata +Version: v1.15.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/google.golang.org/genproto/googleapis/api@v0.0.0-20240725223205-93522f1f2a9f/LICENSE: +Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/pdata@v1.15.0/LICENSE: Apache License @@ -26626,12 +25167,12 @@ Contents of probable licence file $GOMODCACHE/google.golang.org/genproto/googlea -------------------------------------------------------------------------------- -Dependency : google.golang.org/grpc -Version: v1.66.0 +Dependency : go.opentelemetry.io/collector/receiver +Version: v0.109.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/google.golang.org/grpc@v1.66.0/LICENSE: +Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/receiver@v0.109.0/LICENSE: Apache License @@ -26838,98 +25379,24 @@ Contents of probable licence file $GOMODCACHE/google.golang.org/grpc@v1.66.0/LIC -------------------------------------------------------------------------------- -Dependency : google.golang.org/protobuf -Version: v1.34.2 -Licence type (autodetected): BSD-3-Clause +Dependency : go.uber.org/mock +Version: v0.5.0 +Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/google.golang.org/protobuf@v1.34.2/LICENSE: - -Copyright (c) 2018 The Go Authors. All rights reserved. +Contents of probable licence file $GOMODCACHE/go.uber.org/mock@v0.5.0/LICENSE: -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. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -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. + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + 1. Definitions. --------------------------------------------------------------------------------- -Dependency : gopkg.in/inf.v0 -Version: v0.9.1 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/gopkg.in/inf.v0@v0.9.1/LICENSE: - -Copyright (c) 2012 Péter Surányi. Portions Copyright (c) 2009 The Go -Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - --------------------------------------------------------------------------------- -Dependency : gopkg.in/jcmturner/gokrb5.v7 -Version: v7.5.0 -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/gopkg.in/jcmturner/gokrb5.v7@v7.5.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. + "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. @@ -27100,7 +25567,7 @@ Contents of probable licence file $GOMODCACHE/gopkg.in/jcmturner/gokrb5.v7@v7.5. 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 "{}" + 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 @@ -27108,7 +25575,7 @@ Contents of probable licence file $GOMODCACHE/gopkg.in/jcmturner/gokrb5.v7@v7.5. same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright {yyyy} {name of copyright owner} + 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. @@ -27124,16 +25591,43 @@ Contents of probable licence file $GOMODCACHE/gopkg.in/jcmturner/gokrb5.v7@v7.5. -------------------------------------------------------------------------------- -Dependency : gopkg.in/natefinch/lumberjack.v2 -Version: v2.2.1 +Dependency : go.uber.org/multierr +Version: v1.11.0 Licence type (autodetected): MIT -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/gopkg.in/natefinch/lumberjack.v2@v2.2.1/LICENSE: +Contents of probable licence file $GOMODCACHE/go.uber.org/multierr@v1.11.0/LICENSE.txt: -The MIT License (MIT) +Copyright (c) 2017-2021 Uber Technologies, Inc. -Copyright (c) 2014 Nate Finch +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 : go.uber.org/zap +Version: v1.27.0 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/go.uber.org/zap@v1.27.0/LICENSE: + +Copyright (c) 2016-2017 Uber Technologies, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -27142,24 +25636,433 @@ 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 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. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + -------------------------------------------------------------------------------- -Dependency : gopkg.in/yaml.v2 -Version: v2.4.0 +Dependency : golang.org/x/crypto +Version: v0.28.0 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/golang.org/x/crypto@v0.28.0/LICENSE: + +Copyright 2009 The Go Authors. + +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 LLC 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 : golang.org/x/mod +Version: v0.21.0 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/golang.org/x/mod@v0.21.0/LICENSE: + +Copyright 2009 The Go Authors. + +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 LLC 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 : golang.org/x/net +Version: v0.30.0 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/golang.org/x/net@v0.30.0/LICENSE: + +Copyright 2009 The Go Authors. + +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 LLC 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 : golang.org/x/oauth2 +Version: v0.22.0 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/golang.org/x/oauth2@v0.22.0/LICENSE: + +Copyright 2009 The Go Authors. + +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 LLC 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 : golang.org/x/sync +Version: v0.8.0 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/golang.org/x/sync@v0.8.0/LICENSE: + +Copyright 2009 The Go Authors. + +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 LLC 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 : golang.org/x/sys +Version: v0.26.0 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/golang.org/x/sys@v0.26.0/LICENSE: + +Copyright 2009 The Go Authors. + +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 LLC 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 : golang.org/x/term +Version: v0.25.0 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/golang.org/x/term@v0.25.0/LICENSE: + +Copyright 2009 The Go Authors. + +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 LLC 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 : golang.org/x/text +Version: v0.19.0 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/golang.org/x/text@v0.19.0/LICENSE: + +Copyright 2009 The Go Authors. + +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 LLC 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 : golang.org/x/time +Version: v0.6.0 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/golang.org/x/time@v0.6.0/LICENSE: + +Copyright 2009 The Go Authors. + +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 LLC 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 : golang.org/x/tools +Version: v0.25.0 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/golang.org/x/tools@v0.25.0/LICENSE: + +Copyright 2009 The Go Authors. + +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 LLC 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 : google.golang.org/api +Version: v0.191.0 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/google.golang.org/api@v0.191.0/LICENSE: + +Copyright (c) 2011 Google 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: + + * 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 : google.golang.org/genproto/googleapis/api +Version: v0.0.0-20240725223205-93522f1f2a9f Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/gopkg.in/yaml.v2@v2.4.0/LICENSE: +Contents of probable licence file $GOMODCACHE/google.golang.org/genproto/googleapis/api@v0.0.0-20240725223205-93522f1f2a9f/LICENSE: + Apache License Version 2.0, January 2004 @@ -27341,7 +26244,7 @@ Contents of probable licence file $GOMODCACHE/gopkg.in/yaml.v2@v2.4.0/LICENSE: 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 "{}" + 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 @@ -27349,7 +26252,7 @@ Contents of probable licence file $GOMODCACHE/gopkg.in/yaml.v2@v2.4.0/LICENSE: same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright {yyyy} {name of copyright owner} + 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. @@ -27365,12 +26268,12 @@ Contents of probable licence file $GOMODCACHE/gopkg.in/yaml.v2@v2.4.0/LICENSE: -------------------------------------------------------------------------------- -Dependency : gotest.tools/gotestsum -Version: v1.7.0 +Dependency : google.golang.org/grpc +Version: v1.66.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/gotest.tools/gotestsum@v1.7.0/LICENSE: +Contents of probable licence file $GOMODCACHE/google.golang.org/grpc@v1.66.0/LICENSE: Apache License @@ -27577,45 +26480,52 @@ Contents of probable licence file $GOMODCACHE/gotest.tools/gotestsum@v1.7.0/LICE -------------------------------------------------------------------------------- -Dependency : howett.net/plist -Version: v1.0.1 -Licence type (autodetected): BSD-2-Clause +Dependency : google.golang.org/protobuf +Version: v1.34.2 +Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/howett.net/plist@v1.0.1/LICENSE: +Contents of probable licence file $GOMODCACHE/google.golang.org/protobuf@v1.34.2/LICENSE: -Copyright (c) 2013, Dustin L. Howett. All rights reserved. +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: +modification, are permitted provided that the following conditions are +met: -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. 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. + * 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. +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. -The views and conclusions contained in the software and documentation are those -of the authors and should not be interpreted as representing official policies, -either expressed or implied, of the FreeBSD Project. -------------------------------------------------------------------------------- -Parts of this package were made available under the license covering -the Go language and all attended core libraries. That license follows. +Dependency : gopkg.in/inf.v0 +Version: v0.9.1 +Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Copyright (c) 2012 The Go Authors. All rights reserved. +Contents of probable licence file $GOMODCACHE/gopkg.in/inf.v0@v0.9.1/LICENSE: + +Copyright (c) 2012 Péter Surányi. Portions Copyright (c) 2009 The Go +Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -27645,225 +26555,42 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- -Dependency : k8s.io/api -Version: v0.29.5 -Licence type (autodetected): Apache-2.0 +Dependency : gopkg.in/natefinch/lumberjack.v2 +Version: v2.2.1 +Licence type (autodetected): MIT -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/k8s.io/api@v0.29.5/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. +Contents of probable licence file $GOMODCACHE/gopkg.in/natefinch/lumberjack.v2@v2.2.1/LICENSE: - Copyright [yyyy] [name of copyright owner] +The MIT License (MIT) - 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 +Copyright (c) 2014 Nate Finch - http://www.apache.org/licenses/LICENSE-2.0 +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: - 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. +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 : k8s.io/apimachinery -Version: v0.29.5 +Dependency : gopkg.in/yaml.v2 +Version: v2.4.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/k8s.io/apimachinery@v0.29.5/LICENSE: - +Contents of probable licence file $GOMODCACHE/gopkg.in/yaml.v2@v2.4.0/LICENSE: Apache License Version 2.0, January 2004 @@ -28045,7 +26772,7 @@ Contents of probable licence file $GOMODCACHE/k8s.io/apimachinery@v0.29.5/LICENS 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 "[]" + 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 @@ -28053,7 +26780,7 @@ Contents of probable licence file $GOMODCACHE/k8s.io/apimachinery@v0.29.5/LICENS same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + 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. @@ -28069,12 +26796,12 @@ Contents of probable licence file $GOMODCACHE/k8s.io/apimachinery@v0.29.5/LICENS -------------------------------------------------------------------------------- -Dependency : k8s.io/client-go -Version: v0.29.5 +Dependency : gotest.tools/gotestsum +Version: v1.7.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/k8s.io/client-go@v0.29.5/LICENSE: +Contents of probable licence file $GOMODCACHE/gotest.tools/gotestsum@v1.7.0/LICENSE: Apache License @@ -28281,455 +27008,80 @@ Contents of probable licence file $GOMODCACHE/k8s.io/client-go@v0.29.5/LICENSE: -------------------------------------------------------------------------------- -Dependency : kernel.org/pub/linux/libs/security/libcap/cap -Version: v1.2.57 -Licence type (autodetected): BSD-3-Clause +Dependency : howett.net/plist +Version: v1.0.1 +Licence type (autodetected): BSD-2-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/kernel.org/pub/linux/libs/security/libcap/cap@v1.2.57/License: - -Unless otherwise *explicitly* stated, the following text describes the -licensed conditions under which the contents of this libcap/cap release -may be used and distributed. - -The licensed conditions are one or the other of these two Licenses: - - - BSD 3-clause - - GPL v2.0 - -------------------------------------------------------------------------- -BSD 3-clause: -------------- - -Redistribution and use in source and binary forms of libcap/cap, with -or without modification, are permitted provided that the following -conditions are met: - -1. Redistributions of source code must retain any existing copyright - notice, and this entire permission notice in its entirety, - including the disclaimer of warranties. - -2. Redistributions in binary form must reproduce all prior and current - copyright notices, this list of conditions, and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - -3. The name of any author may not be used to endorse or promote - products derived from this software without their specific prior - written permission. - -THIS SOFTWARE IS PROVIDED ``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 AUTHOR(S) 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. - -------------------------------------------------------------------------- -GPL v2.0: ---------- - -ALTERNATIVELY, this product may be distributed under the terms of the -GNU General Public License (v2.0 - see below), in which case the -provisions of the GNU GPL are required INSTEAD OF the above -restrictions. (This clause is necessary due to a potential conflict -between the GNU GPL and the restrictions contained in a BSD-style -copyright.) - -------------------------- -Full text of gpl-2.0.txt: -------------------------- - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. +Contents of probable licence file $GOMODCACHE/howett.net/plist@v1.0.1/LICENSE: +Copyright (c) 2013, Dustin L. Howett. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. 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. -================================================================================ -Indirect dependencies +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. +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. -------------------------------------------------------------------------------- -Dependency : aqwari.net/xml -Version: v0.0.0-20210331023308-d9421b293817 -Licence type (autodetected): MIT +Parts of this package were made available under the license covering +the Go language and all attended core libraries. That license follows. -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/aqwari.net/xml@v0.0.0-20210331023308-d9421b293817/LICENSE: - -The MIT License (MIT) - -Copyright (c) 2015 David Arroyo +Copyright (c) 2012 The Go Authors. All rights reserved. -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: +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. + * 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. -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. +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 : cloud.google.com/go/auth -Version: v0.8.0 +Dependency : k8s.io/api +Version: v0.29.5 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/cloud.google.com/go/auth@v0.8.0/LICENSE: +Contents of probable licence file $GOMODCACHE/k8s.io/api@v0.29.5/LICENSE: Apache License @@ -28936,12 +27288,12 @@ Contents of probable licence file $GOMODCACHE/cloud.google.com/go/auth@v0.8.0/LI -------------------------------------------------------------------------------- -Dependency : cloud.google.com/go/auth/oauth2adapt -Version: v0.2.4 +Dependency : k8s.io/apimachinery +Version: v0.29.5 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/cloud.google.com/go/auth/oauth2adapt@v0.2.4/LICENSE: +Contents of probable licence file $GOMODCACHE/k8s.io/apimachinery@v0.29.5/LICENSE: Apache License @@ -29148,12 +27500,12 @@ Contents of probable licence file $GOMODCACHE/cloud.google.com/go/auth/oauth2ada -------------------------------------------------------------------------------- -Dependency : cloud.google.com/go/compute/metadata -Version: v0.5.0 +Dependency : k8s.io/client-go +Version: v0.29.5 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/cloud.google.com/go/compute/metadata@v0.5.0/LICENSE: +Contents of probable licence file $GOMODCACHE/k8s.io/client-go@v0.29.5/LICENSE: Apache License @@ -29360,19 +27712,462 @@ Contents of probable licence file $GOMODCACHE/cloud.google.com/go/compute/metada -------------------------------------------------------------------------------- -Dependency : cloud.google.com/go/datacatalog -Version: v1.20.5 -Licence type (autodetected): Apache-2.0 +Dependency : kernel.org/pub/linux/libs/security/libcap/cap +Version: v1.2.57 +Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/cloud.google.com/go/datacatalog@v1.20.5/LICENSE: - +Contents of probable licence file $GOMODCACHE/kernel.org/pub/linux/libs/security/libcap/cap@v1.2.57/License: - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ +Unless otherwise *explicitly* stated, the following text describes the +licensed conditions under which the contents of this libcap/cap release +may be used and distributed. - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +The licensed conditions are one or the other of these two Licenses: + + - BSD 3-clause + - GPL v2.0 + +------------------------------------------------------------------------- +BSD 3-clause: +------------- + +Redistribution and use in source and binary forms of libcap/cap, with +or without modification, are permitted provided that the following +conditions are met: + +1. Redistributions of source code must retain any existing copyright + notice, and this entire permission notice in its entirety, + including the disclaimer of warranties. + +2. Redistributions in binary form must reproduce all prior and current + copyright notices, this list of conditions, and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +3. The name of any author may not be used to endorse or promote + products derived from this software without their specific prior + written permission. + +THIS SOFTWARE IS PROVIDED ``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 AUTHOR(S) 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. + +------------------------------------------------------------------------- +GPL v2.0: +--------- + +ALTERNATIVELY, this product may be distributed under the terms of the +GNU General Public License (v2.0 - see below), in which case the +provisions of the GNU GPL are required INSTEAD OF the above +restrictions. (This clause is necessary due to a potential conflict +between the GNU GPL and the restrictions contained in a BSD-style +copyright.) + +------------------------- +Full text of gpl-2.0.txt: +------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. + + + + +================================================================================ +Indirect dependencies + + +-------------------------------------------------------------------------------- +Dependency : aqwari.net/xml +Version: v0.0.0-20210331023308-d9421b293817 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/aqwari.net/xml@v0.0.0-20210331023308-d9421b293817/LICENSE: + +The MIT License (MIT) + +Copyright (c) 2015 David Arroyo + +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 : cloud.google.com/go/auth +Version: v0.8.0 +Licence type (autodetected): Apache-2.0 +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/cloud.google.com/go/auth@v0.8.0/LICENSE: + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. @@ -29572,12 +28367,12 @@ Contents of probable licence file $GOMODCACHE/cloud.google.com/go/datacatalog@v1 -------------------------------------------------------------------------------- -Dependency : cloud.google.com/go/iam -Version: v1.1.12 +Dependency : cloud.google.com/go/auth/oauth2adapt +Version: v0.2.4 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/cloud.google.com/go/iam@v1.1.12/LICENSE: +Contents of probable licence file $GOMODCACHE/cloud.google.com/go/auth/oauth2adapt@v0.2.4/LICENSE: Apache License @@ -29784,12 +28579,12 @@ Contents of probable licence file $GOMODCACHE/cloud.google.com/go/iam@v1.1.12/LI -------------------------------------------------------------------------------- -Dependency : cloud.google.com/go/kms -Version: v1.18.4 +Dependency : cloud.google.com/go/compute/metadata +Version: v0.5.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/cloud.google.com/go/kms@v1.18.4/LICENSE: +Contents of probable licence file $GOMODCACHE/cloud.google.com/go/compute/metadata@v0.5.0/LICENSE: Apache License @@ -29996,12 +28791,12 @@ Contents of probable licence file $GOMODCACHE/cloud.google.com/go/kms@v1.18.4/LI -------------------------------------------------------------------------------- -Dependency : cloud.google.com/go/longrunning -Version: v0.5.11 +Dependency : cloud.google.com/go/datacatalog +Version: v1.20.5 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/cloud.google.com/go/longrunning@v0.5.11/LICENSE: +Contents of probable licence file $GOMODCACHE/cloud.google.com/go/datacatalog@v1.20.5/LICENSE: Apache License @@ -30208,12 +29003,13 @@ Contents of probable licence file $GOMODCACHE/cloud.google.com/go/longrunning@v0 -------------------------------------------------------------------------------- -Dependency : code.cloudfoundry.org/go-diodes -Version: v0.0.0-20190809170250-f77fb823c7ee +Dependency : cloud.google.com/go/iam +Version: v1.1.12 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/code.cloudfoundry.org/go-diodes@v0.0.0-20190809170250-f77fb823c7ee/LICENSE: +Contents of probable licence file $GOMODCACHE/cloud.google.com/go/iam@v1.1.12/LICENSE: + Apache License Version 2.0, January 2004 @@ -30417,13 +29213,14 @@ Contents of probable licence file $GOMODCACHE/code.cloudfoundry.org/go-diodes@v0 See the License for the specific language governing permissions and limitations under the License. + -------------------------------------------------------------------------------- -Dependency : code.cloudfoundry.org/gofileutils -Version: v0.0.0-20170111115228-4d0c80011a0f +Dependency : cloud.google.com/go/kms +Version: v1.18.4 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/code.cloudfoundry.org/gofileutils@v0.0.0-20170111115228-4d0c80011a0f/LICENSE: +Contents of probable licence file $GOMODCACHE/cloud.google.com/go/kms@v1.18.4/LICENSE: Apache License @@ -30630,47 +29427,13 @@ Contents of probable licence file $GOMODCACHE/code.cloudfoundry.org/gofileutils@ -------------------------------------------------------------------------------- -Dependency : code.cloudfoundry.org/rfc5424 -Version: v0.0.0-20180905210152-236a6d29298a -Licence type (autodetected): BSD-2-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/code.cloudfoundry.org/rfc5424@v0.0.0-20180905210152-236a6d29298a/LICENSE: - -BSD 2-Clause License - -Copyright (c) 2016, Ross Kinder -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. - -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 HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - --------------------------------------------------------------------------------- -Dependency : github.com/AdaLogics/go-fuzz-headers -Version: v0.0.0-20230811130428-ced1acdcaa24 +Dependency : cloud.google.com/go/longrunning +Version: v0.5.11 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/!ada!logics/go-fuzz-headers@v0.0.0-20230811130428-ced1acdcaa24/LICENSE: +Contents of probable licence file $GOMODCACHE/cloud.google.com/go/longrunning@v0.5.11/LICENSE: + Apache License Version 2.0, January 2004 @@ -30876,289 +29639,12 @@ Contents of probable licence file $GOMODCACHE/github.com/!ada!logics/go-fuzz-hea -------------------------------------------------------------------------------- -Dependency : github.com/Azure/azure-amqp-common-go/v4 -Version: v4.2.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/!azure/azure-amqp-common-go/v4@v4.2.0/LICENSE: - - MIT License - - Copyright (c) Microsoft Corporation. All rights reserved. - - 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/Azure/azure-pipeline-go -Version: v0.2.3 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/!azure/azure-pipeline-go@v0.2.3/LICENSE: - - MIT License - - Copyright (c) Microsoft Corporation. All rights reserved. - - 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/Azure/azure-sdk-for-go/sdk/internal -Version: v1.10.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/!azure/azure-sdk-for-go/sdk/internal@v1.10.0/LICENSE.txt: - -MIT License - -Copyright (c) Microsoft Corporation. - -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/Azure/azure-sdk-for-go/sdk/resourcemanager/eventhub/armeventhub -Version: v1.2.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/!azure/azure-sdk-for-go/sdk/resourcemanager/eventhub/armeventhub@v1.2.0/LICENSE.txt: - -MIT License - -Copyright (c) Microsoft Corporation. All rights reserved. - -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/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 -Version: v2.0.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/!azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2@v2.0.0/LICENSE.txt: - -MIT License - -Copyright (c) Microsoft Corporation. - -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/Azure/azure-sdk-for-go/sdk/resourcemanager/managementgroups/armmanagementgroups -Version: v1.0.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/!azure/azure-sdk-for-go/sdk/resourcemanager/managementgroups/armmanagementgroups@v1.0.0/LICENSE.txt: - -MIT License - -Copyright (c) Microsoft Corporation. All rights reserved. - -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/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage -Version: v1.6.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/!azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage@v1.6.0/LICENSE.txt: - -MIT License - -Copyright (c) Microsoft Corporation. All rights reserved. - -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/Azure/go-amqp -Version: v1.0.5 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/!azure/go-amqp@v1.0.5/LICENSE: - - MIT License - - Copyright (C) 2017 Kale Blankenship - Portions Copyright (C) Microsoft Corporation - - 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/Azure/go-ansiterm -Version: v0.0.0-20230124172434-306776ec8161 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/!azure/go-ansiterm@v0.0.0-20230124172434-306776ec8161/LICENSE: - -The MIT License (MIT) - -Copyright (c) 2015 Microsoft Corporation - -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/Azure/go-autorest -Version: v14.2.0+incompatible +Dependency : code.cloudfoundry.org/go-diodes +Version: v0.0.0-20190809170250-f77fb823c7ee Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest@v14.2.0+incompatible/LICENSE: - +Contents of probable licence file $GOMODCACHE/code.cloudfoundry.org/go-diodes@v0.0.0-20190809170250-f77fb823c7ee/LICENSE: Apache License Version 2.0, January 2004 @@ -31337,7 +29823,18 @@ Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest@v14. END OF TERMS AND CONDITIONS - Copyright 2015 Microsoft Corporation + 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. @@ -31351,14 +29848,13 @@ Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest@v14. See the License for the specific language governing permissions and limitations under the License. - -------------------------------------------------------------------------------- -Dependency : github.com/Azure/go-autorest/autorest/azure/auth -Version: v0.4.2 +Dependency : code.cloudfoundry.org/gofileutils +Version: v0.0.0-20170111115228-4d0c80011a0f Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/autorest/azure/auth@v0.4.2/LICENSE: +Contents of probable licence file $GOMODCACHE/code.cloudfoundry.org/gofileutils@v0.0.0-20170111115228-4d0c80011a0f/LICENSE: Apache License @@ -31538,7 +30034,18 @@ Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/auto END OF TERMS AND CONDITIONS - Copyright 2015 Microsoft Corporation + 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. @@ -31554,13 +30061,47 @@ Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/auto -------------------------------------------------------------------------------- -Dependency : github.com/Azure/go-autorest/autorest/azure/cli -Version: v0.3.1 -Licence type (autodetected): Apache-2.0 +Dependency : code.cloudfoundry.org/rfc5424 +Version: v0.0.0-20180905210152-236a6d29298a +Licence type (autodetected): BSD-2-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/autorest/azure/cli@v0.3.1/LICENSE: +Contents of probable licence file $GOMODCACHE/code.cloudfoundry.org/rfc5424@v0.0.0-20180905210152-236a6d29298a/LICENSE: + +BSD 2-Clause License + +Copyright (c) 2016, Ross Kinder +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. + +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 HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +-------------------------------------------------------------------------------- +Dependency : github.com/AdaLogics/go-fuzz-headers +Version: v0.0.0-20230811130428-ced1acdcaa24 +Licence type (autodetected): Apache-2.0 +-------------------------------------------------------------------------------- +Contents of probable licence file $GOMODCACHE/github.com/!ada!logics/go-fuzz-headers@v0.0.0-20230811130428-ced1acdcaa24/LICENSE: Apache License Version 2.0, January 2004 @@ -31739,7 +30280,18 @@ Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/auto END OF TERMS AND CONDITIONS - Copyright 2015 Microsoft Corporation + 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. @@ -31755,12 +30307,348 @@ Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/auto -------------------------------------------------------------------------------- -Dependency : github.com/Azure/go-autorest/autorest/mocks -Version: v0.4.2 +Dependency : github.com/Azure/azure-amqp-common-go/v4 +Version: v4.2.0 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/!azure/azure-amqp-common-go/v4@v4.2.0/LICENSE: + + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + 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/Azure/azure-pipeline-go +Version: v0.2.3 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/!azure/azure-pipeline-go@v0.2.3/LICENSE: + + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + 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/Azure/azure-sdk-for-go/sdk/internal +Version: v1.10.0 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/!azure/azure-sdk-for-go/sdk/internal@v1.10.0/LICENSE.txt: + +MIT License + +Copyright (c) Microsoft Corporation. + +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/Azure/azure-sdk-for-go/sdk/resourcemanager/eventhub/armeventhub +Version: v1.2.0 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/!azure/azure-sdk-for-go/sdk/resourcemanager/eventhub/armeventhub@v1.2.0/LICENSE.txt: + +MIT License + +Copyright (c) Microsoft Corporation. All rights reserved. + +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/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 +Version: v2.0.0 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/!azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2@v2.0.0/LICENSE.txt: + +MIT License + +Copyright (c) Microsoft Corporation. + +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/Azure/azure-sdk-for-go/sdk/resourcemanager/managementgroups/armmanagementgroups +Version: v1.0.0 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/!azure/azure-sdk-for-go/sdk/resourcemanager/managementgroups/armmanagementgroups@v1.0.0/LICENSE.txt: + +MIT License + +Copyright (c) Microsoft Corporation. All rights reserved. + +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/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage +Version: v1.6.0 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/!azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage@v1.6.0/LICENSE.txt: + +MIT License + +Copyright (c) Microsoft Corporation. All rights reserved. + +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/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys +Version: v1.0.1 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/!azure/azure-sdk-for-go/sdk/security/keyvault/azkeys@v1.0.1/LICENSE.txt: + + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + 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/Azure/azure-sdk-for-go/sdk/security/keyvault/internal +Version: v1.0.0 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/!azure/azure-sdk-for-go/sdk/security/keyvault/internal@v1.0.0/LICENSE.txt: + + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + 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/Azure/go-amqp +Version: v1.0.5 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/!azure/go-amqp@v1.0.5/LICENSE: + + MIT License + + Copyright (C) 2017 Kale Blankenship + Portions Copyright (C) Microsoft Corporation + + 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/Azure/go-ansiterm +Version: v0.0.0-20230124172434-306776ec8161 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/!azure/go-ansiterm@v0.0.0-20230124172434-306776ec8161/LICENSE: + +The MIT License (MIT) + +Copyright (c) 2015 Microsoft Corporation + +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/Azure/go-autorest +Version: v14.2.0+incompatible Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/autorest/mocks@v0.4.2/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest@v14.2.0+incompatible/LICENSE: Apache License @@ -31956,12 +30844,12 @@ Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/auto -------------------------------------------------------------------------------- -Dependency : github.com/Azure/go-autorest/autorest/to -Version: v0.4.0 +Dependency : github.com/Azure/go-autorest/autorest/azure/auth +Version: v0.4.2 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/autorest/to@v0.4.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/autorest/azure/auth@v0.4.2/LICENSE: Apache License @@ -32157,12 +31045,12 @@ Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/auto -------------------------------------------------------------------------------- -Dependency : github.com/Azure/go-autorest/autorest/validation +Dependency : github.com/Azure/go-autorest/autorest/azure/cli Version: v0.3.1 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/autorest/validation@v0.3.1/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/autorest/azure/cli@v0.3.1/LICENSE: Apache License @@ -32358,12 +31246,12 @@ Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/auto -------------------------------------------------------------------------------- -Dependency : github.com/Azure/go-autorest/logger -Version: v0.2.1 +Dependency : github.com/Azure/go-autorest/autorest/mocks +Version: v0.4.2 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/logger@v0.2.1/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/autorest/mocks@v0.4.2/LICENSE: Apache License @@ -32559,12 +31447,12 @@ Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/logg -------------------------------------------------------------------------------- -Dependency : github.com/Azure/go-autorest/tracing -Version: v0.6.0 +Dependency : github.com/Azure/go-autorest/autorest/to +Version: v0.4.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/tracing@v0.6.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/autorest/to@v0.4.0/LICENSE: Apache License @@ -32760,278 +31648,213 @@ Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/trac -------------------------------------------------------------------------------- -Dependency : github.com/Azure/go-ntlmssp -Version: v0.0.0-20221128193559-754e69321358 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/!azure/go-ntlmssp@v0.0.0-20221128193559-754e69321358/LICENSE: - -The MIT License (MIT) - -Copyright (c) 2016 Microsoft - -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/AzureAD/microsoft-authentication-library-for-go -Version: v1.2.2 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/!azure!a!d/microsoft-authentication-library-for-go@v1.2.2/LICENSE: - - MIT License - - Copyright (c) Microsoft Corporation. - - 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/JohnCGriffin/overflow -Version: v0.0.0-20211019200055-46fa312c352c -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -No licence file provided. - --------------------------------------------------------------------------------- -Dependency : github.com/Masterminds/semver -Version: v1.5.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/!masterminds/semver@v1.5.0/LICENSE.txt: - -Copyright (C) 2014-2019, Matt Butcher and Matt Farina - -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/Shopify/toxiproxy -Version: v2.1.4+incompatible -Licence type (autodetected): MIT +Dependency : github.com/Azure/go-autorest/autorest/validation +Version: v0.3.1 +Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/!shopify/toxiproxy@v2.1.4+incompatible/LICENSE: - -The MIT License (MIT) +Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/autorest/validation@v0.3.1/LICENSE: -Copyright (c) 2014 Shopify -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: + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -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. + 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. --------------------------------------------------------------------------------- -Dependency : github.com/akavel/rsrc -Version: v0.8.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- + "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. -Contents of probable licence file $GOMODCACHE/github.com/akavel/rsrc@v0.8.0/LICENSE.txt: + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. -The MIT License (MIT) - -Copyright (c) 2013-2017 The rsrc Authors. - -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. + "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. --------------------------------------------------------------------------------- -Dependency : github.com/alexbrainman/sspi -Version: v0.0.0-20210105120005-909beea2cc74 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- + "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). -Contents of probable licence file $GOMODCACHE/github.com/alexbrainman/sspi@v0.0.0-20210105120005-909beea2cc74/LICENSE: + "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. -Copyright (c) 2012 The Go Authors. All rights reserved. + "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." -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: + "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. - * 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. + 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. -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. + 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: --------------------------------------------------------------------------------- -Dependency : github.com/andybalholm/brotli -Version: v1.0.5 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and -Contents of probable licence file $GOMODCACHE/github.com/andybalholm/brotli@v1.0.5/LICENSE: + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. + (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 -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: + (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. -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. + 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. -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. + 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. --------------------------------------------------------------------------------- -Dependency : github.com/antlr4-go/antlr/v4 -Version: v4.13.0 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- + 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. -Contents of probable licence file $GOMODCACHE/github.com/antlr4-go/antlr/v4@v4.13.0/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. -Copyright (c) 2012-2023 The ANTLR Project. All rights reserved. + 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. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: + END OF TERMS AND CONDITIONS -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. + Copyright 2015 Microsoft Corporation -2. 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. + 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 -3. Neither name of copyright holders nor the names of its contributors -may be used to endorse or promote products derived from this software -without specific prior written permission. + http://www.apache.org/licenses/LICENSE-2.0 -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 REGENTS 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. + 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/apache/arrow/go/v15 -Version: v15.0.2 +Dependency : github.com/Azure/go-autorest/logger +Version: v0.2.1 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/apache/arrow/go/v15@v15.0.2/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/logger@v0.2.1/LICENSE: Apache License @@ -33211,18 +32034,7 @@ Contents of probable licence file $GOMODCACHE/github.com/apache/arrow/go/v15@v15 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] + Copyright 2015 Microsoft Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -33236,210 +32048,381 @@ Contents of probable licence file $GOMODCACHE/github.com/apache/arrow/go/v15@v15 See the License for the specific language governing permissions and limitations under the License. --------------------------------------------------------------------------------- - -src/arrow/util (some portions): Apache 2.0, and 3-clause BSD - -Some portions of this module are derived from code in the Chromium project, -copyright (c) Google inc and (c) The Chromium Authors and licensed under the -Apache 2.0 License or the under the 3-clause BSD license: - - Copyright (c) 2013 The Chromium Authors. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- +Dependency : github.com/Azure/go-autorest/tracing +Version: v0.6.0 +Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -This project includes code from Daniel Lemire's FrameOfReference project. +Contents of probable licence file $GOMODCACHE/github.com/!azure/go-autorest/tracing@v0.6.0/LICENSE: -https://github.com/lemire/FrameOfReference/blob/6ccaf9e97160f9a3b299e23a8ef739e711ef0c71/src/bpacking.cpp -Copyright: 2013 Daniel Lemire -Home page: http://lemire.me/en/ -Project page: https://github.com/lemire/FrameOfReference -License: Apache License Version 2.0 http://www.apache.org/licenses/LICENSE-2.0 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ --------------------------------------------------------------------------------- + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -This project includes code from the TensorFlow project + 1. Definitions. -Copyright 2015 The TensorFlow Authors. All Rights Reserved. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. -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 + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. - http://www.apache.org/licenses/LICENSE-2.0 + "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. -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. + "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. -This project includes code from the NumPy project. + "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. -https://github.com/numpy/numpy/blob/e1f191c46f2eebd6cb892a4bfe14d9dd43a06c4e/numpy/core/src/multiarray/multiarraymodule.c#L2910 + "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). -https://github.com/numpy/numpy/blob/68fd82271b9ea5a9e50d4e761061dfcca851382a/numpy/core/src/multiarray/datetime.c + "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. -Copyright (c) 2005-2017, NumPy Developers. -All rights reserved. + "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." -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: + "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. - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + 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. - * 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. + 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. - * Neither the name of the NumPy Developers nor the names of any - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. + 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: -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. + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2015 Microsoft Corporation + + 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/Azure/go-ntlmssp +Version: v0.0.0-20221128193559-754e69321358 +Licence type (autodetected): MIT -------------------------------------------------------------------------------- -This project includes code from the Boost project +Contents of probable licence file $GOMODCACHE/github.com/!azure/go-ntlmssp@v0.0.0-20221128193559-754e69321358/LICENSE: -Boost Software License - Version 1.0 - August 17th, 2003 +The MIT License (MIT) -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: +Copyright (c) 2016 Microsoft -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. +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/AzureAD/microsoft-authentication-library-for-go +Version: v1.2.2 +Licence type (autodetected): MIT -------------------------------------------------------------------------------- -This project includes code from the FlatBuffers project +Contents of probable licence file $GOMODCACHE/github.com/!azure!a!d/microsoft-authentication-library-for-go@v1.2.2/LICENSE: -Copyright 2014 Google Inc. + MIT License + + Copyright (c) Microsoft Corporation. + + 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 -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 +-------------------------------------------------------------------------------- +Dependency : github.com/IBM/sarama +Version: v1.43.3 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- -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. +Contents of probable licence file $GOMODCACHE/github.com/!i!b!m/sarama@v1.43.3/LICENSE.md: --------------------------------------------------------------------------------- +# MIT License -This project includes code from the tslib project +Copyright (c) 2013 Shopify -Copyright 2015 Microsoft Corporation. All rights reserved. +Copyright (c) 2023 IBM Corporation -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 +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: - http://www.apache.org/licenses/LICENSE-2.0 +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. -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/JohnCGriffin/overflow +Version: v0.0.0-20211019200055-46fa312c352c +Licence type (autodetected): MIT -------------------------------------------------------------------------------- -This project includes code from the jemalloc project +No licence file provided. -https://github.com/jemalloc/jemalloc +-------------------------------------------------------------------------------- +Dependency : github.com/Masterminds/semver +Version: v1.5.0 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- -Copyright (C) 2002-2017 Jason Evans . -All rights reserved. -Copyright (C) 2007-2012 Mozilla Foundation. All rights reserved. -Copyright (C) 2009-2017 Facebook, Inc. All rights reserved. +Contents of probable licence file $GOMODCACHE/github.com/!masterminds/semver@v1.5.0/LICENSE.txt: + +Copyright (C) 2014-2019, Matt Butcher and Matt Farina + +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. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright notice(s), - this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice(s), - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- +Dependency : github.com/akavel/rsrc +Version: v0.8.0 +Licence type (autodetected): MIT -------------------------------------------------------------------------------- -This project includes code from the Go project, BSD 3-clause license + PATENTS -weak patent termination clause -(https://github.com/golang/go/blob/master/PATENTS). +Contents of probable licence file $GOMODCACHE/github.com/akavel/rsrc@v0.8.0/LICENSE.txt: -Copyright (c) 2009 The Go Authors. All rights reserved. +The MIT License (MIT) + +Copyright (c) 2013-2017 The rsrc Authors. + +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/alexbrainman/sspi +Version: v0.0.0-20210105120005-909beea2cc74 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/alexbrainman/sspi@v0.0.0-20210105120005-909beea2cc74/LICENSE: + +Copyright (c) 2012 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 @@ -33467,327 +32450,394 @@ 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. --------------------------------------------------------------------------------- - -This project includes code from the hs2client - -https://github.com/cloudera/hs2client - -Copyright 2016 Cloudera Inc. - -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/andybalholm/brotli +Version: v1.1.0 +Licence type (autodetected): MIT -------------------------------------------------------------------------------- -The script ci/scripts/util_wait_for_it.sh has the following license +Contents of probable licence file $GOMODCACHE/github.com/andybalholm/brotli@v1.1.0/LICENSE: -Copyright (c) 2016 Giles Hall +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. -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: +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 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 +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. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +-------------------------------------------------------------------------------- +Dependency : github.com/antlr4-go/antlr/v4 +Version: v4.13.0 +Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -The script r/configure has the following license (MIT) +Contents of probable licence file $GOMODCACHE/github.com/antlr4-go/antlr/v4@v4.13.0/LICENSE: -Copyright (c) 2017, Jeroen Ooms and Jim Hester +Copyright (c) 2012-2023 The ANTLR Project. All rights reserved. -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: +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. -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. +2. 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. --------------------------------------------------------------------------------- +3. Neither name of copyright holders nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. -cpp/src/arrow/util/logging.cc, cpp/src/arrow/util/logging.h and -cpp/src/arrow/util/logging-test.cc are adapted from -Ray Project (https://github.com/ray-project/ray) (Apache 2.0). +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 REGENTS 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. -Copyright (c) 2016 Ray Project (https://github.com/ray-project/ray) -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 +-------------------------------------------------------------------------------- +Dependency : github.com/apache/arrow/go/v15 +Version: v15.0.2 +Licence type (autodetected): Apache-2.0 +-------------------------------------------------------------------------------- - http://www.apache.org/licenses/LICENSE-2.0 +Contents of probable licence file $GOMODCACHE/github.com/apache/arrow/go/v15@v15.0.2/LICENSE.txt: -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. --------------------------------------------------------------------------------- -The files cpp/src/arrow/vendored/datetime/date.h, cpp/src/arrow/vendored/datetime/tz.h, -cpp/src/arrow/vendored/datetime/tz_private.h, cpp/src/arrow/vendored/datetime/ios.h, -cpp/src/arrow/vendored/datetime/ios.mm, -cpp/src/arrow/vendored/datetime/tz.cpp are adapted from -Howard Hinnant's date library (https://github.com/HowardHinnant/date) -It is licensed under MIT license. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -The MIT License (MIT) -Copyright (c) 2015, 2016, 2017 Howard Hinnant -Copyright (c) 2016 Adrian Colomitchi -Copyright (c) 2017 Florian Dang -Copyright (c) 2017 Paul Thompson -Copyright (c) 2018 Tomasz Kamiński + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -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: + 1. Definitions. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. -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. + "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. -The file cpp/src/arrow/util/utf8.h includes code adapted from the page - https://bjoern.hoehrmann.de/utf-8/decoder/dfa/ -with the following license (MIT) + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. -Copyright (c) 2008-2009 Bjoern Hoehrmann + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. -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: + "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. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + "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). -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. + "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." -The file cpp/src/arrow/vendored/string_view.hpp has the following license + "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. -Boost Software License - Version 1.0 - August 17th, 2003 + 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. -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: + 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. -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. + 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: -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, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. + (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 -The files in cpp/src/arrow/vendored/xxhash/ have the following license -(BSD 2-Clause License) + (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 -xxHash Library -Copyright (c) 2012-2014, Yann Collet -All rights reserved. + (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. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: + 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. -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. + 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. -* 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. + 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. -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 HOLDER 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. + 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. -You can contact the author at : -- xxHash homepage: http://www.xxhash.com -- xxHash source repository : https://github.com/Cyan4973/xxHash + 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. -------------------------------------------------------------------------------- -The files in cpp/src/arrow/vendored/double-conversion/ have the following license -(BSD 3-Clause License) +src/arrow/util (some portions): Apache 2.0, and 3-clause BSD -Copyright 2006-2011, the V8 project 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: +Some portions of this module are derived from code in the Chromium project, +copyright (c) Google inc and (c) The Chromium Authors and licensed under the +Apache 2.0 License or the under the 3-clause BSD license: - * 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. + Copyright (c) 2013 The Chromium Authors. All rights reserved. -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. + 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. -------------------------------------------------------------------------------- -The files in cpp/src/arrow/vendored/uriparser/ have the following license -(BSD 3-Clause License) +This project includes code from Daniel Lemire's FrameOfReference project. -uriparser - RFC 3986 URI parsing library +https://github.com/lemire/FrameOfReference/blob/6ccaf9e97160f9a3b299e23a8ef739e711ef0c71/src/bpacking.cpp -Copyright (C) 2007, Weijia Song -Copyright (C) 2007, Sebastian Pipping -All rights reserved. +Copyright: 2013 Daniel Lemire +Home page: http://lemire.me/en/ +Project page: https://github.com/lemire/FrameOfReference +License: Apache License Version 2.0 http://www.apache.org/licenses/LICENSE-2.0 -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. +This project includes code from the TensorFlow project - * 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. +Copyright 2015 The TensorFlow Authors. All Rights Reserved. - * Neither the name of the nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior written - permission. +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 -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. + 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. -------------------------------------------------------------------------------- -The files under dev/tasks/conda-recipes have the following license +This project includes code from the NumPy project. -BSD 3-clause license -Copyright (c) 2015-2018, conda-forge +https://github.com/numpy/numpy/blob/e1f191c46f2eebd6cb892a4bfe14d9dd43a06c4e/numpy/core/src/multiarray/multiarraymodule.c#L2910 + +https://github.com/numpy/numpy/blob/68fd82271b9ea5a9e50d4e761061dfcca851382a/numpy/core/src/multiarray/datetime.c + +Copyright (c) 2005-2017, NumPy Developers. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. -2. 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. + * 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. -3. Neither the name of the copyright holder nor the names of its contributors - may be used to endorse or promote products derived from this software without - specific prior written permission. + * Neither the name of the NumPy Developers nor the names of any + 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 HOLDER 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. +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. -------------------------------------------------------------------------------- -The files in cpp/src/arrow/vendored/utf8cpp/ have the following license +This project includes code from the Boost project -Copyright 2006 Nemanja Trifunovic +Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by @@ -33813,82 +32863,525 @@ DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- -This project includes code from Apache Kudu. - - * cpp/cmake_modules/CompilerInfo.cmake is based on Kudu's cmake_modules/CompilerInfo.cmake +This project includes code from the FlatBuffers project -Copyright: 2016 The Apache Software Foundation. -Home page: https://kudu.apache.org/ -License: http://www.apache.org/licenses/LICENSE-2.0 +Copyright 2014 Google Inc. --------------------------------------------------------------------------------- +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 -This project includes code from Apache Impala (incubating), formerly -Impala. The Impala code and rights were donated to the ASF as part of the -Incubator process after the initial code imports into Apache Parquet. + http://www.apache.org/licenses/LICENSE-2.0 -Copyright: 2012 Cloudera, Inc. -Copyright: 2016 The Apache Software Foundation. -Home page: http://impala.apache.org/ -License: 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. -------------------------------------------------------------------------------- -This project includes code from Apache Aurora. - -* dev/release/{release,changelog,release-candidate} are based on the scripts from - Apache Aurora - -Copyright: 2016 The Apache Software Foundation. -Home page: https://aurora.apache.org/ -License: http://www.apache.org/licenses/LICENSE-2.0 +This project includes code from the tslib project --------------------------------------------------------------------------------- +Copyright 2015 Microsoft Corporation. All rights reserved. -This project includes code from the Google styleguide. +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 -* cpp/build-support/cpplint.py is based on the scripts from the Google styleguide. + http://www.apache.org/licenses/LICENSE-2.0 -Copyright: 2009 Google Inc. All rights reserved. -Homepage: https://github.com/google/styleguide -License: 3-clause BSD +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. -------------------------------------------------------------------------------- -This project includes code from Snappy. - -* cpp/cmake_modules/{SnappyCMakeLists.txt,SnappyConfig.h} are based on code - from Google's Snappy project. - -Copyright: 2009 Google Inc. All rights reserved. -Homepage: https://github.com/google/snappy -License: 3-clause BSD - --------------------------------------------------------------------------------- +This project includes code from the jemalloc project -This project includes code from the manylinux project. +https://github.com/jemalloc/jemalloc -* python/manylinux1/scripts/{build_python.sh,python-tag-abi-tag.py, - requirements.txt} are based on code from the manylinux project. +Copyright (C) 2002-2017 Jason Evans . +All rights reserved. +Copyright (C) 2007-2012 Mozilla Foundation. All rights reserved. +Copyright (C) 2009-2017 Facebook, Inc. All rights reserved. -Copyright: 2016 manylinux -Homepage: https://github.com/pypa/manylinux -License: The MIT License (MIT) +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright notice(s), + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice(s), + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 HOLDER(S) 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. -------------------------------------------------------------------------------- -This project includes code from the cymove project: +This project includes code from the Go project, BSD 3-clause license + PATENTS +weak patent termination clause +(https://github.com/golang/go/blob/master/PATENTS). -* python/pyarrow/includes/common.pxd includes code from the cymove project +Copyright (c) 2009 The Go Authors. All rights reserved. -The MIT License (MIT) -Copyright (c) 2019 Omer Ozarslan +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: -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 + * 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. + +-------------------------------------------------------------------------------- + +This project includes code from the hs2client + +https://github.com/cloudera/hs2client + +Copyright 2016 Cloudera Inc. + +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. + +-------------------------------------------------------------------------------- + +The script ci/scripts/util_wait_for_it.sh has the following license + +Copyright (c) 2016 Giles Hall + +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. + +-------------------------------------------------------------------------------- + +The script r/configure has the following license (MIT) + +Copyright (c) 2017, Jeroen Ooms and Jim Hester + +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. + +-------------------------------------------------------------------------------- + +cpp/src/arrow/util/logging.cc, cpp/src/arrow/util/logging.h and +cpp/src/arrow/util/logging-test.cc are adapted from +Ray Project (https://github.com/ray-project/ray) (Apache 2.0). + +Copyright (c) 2016 Ray Project (https://github.com/ray-project/ray) + +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. + +-------------------------------------------------------------------------------- +The files cpp/src/arrow/vendored/datetime/date.h, cpp/src/arrow/vendored/datetime/tz.h, +cpp/src/arrow/vendored/datetime/tz_private.h, cpp/src/arrow/vendored/datetime/ios.h, +cpp/src/arrow/vendored/datetime/ios.mm, +cpp/src/arrow/vendored/datetime/tz.cpp are adapted from +Howard Hinnant's date library (https://github.com/HowardHinnant/date) +It is licensed under MIT license. + +The MIT License (MIT) +Copyright (c) 2015, 2016, 2017 Howard Hinnant +Copyright (c) 2016 Adrian Colomitchi +Copyright (c) 2017 Florian Dang +Copyright (c) 2017 Paul Thompson +Copyright (c) 2018 Tomasz Kamiński + +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. + +-------------------------------------------------------------------------------- + +The file cpp/src/arrow/util/utf8.h includes code adapted from the page + https://bjoern.hoehrmann.de/utf-8/decoder/dfa/ +with the following license (MIT) + +Copyright (c) 2008-2009 Bjoern Hoehrmann + +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. + +-------------------------------------------------------------------------------- + +The file cpp/src/arrow/vendored/string_view.hpp has the following license + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +-------------------------------------------------------------------------------- + +The files in cpp/src/arrow/vendored/xxhash/ have the following license +(BSD 2-Clause License) + +xxHash Library +Copyright (c) 2012-2014, Yann Collet +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. + +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 HOLDER 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. + +You can contact the author at : +- xxHash homepage: http://www.xxhash.com +- xxHash source repository : https://github.com/Cyan4973/xxHash + +-------------------------------------------------------------------------------- + +The files in cpp/src/arrow/vendored/double-conversion/ have the following license +(BSD 3-Clause License) + +Copyright 2006-2011, the V8 project 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. + +-------------------------------------------------------------------------------- + +The files in cpp/src/arrow/vendored/uriparser/ have the following license +(BSD 3-Clause License) + +uriparser - RFC 3986 URI parsing library + +Copyright (C) 2007, Weijia Song +Copyright (C) 2007, Sebastian Pipping +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + * Neither the name of the 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. + +-------------------------------------------------------------------------------- + +The files under dev/tasks/conda-recipes have the following license + +BSD 3-clause license +Copyright (c) 2015-2018, conda-forge +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder 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 HOLDER 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. + +-------------------------------------------------------------------------------- + +The files in cpp/src/arrow/vendored/utf8cpp/ have the following license + +Copyright 2006 Nemanja Trifunovic + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +-------------------------------------------------------------------------------- + +This project includes code from Apache Kudu. + + * cpp/cmake_modules/CompilerInfo.cmake is based on Kudu's cmake_modules/CompilerInfo.cmake + +Copyright: 2016 The Apache Software Foundation. +Home page: https://kudu.apache.org/ +License: http://www.apache.org/licenses/LICENSE-2.0 + +-------------------------------------------------------------------------------- + +This project includes code from Apache Impala (incubating), formerly +Impala. The Impala code and rights were donated to the ASF as part of the +Incubator process after the initial code imports into Apache Parquet. + +Copyright: 2012 Cloudera, Inc. +Copyright: 2016 The Apache Software Foundation. +Home page: http://impala.apache.org/ +License: http://www.apache.org/licenses/LICENSE-2.0 + +-------------------------------------------------------------------------------- + +This project includes code from Apache Aurora. + +* dev/release/{release,changelog,release-candidate} are based on the scripts from + Apache Aurora + +Copyright: 2016 The Apache Software Foundation. +Home page: https://aurora.apache.org/ +License: http://www.apache.org/licenses/LICENSE-2.0 + +-------------------------------------------------------------------------------- + +This project includes code from the Google styleguide. + +* cpp/build-support/cpplint.py is based on the scripts from the Google styleguide. + +Copyright: 2009 Google Inc. All rights reserved. +Homepage: https://github.com/google/styleguide +License: 3-clause BSD + +-------------------------------------------------------------------------------- + +This project includes code from Snappy. + +* cpp/cmake_modules/{SnappyCMakeLists.txt,SnappyConfig.h} are based on code + from Google's Snappy project. + +Copyright: 2009 Google Inc. All rights reserved. +Homepage: https://github.com/google/snappy +License: 3-clause BSD + +-------------------------------------------------------------------------------- + +This project includes code from the manylinux project. + +* python/manylinux1/scripts/{build_python.sh,python-tag-abi-tag.py, + requirements.txt} are based on code from the manylinux project. + +Copyright: 2016 manylinux +Homepage: https://github.com/pypa/manylinux +License: The MIT License (MIT) + +-------------------------------------------------------------------------------- + +This project includes code from the cymove project: + +* python/pyarrow/includes/common.pxd includes code from the cymove project + +The MIT License (MIT) +Copyright (c) 2019 Omer Ozarslan + +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 @@ -34828,11 +34321,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- Dependency : github.com/apache/thrift -Version: v0.19.0 +Version: v0.20.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/apache/thrift@v0.19.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/apache/thrift@v0.20.0/LICENSE: Apache License @@ -38219,12 +37712,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -------------------------------------------------------------------------------- -Dependency : github.com/dgraph-io/ristretto -Version: v0.1.2-0.20240116140435-c67e07994f91 +Dependency : github.com/dgraph-io/ristretto/v2 +Version: v2.0.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/dgraph-io/ristretto@v0.1.2-0.20240116140435-c67e07994f91/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/dgraph-io/ristretto/v2@v2.0.0/LICENSE: Apache License Version 2.0, January 2004 @@ -39130,11 +38623,11 @@ Contents of probable licence file $GOMODCACHE/github.com/docker/go-metrics@v0.0. -------------------------------------------------------------------------------- Dependency : github.com/eapache/go-xerial-snappy -Version: v0.0.0-20180814174437-776d5712da21 +Version: v0.0.0-20230731223053-c322873962e3 Licence type (autodetected): MIT -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/eapache/go-xerial-snappy@v0.0.0-20180814174437-776d5712da21/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/eapache/go-xerial-snappy@v0.0.0-20230731223053-c322873962e3/LICENSE: The MIT License (MIT) @@ -41463,11 +40956,11 @@ THE SOFTWARE. -------------------------------------------------------------------------------- Dependency : github.com/goccy/go-json -Version: v0.10.2 +Version: v0.10.3 Licence type (autodetected): MIT -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/goccy/go-json@v0.10.2/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/goccy/go-json@v0.10.3/LICENSE: MIT License @@ -41724,11 +41217,11 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI -------------------------------------------------------------------------------- Dependency : github.com/golang-sql/civil -Version: v0.0.0-20190719163853-cb61b32ac6fe +Version: v0.0.0-20220223132316-b832511892a9 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/golang-sql/civil@v0.0.0-20190719163853-cb61b32ac6fe/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/golang-sql/civil@v0.0.0-20220223132316-b832511892a9/LICENSE: Apache License @@ -42172,50 +41665,12 @@ third-party archives. -------------------------------------------------------------------------------- -Dependency : github.com/golang/protobuf -Version: v1.5.4 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/golang/protobuf@v1.5.4/LICENSE: - -Copyright 2010 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - --------------------------------------------------------------------------------- -Dependency : github.com/google/gnostic-models -Version: v0.6.8 +Dependency : github.com/golang/mock +Version: v1.6.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/google/gnostic-models@v0.6.8/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/golang/mock@v1.6.0/LICENSE: Apache License @@ -42421,28 +41876,27 @@ Contents of probable licence file $GOMODCACHE/github.com/google/gnostic-models@v limitations under the License. - -------------------------------------------------------------------------------- -Dependency : github.com/google/go-querystring -Version: v1.1.0 +Dependency : github.com/golang/protobuf +Version: v1.5.4 Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/google/go-querystring@v1.1.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/golang/protobuf@v1.5.4/LICENSE: -Copyright (c) 2013 Google. All rights reserved. +Copyright 2010 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 + * 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 + * 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 + * 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. @@ -42459,225 +41913,14 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------------- -Dependency : github.com/google/gofuzz -Version: v1.2.0 -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/google/gofuzz@v1.2.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 : github.com/google/licenseclassifier -Version: v0.0.0-20221004142553-c1ed8fcf4bab +Dependency : github.com/google/gnostic-models +Version: v0.6.8 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/google/licenseclassifier@v0.0.0-20221004142553-c1ed8fcf4bab/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/google/gnostic-models@v0.6.8/LICENSE: Apache License @@ -42883,13 +42126,51 @@ Contents of probable licence file $GOMODCACHE/github.com/google/licenseclassifie limitations under the License. + -------------------------------------------------------------------------------- -Dependency : github.com/google/martian/v3 -Version: v3.3.3 +Dependency : github.com/google/go-querystring +Version: v1.1.0 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/google/go-querystring@v1.1.0/LICENSE: + +Copyright (c) 2013 Google. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +-------------------------------------------------------------------------------- +Dependency : github.com/google/gofuzz +Version: v1.2.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/google/martian/v3@v3.3.3/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/google/gofuzz@v1.2.0/LICENSE: Apache License @@ -43096,12 +42377,12 @@ Contents of probable licence file $GOMODCACHE/github.com/google/martian/v3@v3.3. -------------------------------------------------------------------------------- -Dependency : github.com/google/pprof -Version: v0.0.0-20240711041743-f6c9dda6c6da +Dependency : github.com/google/licenseclassifier +Version: v0.0.0-20221004142553-c1ed8fcf4bab Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/google/pprof@v0.0.0-20240711041743-f6c9dda6c6da/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/google/licenseclassifier@v0.0.0-20221004142553-c1ed8fcf4bab/LICENSE: Apache License @@ -43308,12 +42589,12 @@ Contents of probable licence file $GOMODCACHE/github.com/google/pprof@v0.0.0-202 -------------------------------------------------------------------------------- -Dependency : github.com/google/s2a-go -Version: v0.1.8 +Dependency : github.com/google/martian/v3 +Version: v3.3.3 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/google/s2a-go@v0.1.8/LICENSE.md: +Contents of probable licence file $GOMODCACHE/github.com/google/martian/v3@v3.3.3/LICENSE: Apache License @@ -43520,12 +42801,12 @@ Contents of probable licence file $GOMODCACHE/github.com/google/s2a-go@v0.1.8/LI -------------------------------------------------------------------------------- -Dependency : github.com/google/shlex -Version: v0.0.0-20191202100458-e7afc7fbc510 +Dependency : github.com/google/pprof +Version: v0.0.0-20240711041743-f6c9dda6c6da Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/google/shlex@v0.0.0-20191202100458-e7afc7fbc510/COPYING: +Contents of probable licence file $GOMODCACHE/github.com/google/pprof@v0.0.0-20240711041743-f6c9dda6c6da/LICENSE: Apache License @@ -43732,49 +43013,12 @@ Contents of probable licence file $GOMODCACHE/github.com/google/shlex@v0.0.0-201 -------------------------------------------------------------------------------- -Dependency : github.com/google/uuid -Version: v1.6.0 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/google/uuid@v1.6.0/LICENSE: - -Copyright (c) 2009,2014 Google 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: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - --------------------------------------------------------------------------------- -Dependency : github.com/googleapis/enterprise-certificate-proxy -Version: v0.3.2 +Dependency : github.com/google/s2a-go +Version: v0.1.8 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/googleapis/enterprise-certificate-proxy@v0.3.2/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/google/s2a-go@v0.1.8/LICENSE.md: Apache License @@ -43981,189 +43225,12 @@ Contents of probable licence file $GOMODCACHE/github.com/googleapis/enterprise-c -------------------------------------------------------------------------------- -Dependency : github.com/gopherjs/gopherjs -Version: v0.0.0-20181017120253-0766667cb4d1 -Licence type (autodetected): BSD-2-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/gopherjs/gopherjs@v0.0.0-20181017120253-0766667cb4d1/LICENSE: - -Copyright (c) 2013 Richard Musiol. 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. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - --------------------------------------------------------------------------------- -Dependency : github.com/grafana/regexp -Version: v0.0.0-20240518133315-a468a5bfb3bc -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/grafana/regexp@v0.0.0-20240518133315-a468a5bfb3bc/LICENSE: - -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - --------------------------------------------------------------------------------- -Dependency : github.com/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. - -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 Gengo, Inc. nor the names of its - contributors may be used to endorse or promote products derived from this - software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - --------------------------------------------------------------------------------- -Dependency : github.com/grpc-ecosystem/grpc-gateway/v2 -Version: v2.20.0 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/grpc-ecosystem/grpc-gateway/v2@v2.20.0/LICENSE: - -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: - - * 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 Gengo, Inc. nor the names of its - contributors may be used to endorse or promote products derived from this - software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - --------------------------------------------------------------------------------- -Dependency : github.com/h2non/parth -Version: v0.0.0-20190131123155-b4df798d6542 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/h2non/parth@v0.0.0-20190131123155-b4df798d6542/LICENSE: - -The MIT License (MIT) - -Copyright (c) 2018 codemodus - -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/hashicorp/cronexpr -Version: v1.1.2 +Dependency : github.com/google/shlex +Version: v0.0.0-20191202100458-e7afc7fbc510 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/hashicorp/cronexpr@v1.1.2/APLv2: +Contents of probable licence file $GOMODCACHE/github.com/google/shlex@v0.0.0-20191202100458-e7afc7fbc510/COPYING: Apache License @@ -44370,464 +43437,812 @@ Contents of probable licence file $GOMODCACHE/github.com/hashicorp/cronexpr@v1.1 -------------------------------------------------------------------------------- -Dependency : github.com/hashicorp/errwrap -Version: v1.1.0 -Licence type (autodetected): MPL-2.0 +Dependency : github.com/google/uuid +Version: v1.6.0 +Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/hashicorp/errwrap@v1.1.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/google/uuid@v1.6.0/LICENSE: -Mozilla Public License, version 2.0 +Copyright (c) 2009,2014 Google Inc. All rights reserved. -1. Definitions +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: -1.1. “Contributor” + * 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. - means each individual or legal entity that creates, contributes to the - creation of, or owns Covered Software. +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. -1.2. “Contributor Version” - means the combination of the Contributions of others (if any) used by a - Contributor and that particular Contributor’s Contribution. +-------------------------------------------------------------------------------- +Dependency : github.com/googleapis/enterprise-certificate-proxy +Version: v0.3.2 +Licence type (autodetected): Apache-2.0 +-------------------------------------------------------------------------------- -1.3. “Contribution” +Contents of probable licence file $GOMODCACHE/github.com/googleapis/enterprise-certificate-proxy@v0.3.2/LICENSE: - means Covered Software of a particular Contributor. -1.4. “Covered Software” + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ - means Source Code Form to which the initial Contributor has attached the - notice in Exhibit A, the Executable Form of such Source Code Form, and - Modifications of such Source Code Form, in each case including portions - thereof. + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -1.5. “Incompatible With Secondary Licenses” - means + 1. Definitions. - a. that the initial Contributor has attached the notice described in - Exhibit B to the Covered Software; or + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. - b. that the Covered Software was made available under the terms of version - 1.1 or earlier of the License, but not also under the terms of a - Secondary License. + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. -1.6. “Executable Form” + "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. - means any form of the work other than Source Code Form. + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. -1.7. “Larger Work” + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. - means a work that combines Covered Software with other material, in a separate - file or files, that is not Covered Software. + "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. -1.8. “License” + "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). - means this document. + "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. -1.9. “Licensable” + "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." - means having the right to grant, to the maximum extent possible, whether at the - time of the initial grant or subsequently, any and all of the rights conveyed by - this License. + "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. -1.10. “Modifications” + 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. - means any of the following: + 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. - a. any file in Source Code Form that results from an addition to, deletion - from, or modification of the contents of Covered Software; or + 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: - b. any new file in Source Code Form that contains any Covered Software. + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and -1.11. “Patent Claims” of a Contributor + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and - means any patent claim(s), including without limitation, method, process, - and apparatus claims, in any patent Licensable by such Contributor that - would be infringed, but for the grant of the License, by the making, - using, selling, offering for sale, having made, import, or transfer of - either its Contributions or its Contributor Version. + (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 -1.12. “Secondary License” + (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. - means either the GNU General Public License, Version 2.0, the GNU Lesser - General Public License, Version 2.1, the GNU Affero General Public - License, Version 3.0, or any later versions of those licenses. + 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. -1.13. “Source Code Form” + 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. - means the form of the work preferred for making modifications. + 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. -1.14. “You” (or “Your”) + 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. - means an individual or a legal entity exercising rights under this - License. For legal entities, “You” includes any entity that controls, is - controlled by, or is under common control with You. For purposes of this - definition, “control” means (a) the power, direct or indirect, to cause - the direction or management of such entity, whether by contract or - otherwise, or (b) ownership of more than fifty percent (50%) of the - outstanding shares or beneficial ownership of such entity. + 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. -2. License Grants and Conditions + END OF TERMS AND CONDITIONS -2.1. Grants + APPENDIX: How to apply the Apache License to your work. - Each Contributor hereby grants You a world-wide, royalty-free, - non-exclusive license: + 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. - a. under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or as - part of a Larger Work; and + Copyright [yyyy] [name of copyright owner] - b. under Patent Claims of such Contributor to make, use, sell, offer for - sale, have made, import, and otherwise transfer either its Contributions - or its Contributor Version. + 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 -2.2. Effective Date + http://www.apache.org/licenses/LICENSE-2.0 - The licenses granted in Section 2.1 with respect to any Contribution become - effective for each Contribution on the date the Contributor first distributes - such Contribution. + 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. -2.3. Limitations on Grant Scope - The licenses granted in this Section 2 are the only rights granted under this - License. No additional rights or licenses will be implied from the distribution - or licensing of Covered Software under this License. Notwithstanding Section - 2.1(b) above, no patent license is granted by a Contributor: +-------------------------------------------------------------------------------- +Dependency : github.com/gopherjs/gopherjs +Version: v0.0.0-20181017120253-0766667cb4d1 +Licence type (autodetected): BSD-2-Clause +-------------------------------------------------------------------------------- - a. for any code that a Contributor has removed from Covered Software; or +Contents of probable licence file $GOMODCACHE/github.com/gopherjs/gopherjs@v0.0.0-20181017120253-0766667cb4d1/LICENSE: - b. for infringements caused by: (i) Your and any other third party’s - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or +Copyright (c) 2013 Richard Musiol. All rights reserved. - c. under Patent Claims infringed by Covered Software in the absence of its - Contributions. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: - This License does not grant any rights in the trademarks, service marks, or - logos of any Contributor (except as may be necessary to comply with the - notice requirements in Section 3.4). + * 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. -2.4. Subsequent Licenses +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. - No Contributor makes additional grants as a result of Your choice to - distribute the Covered Software under a subsequent version of this License - (see Section 10.2) or under the terms of a Secondary License (if permitted - under the terms of Section 3.3). -2.5. Representation +-------------------------------------------------------------------------------- +Dependency : github.com/gorilla/securecookie +Version: v1.1.1 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- - Each Contributor represents that the Contributor believes its Contributions - are its original creation(s) or it has sufficient rights to grant the - rights to its Contributions conveyed by this License. +Contents of probable licence file $GOMODCACHE/github.com/gorilla/securecookie@v1.1.1/LICENSE: -2.6. Fair Use +Copyright (c) 2012 Rodrigo Moraes. All rights reserved. - This License is not intended to limit any rights You have under applicable - copyright doctrines of fair use, fair dealing, or other equivalents. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: -2.7. Conditions + * 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. - Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in - Section 2.1. +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. -3. Responsibilities +-------------------------------------------------------------------------------- +Dependency : github.com/gorilla/sessions +Version: v1.2.1 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- -3.1. Distribution of Source Form +Contents of probable licence file $GOMODCACHE/github.com/gorilla/sessions@v1.2.1/LICENSE: - All distribution of Covered Software in Source Code Form, including any - Modifications that You create or to which You contribute, must be under the - terms of this License. You must inform recipients that the Source Code Form - of the Covered Software is governed by the terms of this License, and how - they can obtain a copy of this License. You may not attempt to alter or - restrict the recipients’ rights in the Source Code Form. +Copyright (c) 2012-2018 The Gorilla Authors. All rights reserved. -3.2. Distribution of Executable Form +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: - If You distribute Covered Software in Executable Form then: + * 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. - a. such Covered Software must also be made available in Source Code Form, - as described in Section 3.1, and You must inform recipients of the - Executable Form how they can obtain a copy of such Source Code Form by - reasonable means in a timely manner, at a charge no more than the cost - of distribution to the recipient; and +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. - b. You may distribute such Executable Form under the terms of this License, - or sublicense it under different terms, provided that the license for - the Executable Form does not attempt to limit or alter the recipients’ - rights in the Source Code Form under this License. -3.3. Distribution of a Larger Work +-------------------------------------------------------------------------------- +Dependency : github.com/grafana/regexp +Version: v0.0.0-20240518133315-a468a5bfb3bc +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- - You may create and distribute a Larger Work under terms of Your choice, - provided that You also comply with the requirements of this License for the - Covered Software. If the Larger Work is a combination of Covered Software - with a work governed by one or more Secondary Licenses, and the Covered - Software is not Incompatible With Secondary Licenses, this License permits - You to additionally distribute such Covered Software under the terms of - such Secondary License(s), so that the recipient of the Larger Work may, at - their option, further distribute the Covered Software under the terms of - either this License or such Secondary License(s). +Contents of probable licence file $GOMODCACHE/github.com/grafana/regexp@v0.0.0-20240518133315-a468a5bfb3bc/LICENSE: -3.4. Notices +Copyright (c) 2009 The Go Authors. All rights reserved. - You may not remove or alter the substance of any license notices (including - copyright notices, patent notices, disclaimers of warranty, or limitations - of liability) contained within the Source Code Form of the Covered - Software, except that You may alter any license notices to the extent - required to remedy known factual inaccuracies. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: -3.5. Application of Additional Terms + * 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. - You may choose to offer, and to charge a fee for, warranty, support, - indemnity or liability obligations to one or more recipients of Covered - Software. However, You may do so only on Your own behalf, and not on behalf - of any Contributor. You must make it absolutely clear that any such - warranty, support, indemnity, or liability obligation is offered by You - alone, and You hereby agree to indemnify every Contributor for any - liability incurred by such Contributor as a result of warranty, support, - indemnity or liability terms You offer. You may include additional - disclaimers of warranty and limitations of liability specific to any - jurisdiction. +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. -4. Inability to Comply Due to Statute or Regulation - If it is impossible for You to comply with any of the terms of this License - with respect to some or all of the Covered Software due to statute, judicial - order, or regulation then You must: (a) comply with the terms of this License - to the maximum extent possible; and (b) describe the limitations and the code - they affect. Such description must be placed in a text file included with all - distributions of the Covered Software under this License. Except to the - extent prohibited by statute or regulation, such description must be - sufficiently detailed for a recipient of ordinary skill to be able to - understand it. +-------------------------------------------------------------------------------- +Dependency : github.com/grpc-ecosystem/grpc-gateway +Version: v1.16.0 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- -5. Termination +Contents of probable licence file $GOMODCACHE/github.com/grpc-ecosystem/grpc-gateway@v1.16.0/LICENSE.txt: -5.1. The rights granted under this License will terminate automatically if You - fail to comply with any of its terms. However, if You become compliant, - then the rights granted under this License from a particular Contributor - are reinstated (a) provisionally, unless and until such Contributor - explicitly and finally terminates Your grants, and (b) on an ongoing basis, - if such Contributor fails to notify You of the non-compliance by some - reasonable means prior to 60 days after You have come back into compliance. - Moreover, Your grants from a particular Contributor are reinstated on an - ongoing basis if such Contributor notifies You of the non-compliance by - some reasonable means, this is the first time You have received notice of - non-compliance with this License from such Contributor, and You become - compliant prior to 30 days after Your receipt of the notice. +Copyright (c) 2015, Gengo, Inc. +All rights reserved. -5.2. If You initiate litigation against any entity by asserting a patent - infringement claim (excluding declaratory judgment actions, counter-claims, - and cross-claims) alleging that a Contributor Version directly or - indirectly infringes any patent, then the rights granted to You by any and - all Contributors for the Covered Software under Section 2.1 of this License - shall terminate. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: -5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user - license agreements (excluding distributors and resellers) which have been - validly granted by You or Your distributors under this License prior to - termination shall survive termination. + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. -6. Disclaimer of Warranty + * 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. - Covered Software is provided under this License on an “as is” basis, without - warranty of any kind, either expressed, implied, or statutory, including, - without limitation, warranties that the Covered Software is free of defects, - merchantable, fit for a particular purpose or non-infringing. The entire - risk as to the quality and performance of the Covered Software is with You. - Should any Covered Software prove defective in any respect, You (not any - Contributor) assume the cost of any necessary servicing, repair, or - correction. This disclaimer of warranty constitutes an essential part of this - License. No use of any Covered Software is authorized under this License - except under this disclaimer. + * Neither the name of Gengo, Inc. nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. -7. Limitation of Liability +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. - Under no circumstances and under no legal theory, whether tort (including - negligence), contract, or otherwise, shall any Contributor, or anyone who - distributes Covered Software as permitted above, be liable to You for any - direct, indirect, special, incidental, or consequential damages of any - character including, without limitation, damages for lost profits, loss of - goodwill, work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses, even if such party shall have been - informed of the possibility of such damages. This limitation of liability - shall not apply to liability for death or personal injury resulting from such - party’s negligence to the extent applicable law prohibits such limitation. - Some jurisdictions do not allow the exclusion or limitation of incidental or - consequential damages, so this exclusion and limitation may not apply to You. -8. Litigation +-------------------------------------------------------------------------------- +Dependency : github.com/grpc-ecosystem/grpc-gateway/v2 +Version: v2.20.0 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- - Any litigation relating to this License may be brought only in the courts of - a jurisdiction where the defendant maintains its principal place of business - and such litigation shall be governed by laws of that jurisdiction, without - reference to its conflict-of-law provisions. Nothing in this Section shall - prevent a party’s ability to bring cross-claims or counter-claims. +Contents of probable licence file $GOMODCACHE/github.com/grpc-ecosystem/grpc-gateway/v2@v2.20.0/LICENSE: -9. Miscellaneous +Copyright (c) 2015, Gengo, Inc. +All rights reserved. - This License represents the complete agreement concerning the subject matter - hereof. If any provision of this License is held to be unenforceable, such - provision shall be reformed only to the extent necessary to make it - enforceable. Any law or regulation which provides that the language of a - contract shall be construed against the drafter shall not be used to construe - this License against a Contributor. +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. -10. Versions of the License + * 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. -10.1. New Versions + * Neither the name of Gengo, Inc. nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. - Mozilla Foundation is the license steward. Except as provided in Section - 10.3, no one other than the license steward has the right to modify or - publish new versions of this License. Each version will be given a - distinguishing version number. +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. -10.2. Effect of New Versions - You may distribute the Covered Software under the terms of the version of - the License under which You originally received the Covered Software, or - under the terms of any subsequent version published by the license - steward. +-------------------------------------------------------------------------------- +Dependency : github.com/h2non/parth +Version: v0.0.0-20190131123155-b4df798d6542 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- -10.3. Modified Versions +Contents of probable licence file $GOMODCACHE/github.com/h2non/parth@v0.0.0-20190131123155-b4df798d6542/LICENSE: - If you create software not governed by this License, and you want to - create a new license for such software, you may create and use a modified - version of this License if you rename the license and remove any - references to the name of the license steward (except to note that such - modified license differs from this License). +The MIT License (MIT) -10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses - If You choose to distribute Source Code Form that is Incompatible With - Secondary Licenses under the terms of this version of the License, the - notice described in Exhibit B of this License must be attached. +Copyright (c) 2018 codemodus -Exhibit A - Source Code Form License Notice +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: - This Source Code Form is subject to the - terms of the Mozilla Public License, v. - 2.0. If a copy of the MPL was not - distributed with this file, You can - obtain one at - http://mozilla.org/MPL/2.0/. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -If it is not possible or desirable to put the notice in a particular file, then -You may include the notice in a location (such as a LICENSE file in a relevant -directory) where a recipient would be likely to look for such a notice. +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. -You may add additional accurate notices of copyright ownership. -Exhibit B - “Incompatible With Secondary Licenses” Notice - This Source Code Form is “Incompatible - With Secondary Licenses”, as defined by - the Mozilla Public License, v. 2.0. +-------------------------------------------------------------------------------- +Dependency : github.com/hashicorp/cronexpr +Version: v1.1.2 +Licence type (autodetected): Apache-2.0 +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/hashicorp/cronexpr@v1.1.2/APLv2: + + + 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/hashicorp/go-cleanhttp -Version: v0.5.2 +Dependency : github.com/hashicorp/errwrap +Version: v1.1.0 Licence type (autodetected): MPL-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/hashicorp/go-cleanhttp@v0.5.2/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/hashicorp/errwrap@v1.1.0/LICENSE: Mozilla Public License, version 2.0 1. Definitions -1.1. "Contributor" +1.1. “Contributor” means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. -1.2. "Contributor Version" +1.2. “Contributor Version” means the combination of the Contributions of others (if any) used by a - Contributor and that particular Contributor's Contribution. + Contributor and that particular Contributor’s Contribution. -1.3. "Contribution" +1.3. “Contribution” means Covered Software of a particular Contributor. -1.4. "Covered Software" +1.4. “Covered Software” means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. -1.5. "Incompatible With Secondary Licenses" +1.5. “Incompatible With Secondary Licenses” means a. that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or - b. that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the terms of - a Secondary License. + b. that the Covered Software was made available under the terms of version + 1.1 or earlier of the License, but not also under the terms of a + Secondary License. -1.6. "Executable Form" +1.6. “Executable Form” means any form of the work other than Source Code Form. -1.7. "Larger Work" +1.7. “Larger Work” - means a work that combines Covered Software with other material, in a - separate file or files, that is not Covered Software. + means a work that combines Covered Software with other material, in a separate + file or files, that is not Covered Software. -1.8. "License" +1.8. “License” means this document. -1.9. "Licensable" +1.9. “Licensable” - means having the right to grant, to the maximum extent possible, whether - at the time of the initial grant or subsequently, any and all of the - rights conveyed by this License. + means having the right to grant, to the maximum extent possible, whether at the + time of the initial grant or subsequently, any and all of the rights conveyed by + this License. -1.10. "Modifications" +1.10. “Modifications” means any of the following: - a. any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered Software; or + a. any file in Source Code Form that results from an addition to, deletion + from, or modification of the contents of Covered Software; or b. any new file in Source Code Form that contains any Covered Software. -1.11. "Patent Claims" of a Contributor +1.11. “Patent Claims” of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the License, - by the making, using, selling, offering for sale, having made, import, - or transfer of either its Contributions or its Contributor Version. + means any patent claim(s), including without limitation, method, process, + and apparatus claims, in any patent Licensable by such Contributor that + would be infringed, but for the grant of the License, by the making, + using, selling, offering for sale, having made, import, or transfer of + either its Contributions or its Contributor Version. -1.12. "Secondary License" +1.12. “Secondary License” means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. -1.13. "Source Code Form" +1.13. “Source Code Form” means the form of the work preferred for making modifications. -1.14. "You" (or "Your") +1.14. “You” (or “Your”) means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that controls, is + License. For legal entities, “You” includes any entity that controls, is controlled by, or is under common control with You. For purposes of this - definition, "control" means (a) the power, direct or indirect, to cause + definition, “control” means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. @@ -44843,59 +44258,57 @@ Mozilla Public License, version 2.0 a. under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and + Contributions, either on an unmodified basis, with Modifications, or as + part of a Larger Work; and b. under Patent Claims of such Contributor to make, use, sell, offer for - sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. + sale, have made, import, and otherwise transfer either its Contributions + or its Contributor Version. 2.2. Effective Date - The licenses granted in Section 2.1 with respect to any Contribution - become effective for each Contribution on the date the Contributor first - distributes such Contribution. + The licenses granted in Section 2.1 with respect to any Contribution become + effective for each Contribution on the date the Contributor first distributes + such Contribution. 2.3. Limitations on Grant Scope - The licenses granted in this Section 2 are the only rights granted under - this License. No additional rights or licenses will be implied from the - distribution or licensing of Covered Software under this License. - Notwithstanding Section 2.1(b) above, no patent license is granted by a - Contributor: + The licenses granted in this Section 2 are the only rights granted under this + License. No additional rights or licenses will be implied from the distribution + or licensing of Covered Software under this License. Notwithstanding Section + 2.1(b) above, no patent license is granted by a Contributor: a. for any code that a Contributor has removed from Covered Software; or - b. for infringements caused by: (i) Your and any other third party's + b. for infringements caused by: (i) Your and any other third party’s modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or - c. under Patent Claims infringed by Covered Software in the absence of - its Contributions. + c. under Patent Claims infringed by Covered Software in the absence of its + Contributions. - This License does not grant any rights in the trademarks, service marks, - or logos of any Contributor (except as may be necessary to comply with - the notice requirements in Section 3.4). + This License does not grant any rights in the trademarks, service marks, or + logos of any Contributor (except as may be necessary to comply with the + notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to - distribute the Covered Software under a subsequent version of this - License (see Section 10.2) or under the terms of a Secondary License (if - permitted under the terms of Section 3.3). + distribute the Covered Software under a subsequent version of this License + (see Section 10.2) or under the terms of a Secondary License (if permitted + under the terms of Section 3.3). 2.5. Representation - Each Contributor represents that the Contributor believes its - Contributions are its original creation(s) or it has sufficient rights to - grant the rights to its Contributions conveyed by this License. + Each Contributor represents that the Contributor believes its Contributions + are its original creation(s) or it has sufficient rights to grant the + rights to its Contributions conveyed by this License. 2.6. Fair Use - This License is not intended to limit any rights You have under - applicable copyright doctrines of fair use, fair dealing, or other - equivalents. + This License is not intended to limit any rights You have under applicable + copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions @@ -44908,12 +44321,11 @@ Mozilla Public License, version 2.0 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any - Modifications that You create or to which You contribute, must be under - the terms of this License. You must inform recipients that the Source - Code Form of the Covered Software is governed by the terms of this - License, and how they can obtain a copy of this License. You may not - attempt to alter or restrict the recipients' rights in the Source Code - Form. + Modifications that You create or to which You contribute, must be under the + terms of this License. You must inform recipients that the Source Code Form + of the Covered Software is governed by the terms of this License, and how + they can obtain a copy of this License. You may not attempt to alter or + restrict the recipients’ rights in the Source Code Form. 3.2. Distribution of Executable Form @@ -44925,29 +44337,396 @@ Mozilla Public License, version 2.0 reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and - b. You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter the - recipients' rights in the Source Code Form under this License. + b. You may distribute such Executable Form under the terms of this License, + or sublicense it under different terms, provided that the license for + the Executable Form does not attempt to limit or alter the recipients’ + rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, - provided that You also comply with the requirements of this License for - the Covered Software. If the Larger Work is a combination of Covered - Software with a work governed by one or more Secondary Licenses, and the - Covered Software is not Incompatible With Secondary Licenses, this - License permits You to additionally distribute such Covered Software - under the terms of such Secondary License(s), so that the recipient of - the Larger Work may, at their option, further distribute the Covered - Software under the terms of either this License or such Secondary - License(s). + provided that You also comply with the requirements of this License for the + Covered Software. If the Larger Work is a combination of Covered Software + with a work governed by one or more Secondary Licenses, and the Covered + Software is not Incompatible With Secondary Licenses, this License permits + You to additionally distribute such Covered Software under the terms of + such Secondary License(s), so that the recipient of the Larger Work may, at + their option, further distribute the Covered Software under the terms of + either this License or such Secondary License(s). 3.4. Notices - You may not remove or alter the substance of any license notices - (including copyright notices, patent notices, disclaimers of warranty, or - limitations of liability) contained within the Source Code Form of the + You may not remove or alter the substance of any license notices (including + copyright notices, patent notices, disclaimers of warranty, or limitations + of liability) contained within the Source Code Form of the Covered + Software, except that You may alter any license notices to the extent + required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on behalf + of any Contributor. You must make it absolutely clear that any such + warranty, support, indemnity, or liability obligation is offered by You + alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, judicial + order, or regulation then You must: (a) comply with the terms of this License + to the maximum extent possible; and (b) describe the limitations and the code + they affect. Such description must be placed in a text file included with all + distributions of the Covered Software under this License. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing basis, + if such Contributor fails to notify You of the non-compliance by some + reasonable means prior to 60 days after You have come back into compliance. + Moreover, Your grants from a particular Contributor are reinstated on an + ongoing basis if such Contributor notifies You of the non-compliance by + some reasonable means, this is the first time You have received notice of + non-compliance with this License from such Contributor, and You become + compliant prior to 30 days after Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, counter-claims, + and cross-claims) alleging that a Contributor Version directly or + indirectly infringes any patent, then the rights granted to You by any and + all Contributors for the Covered Software under Section 2.1 of this License + shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an “as is” basis, without + warranty of any kind, either expressed, implied, or statutory, including, + without limitation, warranties that the Covered Software is free of defects, + merchantable, fit for a particular purpose or non-infringing. The entire + risk as to the quality and performance of the Covered Software is with You. + Should any Covered Software prove defective in any respect, You (not any + Contributor) assume the cost of any necessary servicing, repair, or + correction. This disclaimer of warranty constitutes an essential part of this + License. No use of any Covered Software is authorized under this License + except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from such + party’s negligence to the extent applicable law prohibits such limitation. + Some jurisdictions do not allow the exclusion or limitation of incidental or + consequential damages, so this exclusion and limitation may not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts of + a jurisdiction where the defendant maintains its principal place of business + and such litigation shall be governed by laws of that jurisdiction, without + reference to its conflict-of-law provisions. Nothing in this Section shall + prevent a party’s ability to bring cross-claims or counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject matter + hereof. If any provision of this License is held to be unenforceable, such + provision shall be reformed only to the extent necessary to make it + enforceable. Any law or regulation which provides that the language of a + contract shall be construed against the drafter shall not be used to construe + this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version of + the License under which You originally received the Covered Software, or + under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a modified + version of this License if you rename the license and remove any + references to the name of the license steward (except to note that such + modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses + If You choose to distribute Source Code Form that is Incompatible With + Secondary Licenses under the terms of this version of the License, the + notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, then +You may include the notice in a location (such as a LICENSE file in a relevant +directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - “Incompatible With Secondary Licenses” Notice + + This Source Code Form is “Incompatible + With Secondary Licenses”, as defined by + the Mozilla Public License, v. 2.0. + + + +-------------------------------------------------------------------------------- +Dependency : github.com/hashicorp/go-cleanhttp +Version: v0.5.2 +Licence type (autodetected): MPL-2.0 +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/hashicorp/go-cleanhttp@v0.5.2/LICENSE: + +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. @@ -45873,11 +45652,13 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice -------------------------------------------------------------------------------- Dependency : github.com/hashicorp/go-uuid -Version: v1.0.2 +Version: v1.0.3 Licence type (autodetected): MPL-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/hashicorp/go-uuid@v1.0.2/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/hashicorp/go-uuid@v1.0.3/LICENSE: + +Copyright © 2015-2022 HashiCorp, Inc. Mozilla Public License, version 2.0 @@ -47312,11 +47093,11 @@ Contents of probable licence file $GOMODCACHE/github.com/jcmturner/dnsutils/v2@v -------------------------------------------------------------------------------- Dependency : github.com/jcmturner/gofork -Version: v1.0.0 +Version: v1.7.6 Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/jcmturner/gofork@v1.0.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/jcmturner/gofork@v1.7.6/LICENSE: Copyright (c) 2009 The Go Authors. All rights reserved. @@ -47559,12 +47340,12 @@ Contents of probable licence file $GOMODCACHE/github.com/jcmturner/goidentity/v6 -------------------------------------------------------------------------------- -Dependency : github.com/jcmturner/gokrb5/v8 -Version: v8.4.2 +Dependency : github.com/jcmturner/rpc/v2 +Version: v2.0.3 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/jcmturner/gokrb5/v8@v8.4.2/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/jcmturner/rpc/v2@v2.0.3/LICENSE: Apache License Version 2.0, January 2004 @@ -47746,7 +47527,7 @@ Contents of probable licence file $GOMODCACHE/github.com/jcmturner/gokrb5/v8@v8. 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 "{}" + 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 @@ -47754,7 +47535,7 @@ Contents of probable licence file $GOMODCACHE/github.com/jcmturner/gokrb5/v8@v8. same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright {yyyy} {name of copyright owner} + 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. @@ -47770,345 +47551,134 @@ Contents of probable licence file $GOMODCACHE/github.com/jcmturner/gokrb5/v8@v8. -------------------------------------------------------------------------------- -Dependency : github.com/jcmturner/rpc/v2 -Version: v2.0.3 +Dependency : github.com/jmespath/go-jmespath +Version: v0.4.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/jcmturner/rpc/v2@v2.0.3/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." +Contents of probable licence file $GOMODCACHE/github.com/jmespath/go-jmespath@v0.4.0/LICENSE: - "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. +Copyright 2015 James Saryerwinnie - 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. +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 - 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. + http://www.apache.org/licenses/LICENSE-2.0 - 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: +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. - (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 +-------------------------------------------------------------------------------- +Dependency : github.com/jmespath/go-jmespath/internal/testify +Version: v1.5.1 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- - (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 +Contents of probable licence file $GOMODCACHE/github.com/jmespath/go-jmespath/internal/testify@v1.5.1/LICENSE: - (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. +MIT 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. +Copyright (c) 2012-2018 Mat Ryer and Tyler Bunnell - 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. +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: - 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. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. - 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. +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. - 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. +-------------------------------------------------------------------------------- +Dependency : github.com/joho/godotenv +Version: v1.5.1 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- - END OF TERMS AND CONDITIONS +Contents of probable licence file $GOMODCACHE/github.com/joho/godotenv@v1.5.1/LICENCE: - APPENDIX: How to apply the Apache License to your work. +Copyright (c) 2013 John Barton - 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. +MIT License - Copyright [yyyy] [name of copyright owner] +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: - 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 +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. - http://www.apache.org/licenses/LICENSE-2.0 +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. - 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/jmespath/go-jmespath -Version: v0.4.0 -Licence type (autodetected): Apache-2.0 +Dependency : github.com/josharian/intern +Version: v1.0.0 +Licence type (autodetected): MIT -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/jmespath/go-jmespath@v0.4.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/josharian/intern@v1.0.0/license.md: -Copyright 2015 James Saryerwinnie +MIT License -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 +Copyright (c) 2019 Josh Bleecher Snyder - http://www.apache.org/licenses/LICENSE-2.0 +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: -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. +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/jmespath/go-jmespath/internal/testify -Version: v1.5.1 +Dependency : github.com/jpillora/backoff +Version: v1.0.0 Licence type (autodetected): MIT -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/jmespath/go-jmespath/internal/testify@v1.5.1/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/jpillora/backoff@v1.0.0/LICENSE: -MIT License +The MIT License (MIT) -Copyright (c) 2012-2018 Mat Ryer and Tyler Bunnell - -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/joho/godotenv -Version: v1.5.1 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/joho/godotenv@v1.5.1/LICENCE: - -Copyright (c) 2013 John Barton - -MIT License - -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/josharian/intern -Version: v1.0.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/josharian/intern@v1.0.0/license.md: - -MIT License - -Copyright (c) 2019 Josh Bleecher Snyder - -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/jpillora/backoff -Version: v1.0.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/jpillora/backoff@v1.0.0/LICENSE: - -The MIT License (MIT) - -Copyright (c) 2017 Jaime Pillora +Copyright (c) 2017 Jaime Pillora Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -48249,327 +47819,13 @@ SOFTWARE. --------------------------------------------------------------------------------- -Dependency : github.com/klauspost/compress -Version: v1.17.9 -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/klauspost/compress@v1.17.9/LICENSE: - -Copyright (c) 2012 The Go Authors. All rights reserved. -Copyright (c) 2019 Klaus Post. 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. - ------------------- - -Files: gzhttp/* - - 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 2016-2017 The New York Times Company - - 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. - ------------------- - -Files: s2/cmd/internal/readahead/* - -The MIT License (MIT) - -Copyright (c) 2015 Klaus Post - -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. - ---------------------- -Files: snappy/* -Files: internal/snapref/* - -Copyright (c) 2011 The Snappy-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. - ------------------ - -Files: s2/cmd/internal/filepathx/* - -Copyright 2016 The filepathx Authors - -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/klauspost/cpuid/v2 -Version: v2.2.5 +Version: v2.2.8 Licence type (autodetected): MIT -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/klauspost/cpuid/v2@v2.2.5/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/klauspost/cpuid/v2@v2.2.8/LICENSE: The MIT License (MIT) @@ -52149,44 +51405,6 @@ Contents of probable licence file $GOMODCACHE/github.com/oxtoacart/bpool@v0.0.0- limitations under the License. --------------------------------------------------------------------------------- -Dependency : github.com/pierrec/lz4 -Version: v2.6.0+incompatible -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/pierrec/lz4@v2.6.0+incompatible/LICENSE: - -Copyright (c) 2015, Pierre Curto -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 xxHash 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 HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - -------------------------------------------------------------------------------- Dependency : github.com/pkg/browser Version: v0.0.0-20240102092130-5ac0b6a4141c @@ -52576,76 +51794,6 @@ DEALINGS IN THE SOFTWARE. --------------------------------------------------------------------------------- -Dependency : github.com/shirou/gopsutil/v4 -Version: v4.24.7 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/shirou/gopsutil/v4@v4.24.7/LICENSE: - -gopsutil is distributed under BSD license reproduced below. - -Copyright (c) 2014, WAKAYAMA Shirou -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of the gopsutil authors nor the names of its contributors - may be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -------- -internal/common/binary.go in the gopsutil is copied and modified from golang/encoding/binary.go. - - - -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -------------------------------------------------------------------------------- Dependency : github.com/shoenig/go-m1cpu Version: v0.1.6 @@ -53535,701 +52683,85 @@ 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. - -NOTE: Various optional and subordinate components carry their own licensing -requirements and restrictions. Use of those components is subject to the terms -and conditions outlined the respective license of each component. - - --------------------------------------------------------------------------------- -Dependency : github.com/stoewer/go-strcase -Version: v1.2.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/stoewer/go-strcase@v1.2.0/LICENSE: - -The MIT License (MIT) - -Copyright (c) 2017, Adrian Stoewer - -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/stretchr/objx -Version: v0.5.2 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/stretchr/objx@v0.5.2/LICENSE: - -The MIT License - -Copyright (c) 2014 Stretchr, Inc. -Copyright (c) 2017-2018 objx contributors - -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/tklauser/numcpus -Version: v0.6.1 -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/tklauser/numcpus@v0.6.1/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 : github.com/vishvananda/netlink -Version: v1.2.1-beta.2 -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/vishvananda/netlink@v1.2.1-beta.2/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 - - Copyright 2014 Vishvananda Ishaya. - Copyright 2014 Docker, Inc. - - 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/vishvananda/netns -Version: v0.0.0-20210104183010-2eb08e3e575f -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/vishvananda/netns@v0.0.0-20210104183010-2eb08e3e575f/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. +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. - 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: +NOTE: Various optional and subordinate components carry their own licensing +requirements and restrictions. Use of those components is subject to the terms +and conditions outlined the respective license of each component. - (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 +-------------------------------------------------------------------------------- +Dependency : github.com/stoewer/go-strcase +Version: v1.2.0 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- - (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 +Contents of probable licence file $GOMODCACHE/github.com/stoewer/go-strcase@v1.2.0/LICENSE: - (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. +The MIT License (MIT) - 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. +Copyright (c) 2017, Adrian Stoewer - 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. +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: - 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. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. - 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. +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. - 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. +-------------------------------------------------------------------------------- +Dependency : github.com/stretchr/objx +Version: v0.5.2 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- - END OF TERMS AND CONDITIONS +Contents of probable licence file $GOMODCACHE/github.com/stretchr/objx@v0.5.2/LICENSE: - Copyright 2014 Vishvananda Ishaya. - Copyright 2014 Docker, Inc. +The MIT License - 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 +Copyright (c) 2014 Stretchr, Inc. +Copyright (c) 2017-2018 objx contributors - http://www.apache.org/licenses/LICENSE-2.0 +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: - 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. +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/xdg-go/pbkdf2 -Version: v1.0.0 +Dependency : github.com/tklauser/numcpus +Version: v0.6.1 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/xdg-go/pbkdf2@v1.0.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/tklauser/numcpus@v0.6.1/LICENSE: Apache License @@ -54407,14 +52939,41 @@ Contents of probable licence file $GOMODCACHE/github.com/xdg-go/pbkdf2@v1.0.0/LI 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/xdg-go/stringprep -Version: v1.0.4 +Dependency : github.com/vishvananda/netlink +Version: v1.1.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/xdg-go/stringprep@v1.0.4/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/vishvananda/netlink@v1.1.0/LICENSE: Apache License @@ -54592,333 +53151,31 @@ Contents of probable licence file $GOMODCACHE/github.com/xdg-go/stringprep@v1.0. incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + END OF TERMS AND CONDITIONS --------------------------------------------------------------------------------- -Dependency : github.com/youmark/pkcs8 -Version: v0.0.0-20201027041543-1326539a0a0a -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/youmark/pkcs8@v0.0.0-20201027041543-1326539a0a0a/LICENSE: - -The MIT License (MIT) - -Copyright (c) 2014 youmark - -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/yuin/gopher-lua -Version: v1.1.1 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/yuin/gopher-lua@v1.1.1/LICENSE: - -The MIT License (MIT) - -Copyright (c) 2015 Yusuke Inuzuka - -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/yusufpapurcu/wmi -Version: v1.2.4 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/yusufpapurcu/wmi@v1.2.4/LICENSE: - -The MIT License (MIT) - -Copyright (c) 2013 Stack Exchange - -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/zeebo/assert -Version: v1.3.0 -Licence type (autodetected): CC0-1.0 --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/zeebo/assert@v1.3.0/LICENSE: - -Creative Commons Legal Code - -CC0 1.0 Universal - - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE - LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN - ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS - INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES - REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS - PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM - THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED - HEREUNDER. - -Statement of Purpose - -The laws of most jurisdictions throughout the world automatically confer -exclusive Copyright and Related Rights (defined below) upon the creator -and subsequent owner(s) (each and all, an "owner") of an original work of -authorship and/or a database (each, a "Work"). - -Certain owners wish to permanently relinquish those rights to a Work for -the purpose of contributing to a commons of creative, cultural and -scientific works ("Commons") that the public can reliably and without fear -of later claims of infringement build upon, modify, incorporate in other -works, reuse and redistribute as freely as possible in any form whatsoever -and for any purposes, including without limitation commercial purposes. -These owners may contribute to the Commons to promote the ideal of a free -culture and the further production of creative, cultural and scientific -works, or to gain reputation or greater distribution for their Work in -part through the use and efforts of others. - -For these and/or other purposes and motivations, and without any -expectation of additional consideration or compensation, the person -associating CC0 with a Work (the "Affirmer"), to the extent that he or she -is an owner of Copyright and Related Rights in the Work, voluntarily -elects to apply CC0 to the Work and publicly distribute the Work under its -terms, with knowledge of his or her Copyright and Related Rights in the -Work and the meaning and intended legal effect of CC0 on those rights. - -1. Copyright and Related Rights. A Work made available under CC0 may be -protected by copyright and related or neighboring rights ("Copyright and -Related Rights"). Copyright and Related Rights include, but are not -limited to, the following: - - i. the right to reproduce, adapt, distribute, perform, display, - communicate, and translate a Work; - ii. moral rights retained by the original author(s) and/or performer(s); -iii. publicity and privacy rights pertaining to a person's image or - likeness depicted in a Work; - iv. rights protecting against unfair competition in regards to a Work, - subject to the limitations in paragraph 4(a), below; - v. rights protecting the extraction, dissemination, use and reuse of data - in a Work; - vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal - protection of databases, and under any national implementation - thereof, including any amended or successor version of such - directive); and -vii. other similar, equivalent or corresponding rights throughout the - world based on applicable law or treaty, and any national - implementations thereof. - -2. Waiver. To the greatest extent permitted by, but not in contravention -of, applicable law, Affirmer hereby overtly, fully, permanently, -irrevocably and unconditionally waives, abandons, and surrenders all of -Affirmer's Copyright and Related Rights and associated claims and causes -of action, whether now known or unknown (including existing as well as -future claims and causes of action), in the Work (i) in all territories -worldwide, (ii) for the maximum duration provided by applicable law or -treaty (including future time extensions), (iii) in any current or future -medium and for any number of copies, and (iv) for any purpose whatsoever, -including without limitation commercial, advertising or promotional -purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each -member of the public at large and to the detriment of Affirmer's heirs and -successors, fully intending that such Waiver shall not be subject to -revocation, rescission, cancellation, termination, or any other legal or -equitable action to disrupt the quiet enjoyment of the Work by the public -as contemplated by Affirmer's express Statement of Purpose. - -3. Public License Fallback. Should any part of the Waiver for any reason -be judged legally invalid or ineffective under applicable law, then the -Waiver shall be preserved to the maximum extent permitted taking into -account Affirmer's express Statement of Purpose. In addition, to the -extent the Waiver is so judged Affirmer hereby grants to each affected -person a royalty-free, non transferable, non sublicensable, non exclusive, -irrevocable and unconditional license to exercise Affirmer's Copyright and -Related Rights in the Work (i) in all territories worldwide, (ii) for the -maximum duration provided by applicable law or treaty (including future -time extensions), (iii) in any current or future medium and for any number -of copies, and (iv) for any purpose whatsoever, including without -limitation commercial, advertising or promotional purposes (the -"License"). The License shall be deemed effective as of the date CC0 was -applied by Affirmer to the Work. Should any part of the License for any -reason be judged legally invalid or ineffective under applicable law, such -partial invalidity or ineffectiveness shall not invalidate the remainder -of the License, and in such case Affirmer hereby affirms that he or she -will not (i) exercise any of his or her remaining Copyright and Related -Rights in the Work or (ii) assert any associated claims and causes of -action with respect to the Work, in either case contrary to Affirmer's -express Statement of Purpose. - -4. Limitations and Disclaimers. - - a. No trademark or patent rights held by Affirmer are waived, abandoned, - surrendered, licensed or otherwise affected by this document. - b. Affirmer offers the Work as-is and makes no representations or - warranties of any kind concerning the Work, express, implied, - statutory or otherwise, including without limitation warranties of - title, merchantability, fitness for a particular purpose, non - infringement, or the absence of latent or other defects, accuracy, or - the present or absence of errors, whether or not discoverable, all to - the greatest extent permissible under applicable law. - c. Affirmer disclaims responsibility for clearing rights of other persons - that may apply to the Work or any use thereof, including without - limitation any person's Copyright and Related Rights in the Work. - Further, Affirmer disclaims responsibility for obtaining any necessary - consents, permissions or other rights required for any use of the - Work. - d. Affirmer understands and acknowledges that Creative Commons is not a - party to this document and has no duty or obligation with respect to - this CC0 or use of the Work. - - --------------------------------------------------------------------------------- -Dependency : github.com/zeebo/xxh3 -Version: v1.0.2 -Licence type (autodetected): BSD-2-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/github.com/zeebo/xxh3@v1.0.2/LICENSE: - -xxHash Library -Copyright (c) 2012-2014, Yann Collet -Copyright (c) 2019, Jeff Wendling -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. - -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 HOLDER 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 : go.einride.tech/aip -Version: v0.67.1 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/go.einride.tech/aip@v0.67.1/LICENSE: - -Copyright 2020 Einride AB - -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 : go.elastic.co/fastjson -Version: v1.1.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/go.elastic.co/fastjson@v1.1.0/LICENSE: - -Copyright 2018 Elasticsearch BV - -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. - ---- - -Copyright (c) 2016 Mail.Ru Group + Copyright 2014 Vishvananda Ishaya. + Copyright 2014 Docker, Inc. -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: + 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 -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + http://www.apache.org/licenses/LICENSE-2.0 -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. + 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 : go.opencensus.io -Version: v0.24.0 +Dependency : github.com/vishvananda/netns +Version: v0.0.0-20210104183010-2eb08e3e575f Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.opencensus.io@v0.24.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/vishvananda/netns@v0.0.0-20210104183010-2eb08e3e575f/LICENSE: Apache License @@ -55098,18 +53355,8 @@ Contents of probable licence file $GOMODCACHE/go.opencensus.io@v0.24.0/LICENSE: 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] + Copyright 2014 Vishvananda Ishaya. + Copyright 2014 Docker, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -55123,13 +53370,14 @@ Contents of probable licence file $GOMODCACHE/go.opencensus.io@v0.24.0/LICENSE: See the License for the specific language governing permissions and limitations under the License. + -------------------------------------------------------------------------------- -Dependency : go.opentelemetry.io/collector -Version: v0.109.0 +Dependency : github.com/xdg-go/pbkdf2 +Version: v1.0.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector@v0.109.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/xdg-go/pbkdf2@v1.0.0/LICENSE: Apache License @@ -55307,41 +53555,14 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector@v0.1 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 : go.opentelemetry.io/collector/config/configtelemetry -Version: v0.109.0 +Dependency : github.com/xdg-go/stringprep +Version: v1.0.4 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/config/configtelemetry@v0.109.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/xdg-go/stringprep@v1.0.4/LICENSE: Apache License @@ -55519,41 +53740,333 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/conf 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. +-------------------------------------------------------------------------------- +Dependency : github.com/youmark/pkcs8 +Version: v0.0.0-20201027041543-1326539a0a0a +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- - 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. +Contents of probable licence file $GOMODCACHE/github.com/youmark/pkcs8@v0.0.0-20201027041543-1326539a0a0a/LICENSE: - Copyright [yyyy] [name of copyright owner] +The MIT License (MIT) - 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 +Copyright (c) 2014 youmark - http://www.apache.org/licenses/LICENSE-2.0 +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: - 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. +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 : go.opentelemetry.io/collector/consumer/consumerprofiles -Version: v0.109.0 +Dependency : github.com/yuin/gopher-lua +Version: v1.1.1 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/yuin/gopher-lua@v1.1.1/LICENSE: + +The MIT License (MIT) + +Copyright (c) 2015 Yusuke Inuzuka + +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/yusufpapurcu/wmi +Version: v1.2.4 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/yusufpapurcu/wmi@v1.2.4/LICENSE: + +The MIT License (MIT) + +Copyright (c) 2013 Stack Exchange + +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/zeebo/assert +Version: v1.3.0 +Licence type (autodetected): CC0-1.0 +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/zeebo/assert@v1.3.0/LICENSE: + +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. + + +-------------------------------------------------------------------------------- +Dependency : github.com/zeebo/xxh3 +Version: v1.0.2 +Licence type (autodetected): BSD-2-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/zeebo/xxh3@v1.0.2/LICENSE: + +xxHash Library +Copyright (c) 2012-2014, Yann Collet +Copyright (c) 2019, Jeff Wendling +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. + +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 HOLDER 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 : go.einride.tech/aip +Version: v0.67.1 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/go.einride.tech/aip@v0.67.1/LICENSE: + +Copyright 2020 Einride AB + +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 : go.elastic.co/fastjson +Version: v1.1.0 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/go.elastic.co/fastjson@v1.1.0/LICENSE: + +Copyright 2018 Elasticsearch BV + +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. + +--- + +Copyright (c) 2016 Mail.Ru Group + +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 : go.opencensus.io +Version: v0.24.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/consumer/consumerprofiles@v0.109.0/LICENSE: +Contents of probable licence file $GOMODCACHE/go.opencensus.io@v0.24.0/LICENSE: Apache License @@ -55758,14 +54271,13 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/cons See the License for the specific language governing permissions and limitations under the License. - -------------------------------------------------------------------------------- -Dependency : go.opentelemetry.io/collector/consumer/consumertest +Dependency : go.opentelemetry.io/collector Version: v0.109.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/consumer/consumertest@v0.109.0/LICENSE: +Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector@v0.109.0/LICENSE: Apache License @@ -55972,12 +54484,12 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/cons -------------------------------------------------------------------------------- -Dependency : go.opentelemetry.io/collector/pdata/pprofile +Dependency : go.opentelemetry.io/collector/config/configtelemetry Version: v0.109.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/pdata/pprofile@v0.109.0/LICENSE: +Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/config/configtelemetry@v0.109.0/LICENSE: Apache License @@ -56184,12 +54696,12 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/pdat -------------------------------------------------------------------------------- -Dependency : go.opentelemetry.io/collector/pdata/testdata +Dependency : go.opentelemetry.io/collector/consumer/consumerprofiles Version: v0.109.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/pdata/testdata@v0.109.0/LICENSE: +Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/consumer/consumerprofiles@v0.109.0/LICENSE: Apache License @@ -56396,223 +54908,13 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/pdat -------------------------------------------------------------------------------- -Dependency : go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc -Version: v0.49.0 +Dependency : go.opentelemetry.io/collector/consumer/consumertest +Version: v0.109.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@v0.49.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 : go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp -Version: v0.53.0 -Licence type (autodetected): Apache-2.0 --------------------------------------------------------------------------------- +Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/consumer/consumertest@v0.109.0/LICENSE: -Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp@v0.53.0/LICENSE: Apache License Version 2.0, January 2004 @@ -56818,12 +55120,13 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/contrib/instru -------------------------------------------------------------------------------- -Dependency : go.opentelemetry.io/otel -Version: v1.29.0 +Dependency : go.opentelemetry.io/collector/pdata/pprofile +Version: v0.109.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/otel@v1.29.0/LICENSE: +Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/pdata/pprofile@v0.109.0/LICENSE: + Apache License Version 2.0, January 2004 @@ -57029,12 +55332,13 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/otel@v1.29.0/L -------------------------------------------------------------------------------- -Dependency : go.opentelemetry.io/otel/exporters/otlp/otlptrace -Version: v1.28.0 +Dependency : go.opentelemetry.io/collector/pdata/testdata +Version: v0.109.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/otel/exporters/otlp/otlptrace@v1.28.0/LICENSE: +Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/pdata/testdata@v0.109.0/LICENSE: + Apache License Version 2.0, January 2004 @@ -57240,12 +55544,12 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/otel/exporters -------------------------------------------------------------------------------- -Dependency : go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp -Version: v1.28.0 +Dependency : go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc +Version: v0.49.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp@v1.28.0/LICENSE: +Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@v0.49.0/LICENSE: Apache License Version 2.0, January 2004 @@ -57451,12 +55755,12 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/otel/exporters -------------------------------------------------------------------------------- -Dependency : go.opentelemetry.io/otel/metric -Version: v1.29.0 +Dependency : go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp +Version: v0.53.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/otel/metric@v1.29.0/LICENSE: +Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp@v0.53.0/LICENSE: Apache License Version 2.0, January 2004 @@ -57662,12 +55966,12 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/otel/metric@v1 -------------------------------------------------------------------------------- -Dependency : go.opentelemetry.io/otel/sdk +Dependency : go.opentelemetry.io/otel Version: v1.29.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/otel/sdk@v1.29.0/LICENSE: +Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/otel@v1.29.0/LICENSE: Apache License Version 2.0, January 2004 @@ -57873,12 +56177,12 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/otel/sdk@v1.29 -------------------------------------------------------------------------------- -Dependency : go.opentelemetry.io/otel/trace -Version: v1.29.0 +Dependency : go.opentelemetry.io/otel/exporters/otlp/otlptrace +Version: v1.28.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/otel/trace@v1.29.0/LICENSE: +Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/otel/exporters/otlp/otlptrace@v1.28.0/LICENSE: Apache License Version 2.0, January 2004 @@ -58084,12 +56388,12 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/otel/trace@v1. -------------------------------------------------------------------------------- -Dependency : go.opentelemetry.io/proto/otlp -Version: v1.3.1 +Dependency : go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp +Version: v1.28.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/proto/otlp@v1.3.1/LICENSE: +Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp@v1.28.0/LICENSE: Apache License Version 2.0, January 2004 @@ -58295,209 +56599,12 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/proto/otlp@v1. -------------------------------------------------------------------------------- -Dependency : go.uber.org/atomic -Version: v1.11.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/go.uber.org/atomic@v1.11.0/LICENSE.txt: - -Copyright (c) 2016 Uber Technologies, Inc. - -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 : go.uber.org/goleak -Version: v1.3.0 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/go.uber.org/goleak@v1.3.0/LICENSE: - -The MIT License (MIT) - -Copyright (c) 2018 Uber Technologies, Inc. - -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 : go.uber.org/ratelimit -Version: v0.3.1 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/go.uber.org/ratelimit@v0.3.1/LICENSE: - -The MIT License (MIT) - -Copyright (c) 2016 Uber Technologies, Inc. - -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 : golang.org/x/exp -Version: v0.0.0-20240205201215-2c58cdc269a3 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/golang.org/x/exp@v0.0.0-20240205201215-2c58cdc269a3/LICENSE: - -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - --------------------------------------------------------------------------------- -Dependency : golang.org/x/xerrors -Version: v0.0.0-20231012003039-104605ab7028 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/golang.org/x/xerrors@v0.0.0-20231012003039-104605ab7028/LICENSE: - -Copyright (c) 2019 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 : gonum.org/v1/gonum -Version: v0.12.0 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/gonum.org/v1/gonum@v0.12.0/LICENSE: - -Copyright ©2013 The Gonum 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 the Gonum project nor the names of its authors and - 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 HOLDER 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 : google.golang.org/genproto -Version: v0.0.0-20240730163845-b1a4ccb954bf +Dependency : go.opentelemetry.io/otel/metric +Version: v1.29.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/google.golang.org/genproto@v0.0.0-20240730163845-b1a4ccb954bf/LICENSE: - +Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/otel/metric@v1.29.0/LICENSE: Apache License Version 2.0, January 2004 @@ -58703,13 +56810,12 @@ Contents of probable licence file $GOMODCACHE/google.golang.org/genproto@v0.0.0- -------------------------------------------------------------------------------- -Dependency : google.golang.org/genproto/googleapis/rpc -Version: v0.0.0-20240822170219-fc7c04adadcd +Dependency : go.opentelemetry.io/otel/sdk +Version: v1.29.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/google.golang.org/genproto/googleapis/rpc@v0.0.0-20240822170219-fc7c04adadcd/LICENSE: - +Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/otel/sdk@v1.29.0/LICENSE: Apache License Version 2.0, January 2004 @@ -58915,119 +57021,12 @@ Contents of probable licence file $GOMODCACHE/google.golang.org/genproto/googlea -------------------------------------------------------------------------------- -Dependency : gopkg.in/check.v1 -Version: v1.0.0-20201130134442-10cb98267c6c -Licence type (autodetected): BSD-2-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/gopkg.in/check.v1@v1.0.0-20201130134442-10cb98267c6c/LICENSE: - -Gocheck - A rich testing framework for Go - -Copyright (c) 2010-2013 Gustavo Niemeyer - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. 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. - -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/fsnotify.v1 -Version: v1.4.7 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/gopkg.in/fsnotify.v1@v1.4.7/LICENSE: - -Copyright (c) 2012 The Go Authors. All rights reserved. -Copyright (c) 2012 fsnotify 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/h2non/gock.v1 -Version: v1.1.2 -Licence type (autodetected): MIT --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/gopkg.in/h2non/gock.v1@v1.1.2/LICENSE: - -The MIT License - -Copyright (c) 2016-2019 Tomas Aparicio - -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 : gopkg.in/jcmturner/aescts.v1 -Version: v1.0.1 +Dependency : go.opentelemetry.io/otel/trace +Version: v1.29.0 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/gopkg.in/jcmturner/aescts.v1@v1.0.1/LICENSE: +Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/otel/trace@v1.29.0/LICENSE: Apache License Version 2.0, January 2004 @@ -59209,7 +57208,7 @@ Contents of probable licence file $GOMODCACHE/gopkg.in/jcmturner/aescts.v1@v1.0. 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 "{}" + 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 @@ -59217,7 +57216,7 @@ Contents of probable licence file $GOMODCACHE/gopkg.in/jcmturner/aescts.v1@v1.0. same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright {yyyy} {name of copyright owner} + 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. @@ -59233,12 +57232,12 @@ Contents of probable licence file $GOMODCACHE/gopkg.in/jcmturner/aescts.v1@v1.0. -------------------------------------------------------------------------------- -Dependency : gopkg.in/jcmturner/dnsutils.v1 -Version: v1.0.1 +Dependency : go.opentelemetry.io/proto/otlp +Version: v1.3.1 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/gopkg.in/jcmturner/dnsutils.v1@v1.0.1/LICENSE: +Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/proto/otlp@v1.3.1/LICENSE: Apache License Version 2.0, January 2004 @@ -59444,12 +57443,209 @@ Contents of probable licence file $GOMODCACHE/gopkg.in/jcmturner/dnsutils.v1@v1. -------------------------------------------------------------------------------- -Dependency : gopkg.in/jcmturner/goidentity.v3 -Version: v3.0.0 +Dependency : go.uber.org/atomic +Version: v1.11.0 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/go.uber.org/atomic@v1.11.0/LICENSE.txt: + +Copyright (c) 2016 Uber Technologies, Inc. + +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 : go.uber.org/goleak +Version: v1.3.0 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/go.uber.org/goleak@v1.3.0/LICENSE: + +The MIT License (MIT) + +Copyright (c) 2018 Uber Technologies, Inc. + +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 : go.uber.org/ratelimit +Version: v0.3.1 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/go.uber.org/ratelimit@v0.3.1/LICENSE: + +The MIT License (MIT) + +Copyright (c) 2016 Uber Technologies, Inc. + +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 : golang.org/x/exp +Version: v0.0.0-20240222234643-814bf88cf225 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/golang.org/x/exp@v0.0.0-20240222234643-814bf88cf225/LICENSE: + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +-------------------------------------------------------------------------------- +Dependency : golang.org/x/xerrors +Version: v0.0.0-20231012003039-104605ab7028 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/golang.org/x/xerrors@v0.0.0-20231012003039-104605ab7028/LICENSE: + +Copyright (c) 2019 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 : gonum.org/v1/gonum +Version: v0.15.0 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/gonum.org/v1/gonum@v0.15.0/LICENSE: + +Copyright ©2013 The Gonum 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 the Gonum project nor the names of its authors and + 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 HOLDER 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 : google.golang.org/genproto +Version: v0.0.0-20240730163845-b1a4ccb954bf Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/gopkg.in/jcmturner/goidentity.v3@v3.0.0/LICENSE: +Contents of probable licence file $GOMODCACHE/google.golang.org/genproto@v0.0.0-20240730163845-b1a4ccb954bf/LICENSE: + Apache License Version 2.0, January 2004 @@ -59631,7 +57827,7 @@ Contents of probable licence file $GOMODCACHE/gopkg.in/jcmturner/goidentity.v3@v 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 "{}" + 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 @@ -59639,7 +57835,7 @@ Contents of probable licence file $GOMODCACHE/gopkg.in/jcmturner/goidentity.v3@v same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright {yyyy} {name of copyright owner} + 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. @@ -59655,12 +57851,13 @@ Contents of probable licence file $GOMODCACHE/gopkg.in/jcmturner/goidentity.v3@v -------------------------------------------------------------------------------- -Dependency : gopkg.in/jcmturner/rpc.v1 -Version: v1.1.0 +Dependency : google.golang.org/genproto/googleapis/rpc +Version: v0.0.0-20240822170219-fc7c04adadcd Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/gopkg.in/jcmturner/rpc.v1@v1.1.0/LICENSE: +Contents of probable licence file $GOMODCACHE/google.golang.org/genproto/googleapis/rpc@v0.0.0-20240822170219-fc7c04adadcd/LICENSE: + Apache License Version 2.0, January 2004 @@ -59865,6 +58062,113 @@ Contents of probable licence file $GOMODCACHE/gopkg.in/jcmturner/rpc.v1@v1.1.0/L limitations under the License. +-------------------------------------------------------------------------------- +Dependency : gopkg.in/check.v1 +Version: v1.0.0-20201130134442-10cb98267c6c +Licence type (autodetected): BSD-2-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/gopkg.in/check.v1@v1.0.0-20201130134442-10cb98267c6c/LICENSE: + +Gocheck - A rich testing framework for Go + +Copyright (c) 2010-2013 Gustavo Niemeyer + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. 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. + +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/fsnotify.v1 +Version: v1.4.7 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/gopkg.in/fsnotify.v1@v1.4.7/LICENSE: + +Copyright (c) 2012 The Go Authors. All rights reserved. +Copyright (c) 2012 fsnotify 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/h2non/gock.v1 +Version: v1.1.2 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/gopkg.in/h2non/gock.v1@v1.1.2/LICENSE: + +The MIT License + +Copyright (c) 2016-2019 Tomas Aparicio + +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 : gopkg.in/mcuadros/go-syslog.v2 Version: v2.3.0 diff --git a/README.md b/README.md index 417436490c22..fff2a7527db1 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,6 @@ Beat | Description --- | --- [Auditbeat](https://github.com/elastic/beats/tree/main/auditbeat) | Collect your Linux audit framework data and monitor the integrity of your files. [Filebeat](https://github.com/elastic/beats/tree/main/filebeat) | Tails and ships log files -[Functionbeat](https://github.com/elastic/beats/tree/main/x-pack/functionbeat) | Read and ships events from serverless infrastructure. [Heartbeat](https://github.com/elastic/beats/tree/main/heartbeat) | Ping remote services for availability [Metricbeat](https://github.com/elastic/beats/tree/main/metricbeat) | Fetches sets of metrics from the operating system and services [Packetbeat](https://github.com/elastic/beats/tree/main/packetbeat) | Monitors the network and applications by sniffing packets @@ -41,7 +40,6 @@ on the [elastic.co site](https://www.elastic.co/guide/): * [Beats platform](https://www.elastic.co/guide/en/beats/libbeat/current/index.html) * [Auditbeat](https://www.elastic.co/guide/en/beats/auditbeat/current/index.html) * [Filebeat](https://www.elastic.co/guide/en/beats/filebeat/current/index.html) -* [Functionbeat](https://www.elastic.co/guide/en/beats/functionbeat/current/index.html) * [Heartbeat](https://www.elastic.co/guide/en/beats/heartbeat/current/index.html) * [Metricbeat](https://www.elastic.co/guide/en/beats/metricbeat/current/index.html) * [Packetbeat](https://www.elastic.co/guide/en/beats/packetbeat/current/index.html) diff --git a/auditbeat/helper/hasher/cached_hasher.go b/auditbeat/helper/hasher/cached_hasher.go new file mode 100644 index 000000000000..0af7bb01c74d --- /dev/null +++ b/auditbeat/helper/hasher/cached_hasher.go @@ -0,0 +1,221 @@ +// 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. + +//go:build linux + +package hasher + +import ( + "errors" + "time" + + lru "github.com/hashicorp/golang-lru/v2" + "golang.org/x/sys/unix" + + "github.com/elastic/elastic-agent-libs/logp" +) + +// CachedHasher is a metadata aware FileHasher with a LRU cache on top of it. +type CachedHasher struct { + hasher *FileHasher + hashLRU *lru.Cache[string, hashEntry] + hasStatx bool + stats CachedHasherStats + log *logp.Logger +} + +// CachedHasherStats are basics statistics for debugging and testing. +type CachedHasherStats struct { + Hits uint64 + Misses uint64 + Invalidations uint64 + Evictions uint64 +} + +// hashEntry is an entry in the LRU cache. +type hashEntry struct { + statx unix.Statx_t + hashes map[HashType]Digest +} + +// NewFileHasherWithCache creates a CachedHasher with space up to size elements. +func NewFileHasherWithCache(c Config, size int) (*CachedHasher, error) { + // We don't rate limit our hashes, we cache + c.ScanRateBytesPerSec = 0 + hasher, err := NewFileHasher(c, nil) + if err != nil { + return nil, err + } + hashLRU, err := lru.New[string, hashEntry](size) + if err != nil { + return nil, err + } + var nada unix.Statx_t + hasStatx := unix.Statx(-1, "/", 0, unix.STATX_ALL|unix.STATX_MNT_ID, &nada) != unix.ENOSYS + + return &CachedHasher{ + hasher: hasher, + hashLRU: hashLRU, + hasStatx: hasStatx, + log: logp.NewLogger("cached_hasher"), + }, nil +} + +// HashFile looks up a hashEntry in the cache, if the lookup fails, +// the hash is computed, inserted in the cache, and returned. If the +// lookup succeeds but the file metadata changed, the entry is evicted +// and refreshed. +func (ch *CachedHasher) HashFile(path string) (map[HashType]Digest, error) { + var x time.Time + if logp.IsDebug("cached_hasher") { + x = time.Now() + } + + // See if we have it stored + if entry, ok := ch.hashLRU.Get(path); ok { + statx, err := ch.statxFromPath(path) + if err != nil { + // No point in keeping an entry if we can't compare + if !ch.hashLRU.Remove(path) { + err := errors.New("can't remove existing entry, this is a bug") + ch.log.Error(err) + } + return nil, err + } + // If metadata didn't change, this is a good entry, if not fall and rehash + if statx == entry.statx { + ch.log.Debugf("hit (%s) took %v", path, time.Since(x)) + ch.stats.Hits++ + return entry.hashes, nil + } + // Zap from lru + if !ch.hashLRU.Remove(path) { + err := errors.New("can't remove existing entry, this is a bug") + ch.log.Error(err) + return nil, err + } else { + ch.stats.Invalidations++ + ch.log.Debugf("invalidate (%s)", path) + } + } + // Nah, so do the hard work + hashes, err := ch.hasher.HashFile(path) + if err != nil { + return nil, err + } + // Fetch metadata + statx, err := ch.statxFromPath(path) + if err != nil { + return nil, err + } + // Insert + entry := hashEntry{hashes: hashes, statx: statx} + if ch.hashLRU.Add(path, entry) { + ch.stats.Evictions++ + ch.log.Debugf("evict (%s)") + } + + ch.log.Debugf("miss (%s) took %v", path, time.Since(x)) + ch.stats.Misses++ + + return entry.hashes, nil +} + +// Close releases all resources +func (ch *CachedHasher) Close() { + ch.hashLRU.Purge() +} + +// Stats returns basic stats suitable for debugging and testing +func (ch *CachedHasher) Stats() CachedHasherStats { + return ch.stats +} + +// statxFromPath returns the metadata (unix.Statx_t) of path. In case +// the system doesn't support statx(2), it uses stat(2) and fills the +// corresponding members of unix.Statx_t, leaving the remaining members +// with a zero value. +func (ch *CachedHasher) statxFromPath(path string) (unix.Statx_t, error) { + if ch.hasStatx { + var tmpstx unix.Statx_t + err := unix.Statx(-1, path, 0, unix.STATX_ALL|unix.STATX_MNT_ID, &tmpstx) + if err != nil { + return unix.Statx_t{}, err + } + + // This might look stupid, but it guarantees we only compare + // the members we are really interested, unix.Statx_t grows + // with time, so if they ever add a member that changes all + // the time, we don't introduce a bug where we compare things + // we don't want to. + return unix.Statx_t{ + Mask: tmpstx.Mask, + Blksize: tmpstx.Blksize, + Attributes: tmpstx.Attributes, + Nlink: tmpstx.Nlink, + Uid: tmpstx.Uid, + Gid: tmpstx.Gid, + Mode: tmpstx.Mode, + Ino: tmpstx.Ino, + Size: tmpstx.Size, + Blocks: tmpstx.Blocks, + Attributes_mask: tmpstx.Attributes_mask, + Btime: tmpstx.Btime, + Ctime: tmpstx.Ctime, + Mtime: tmpstx.Mtime, + Rdev_minor: tmpstx.Rdev_minor, + Rdev_major: tmpstx.Rdev_major, + // no Atime + // no Dio_mem_align + // no Dio_offset_align + // no Subvol + // no Atomic_write_unit_min + // no Atomic_write_unit_max + // no Atomic_write_segments_max + }, nil + } + + // No statx(2), fallback to stat(2) + var st unix.Stat_t + if err := unix.Stat(path, &st); err != nil { + return unix.Statx_t{}, err + } + + return unix.Statx_t{ + Dev_major: unix.Major(st.Dev), + Dev_minor: unix.Minor(st.Dev), + Ino: st.Ino, + Nlink: uint32(st.Nlink), + Mode: uint16(st.Mode), + Uid: st.Uid, + Gid: st.Gid, + Rdev_major: unix.Major(st.Rdev), + Rdev_minor: unix.Minor(st.Rdev), + Size: uint64(st.Size), + Blksize: uint32(st.Blksize), + Blocks: uint64(st.Blocks), + Mtime: unix.StatxTimestamp{ + Nsec: uint32(st.Mtim.Nsec), + Sec: st.Mtim.Sec, + }, + Ctime: unix.StatxTimestamp{ + Nsec: uint32(st.Ctim.Nsec), + Sec: st.Ctim.Sec, + }, + // no Atime + }, nil +} diff --git a/auditbeat/helper/hasher/cached_hasher_test.go b/auditbeat/helper/hasher/cached_hasher_test.go new file mode 100644 index 000000000000..7b3374c865a6 --- /dev/null +++ b/auditbeat/helper/hasher/cached_hasher_test.go @@ -0,0 +1,151 @@ +// 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. + +//go:build linux + +package hasher + +import ( + "io" + "os" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +type pattern struct { + text []byte + md5 string + sha1 string + sha256 string + sha512 string + sha3_384 string +} + +var patternA = pattern{ + text: []byte("Rather than love, than money, than fame, give me truth.\n"), + md5: "572698a28f439d3c2647c67df75ed22f", + sha1: "511c4040962d493ba9cb2c0748137c11e42eb46b", + sha256: "19c76b22dd0bf97b0bf064e6587961938ba9f4ab73d034b0edac6c2c2829c0cd", + sha512: "e339322ed81208f930047e8b94db504f40a3e8bb2af75511925e3469488104edcd8eb8c613ea7fd0b08199a4d7061690512a05f66b50b4427470d6c8cf2d74a3", + sha3_384: "9961640983a079920f74f2503feb5ce63325d6a6cd0138905e9419c4307043fa324217587062ac8648cbf43138a33034", +} + +var patternB = pattern{ + text: []byte("From womb to tomb, in kindness and crime.\n"), + md5: "e3d72a80f13b9c1e4b07a7182b934502", + sha1: "90da69d7b93ef792e8e4506543506975018df980", + sha256: "67606f88f25357b2b101e94bd02fc5da8dd2993391b88596c15bea77780a6a77", + sha512: "23c3779d7c6a8d4be2ca7a0bf412a2c99ea2f8a95ac21f56e3b9cb1bd0c0427bf2db91bbb484128f53ef48fbbfc97e525b328e1c4c0f8d24dd8a3f438c449736", + sha3_384: "2034d02ad7b46831b9f2bf09b2eaa77bfcf70ebd136f29b95e6723cc6bf94d0fb7aae972dd2297b5507bb568cb65563b", +} + +var config = Config{ + HashTypes: []HashType{MD5, SHA1, SHA256, SHA512, SHA3_384}, + MaxFileSize: "1 KiB", + MaxFileSizeBytes: 1024, +} + +func TestCachedHasher(t *testing.T) { + ch, err := NewFileHasherWithCache(config, 1) + require.NoError(t, err) + doTestCachedHasher(t, ch) +} + +func TestCachedHasherWithStat(t *testing.T) { + ch, err := NewFileHasherWithCache(config, 1) + require.NoError(t, err) + ch.hasStatx = false + doTestCachedHasher(t, ch) +} + +func doTestCachedHasher(t *testing.T, ch *CachedHasher) { + // Create a file + file := mkTemp(t) + defer file.Close() + + // Write patternA and confirm first hash is a miss + writePattern(t, file, patternA) + ch.checkState(t, file.Name(), patternA, CachedHasherStats{Misses: 1}) + + // Prove a subsequent hash hits the cache + ch.checkState(t, file.Name(), patternA, CachedHasherStats{Misses: 1, Hits: 1}) + + // Prove changing access time still causes a hit. + // Note: we can't use os.Chtimes() to change _only_ atime, it + // might end up modifying mtime since it can round/truncate + // value we would get from file.Stat().ModTime() + time.Sleep(time.Millisecond * 2) + _, err := os.ReadFile(file.Name()) + require.NoError(t, err) + ch.checkState(t, file.Name(), patternA, CachedHasherStats{Misses: 1, Hits: 2}) + + // Prove changing mtime invalides the entry, and causes a miss + ostat, err := file.Stat() + require.NoError(t, err) + mtime := ostat.ModTime().Add(time.Hour) + require.NoError(t, os.Chtimes(file.Name(), mtime, mtime)) + ch.checkState(t, file.Name(), patternA, CachedHasherStats{Misses: 2, Hits: 2, Invalidations: 1}) + + // Write the second pattern, prove it's a miss + writePattern(t, file, patternB) + ch.checkState(t, file.Name(), patternB, CachedHasherStats{Misses: 3, Hits: 2, Invalidations: 2}) + + // Hash something else, prove first one is evicted + file2 := mkTemp(t) + defer file2.Close() + writePattern(t, file2, patternA) + ch.checkState(t, file2.Name(), patternA, CachedHasherStats{Misses: 4, Hits: 2, Invalidations: 2, Evictions: 1}) + + // If we go back and lookup the original path, prove we should evict again and it's a miss + ch.checkState(t, file.Name(), patternB, CachedHasherStats{Misses: 5, Hits: 2, Invalidations: 2, Evictions: 2}) + + // If we close, prove we purge + require.Equal(t, ch.hashLRU.Len(), 1) + ch.Close() + require.Equal(t, ch.hashLRU.Len(), 0) +} + +func mkTemp(t *testing.T) *os.File { + file, err := os.CreateTemp(t.TempDir(), "cached_hasher_test_*") + require.NoError(t, err) + + return file +} + +func writePattern(t *testing.T, file *os.File, p pattern) { + err := file.Truncate(0) + require.NoError(t, err) + _, err = file.Seek(0, io.SeekStart) + require.NoError(t, err) + n, err := file.Write(p.text) + require.NoError(t, err) + require.Equal(t, n, len(p.text)) +} + +func (ch *CachedHasher) checkState(t *testing.T, path string, p pattern, stats CachedHasherStats) { + hashes, err := ch.HashFile(path) + require.NoError(t, err) + require.Len(t, hashes, 5) + require.Equal(t, p.md5, hashes["md5"].String()) + require.Equal(t, p.sha1, hashes["sha1"].String()) + require.Equal(t, p.sha256, hashes["sha256"].String()) + require.Equal(t, p.sha512, hashes["sha512"].String()) + require.Equal(t, p.sha3_384, hashes["sha3_384"].String()) + require.Equal(t, stats, ch.Stats()) +} diff --git a/auditbeat/helper/hasher/hasher.go b/auditbeat/helper/hasher/hasher.go index d0612ab731df..4f97f5705a74 100644 --- a/auditbeat/helper/hasher/hasher.go +++ b/auditbeat/helper/hasher/hasher.go @@ -26,7 +26,6 @@ import ( "fmt" "hash" "io" - "os" "strings" "time" @@ -124,7 +123,7 @@ type FileTooLargeError struct { // Error returns the error message for FileTooLargeError. func (e FileTooLargeError) Error() string { - return fmt.Sprintf("hasher: file size %d exceeds max file size", e.fileSize) + return fmt.Sprintf("size %d exceeds max file size", e.fileSize) } // Config contains the configuration of a FileHasher. @@ -174,11 +173,19 @@ type FileHasher struct { // NewFileHasher creates a new FileHasher. func NewFileHasher(c Config, done <-chan struct{}) (*FileHasher, error) { + var limit rate.Limit + + if c.ScanRateBytesPerSec == 0 { + limit = rate.Inf + } else { + limit = rate.Limit(c.ScanRateBytesPerSec) + } + return &FileHasher{ config: c, limiter: rate.NewLimiter( - rate.Limit(c.ScanRateBytesPerSec), // Rate - int(c.MaxFileSizeBytes), // Burst + limit, // Rate + int(c.MaxFileSizeBytes), // Burst ), done: done, }, nil @@ -186,16 +193,26 @@ func NewFileHasher(c Config, done <-chan struct{}) (*FileHasher, error) { // HashFile hashes the contents of a file. func (hasher *FileHasher) HashFile(path string) (map[HashType]Digest, error) { - info, err := os.Stat(path) + f, err := file.ReadOpen(path) if err != nil { - return nil, fmt.Errorf("failed to stat file %v: %w", path, err) + return nil, fmt.Errorf("open: %w", err) + } + defer f.Close() + + info, err := f.Stat() + if err != nil { + return nil, fmt.Errorf("stat: %w", err) + } + if !info.Mode().IsRegular() { + return nil, fmt.Errorf("not a regular file") + } // Throttle reading and hashing rate. if len(hasher.config.HashTypes) > 0 { err = hasher.throttle(info.Size()) if err != nil { - return nil, fmt.Errorf("failed to hash file %v: %w", path, err) + return nil, err } } @@ -210,15 +227,9 @@ func (hasher *FileHasher) HashFile(path string) (map[HashType]Digest, error) { } if len(hashes) > 0 { - f, err := file.ReadOpen(path) - if err != nil { - return nil, fmt.Errorf("failed to open file for hashing: %w", err) - } - defer f.Close() - hashWriter := multiWriter(hashes) if _, err := io.Copy(hashWriter, f); err != nil { - return nil, fmt.Errorf("failed to calculate file hashes: %w", err) + return nil, err } nameToHash := make(map[HashType]Digest, len(hashes)) @@ -233,6 +244,10 @@ func (hasher *FileHasher) HashFile(path string) (map[HashType]Digest, error) { } func (hasher *FileHasher) throttle(fileSize int64) error { + // Burst is ignored if limit is infinite, so check it manually + if hasher.limiter.Limit() == rate.Inf && int(fileSize) > hasher.limiter.Burst() { + return FileTooLargeError{fileSize} + } reservation := hasher.limiter.ReserveN(time.Now(), int(fileSize)) if !reservation.OK() { // File is bigger than the max file size diff --git a/auditbeat/helper/tty/tty.go b/auditbeat/helper/tty/tty.go new file mode 100644 index 000000000000..509fa6b9aa68 --- /dev/null +++ b/auditbeat/helper/tty/tty.go @@ -0,0 +1,76 @@ +// 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 tty + +type TTYType int + +const ( + TTYUnknown TTYType = iota + Pts + TTY + TTYConsole +) + +const ( + ptsMinMajor = 136 + ptsMaxMajor = 143 + ttyMajor = 4 + consoleMaxMinor = 63 + ttyMaxMinor = 255 +) + +type TTYDev struct { + Minor uint32 + Major uint32 + Winsize TTYWinsize + Termios TTYTermios +} + +type TTYWinsize struct { + Rows uint16 + Cols uint16 +} + +type TTYTermios struct { + CIflag uint32 + COflag uint32 + CLflag uint32 + CCflag uint32 +} + +// interactiveFromTTY returns if this is an interactive tty device. +func InteractiveFromTTY(tty TTYDev) bool { + return TTYUnknown != GetTTYType(tty.Major, tty.Minor) +} + +// getTTYType returns the type of a TTY device based on its major and minor numbers. +func GetTTYType(major uint32, minor uint32) TTYType { + if major >= ptsMinMajor && major <= ptsMaxMajor { + return Pts + } + + if ttyMajor == major { + if minor <= consoleMaxMinor { + return TTYConsole + } else if minor > consoleMaxMinor && minor <= ttyMaxMinor { + return TTY + } + } + + return TTYUnknown +} diff --git a/catalog-info.yaml b/catalog-info.yaml index a0eca0c2c9f6..16d4bd7e0d0b 100644 --- a/catalog-info.yaml +++ b/catalog-info.yaml @@ -31,7 +31,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -81,7 +81,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -128,7 +128,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -175,7 +175,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -222,7 +222,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -269,7 +269,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -316,7 +316,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -363,7 +363,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -410,7 +410,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -456,7 +456,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -503,7 +503,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -550,7 +550,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -597,7 +597,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -644,7 +644,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -690,7 +690,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -725,7 +725,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -761,7 +761,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -808,7 +808,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -855,7 +855,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -902,7 +902,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -949,7 +949,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -996,7 +996,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -1043,7 +1043,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -1092,7 +1092,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -1128,7 +1128,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -1162,7 +1162,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline @@ -1205,7 +1205,7 @@ metadata: spec: type: buildkite-pipeline owner: group:ingest-fp - system: buildkite + system: platform-ingest implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline diff --git a/dev-tools/cmd/update_go/update_go_version.go b/dev-tools/cmd/update_go/update_go_version.go index f589abc756dd..df7f74747c1e 100644 --- a/dev-tools/cmd/update_go/update_go_version.go +++ b/dev-tools/cmd/update_go/update_go_version.go @@ -34,7 +34,6 @@ var files = []string{ "libbeat/docs/version.asciidoc", "metricbeat/Dockerfile", "metricbeat/module/http/_meta/Dockerfile", - "x-pack/functionbeat/Dockerfile", "x-pack/libbeat/Dockerfile", } diff --git a/dev-tools/mage/integtest_docker.go b/dev-tools/mage/integtest_docker.go index 8c5fb6d3603f..ea29d993b272 100644 --- a/dev-tools/mage/integtest_docker.go +++ b/dev-tools/mage/integtest_docker.go @@ -22,7 +22,6 @@ import ( "fmt" "go/build" "io" - "io/ioutil" "os" "path" "path/filepath" @@ -99,11 +98,9 @@ func (d *DockerIntegrationTester) Test(dir string, mageTarget string, env map[st if err != nil { return err } - dockerRepoRoot := filepath.Join("/go/src", repo.CanonicalRootImportPath) - dockerGoCache := filepath.Join(dockerRepoRoot, "build/docker-gocache") magePath := filepath.Join("/go/src", repo.CanonicalRootImportPath, repo.SubDir, "build/mage-linux-"+GOARCH) - goPkgCache := filepath.Join(filepath.SplitList(build.Default.GOPATH)[0], "pkg/mod/cache/download") - dockerGoPkgCache := "/gocache" + goPkgCache := filepath.Join(filepath.SplitList(build.Default.GOPATH)[0], "pkg/mod") + dockerGoPkgCache := "/go/pkg/mod" // Execute the inside of docker-compose. args := []string{"-p", DockerComposeProjectName(), "run", @@ -114,10 +111,8 @@ func (d *DockerIntegrationTester) Test(dir string, mageTarget string, env map[st // compose.EnsureUp needs to know the environment type. "-e", "STACK_ENVIRONMENT=" + StackEnvironment, "-e", "TESTING_ENVIRONMENT=" + StackEnvironment, - "-e", "GOCACHE=" + dockerGoCache, // Use the host machine's pkg cache to minimize external downloads. - "-v", goPkgCache + ":" + dockerGoPkgCache + ":ro", - "-e", "GOPROXY=file://" + dockerGoPkgCache + ",direct", + "-v", goPkgCache + ":" + dockerGoPkgCache, } args, err = addUidGidEnvArgs(args) if err != nil { @@ -356,7 +351,7 @@ func StartIntegTestContainers() error { func StopIntegTestContainers() error { // Docker-compose rm is noisy. So only pass through stderr when in verbose. - out := ioutil.Discard + out := io.Discard if mg.Verbose() { out = os.Stderr } @@ -368,7 +363,7 @@ func StopIntegTestContainers() error { _, err = sh.Exec( composeEnv, - ioutil.Discard, + io.Discard, out, "docker-compose", "-p", DockerComposeProjectName(), diff --git a/dev-tools/mage/kubernetes/kind.go b/dev-tools/mage/kubernetes/kind.go index 133f305fedd2..43ef37e10a4a 100644 --- a/dev-tools/mage/kubernetes/kind.go +++ b/dev-tools/mage/kubernetes/kind.go @@ -19,7 +19,8 @@ package kubernetes import ( "fmt" - "io/ioutil" + "go/build" + "io" "os" "os/exec" "path/filepath" @@ -66,8 +67,8 @@ func (m *KindIntegrationTestStep) Setup(env map[string]string) error { } clusterName := kubernetesClusterName() - stdOut := ioutil.Discard - stdErr := ioutil.Discard + stdOut := io.Discard + stdErr := io.Discard if mg.Verbose() { stdOut = os.Stdout stdErr = os.Stderr @@ -86,9 +87,29 @@ func (m *KindIntegrationTestStep) Setup(env map[string]string) error { return err } + cfg, err := os.CreateTemp("", "kind-") + if err != nil { + return err + } + if _, err := cfg.WriteString(fmt.Sprintf(` +apiVersion: kind.x-k8s.io/v1alpha4 +kind: Cluster +nodes: + - role: control-plane + extraMounts: + - hostPath: %s + containerPath: /go/pkg/mod +`, filepath.Join(build.Default.GOPATH, "pkg", "mod"))); err != nil { + return err + } + if err := cfg.Close(); err != nil { + return err + } + args := []string{ "create", "cluster", + "--config", cfg.Name(), "--name", clusterName, "--kubeconfig", kubeConfig, "--wait", @@ -116,8 +137,8 @@ func (m *KindIntegrationTestStep) Setup(env map[string]string) error { // Teardown destroys the kubernetes cluster. func (m *KindIntegrationTestStep) Teardown(env map[string]string) error { - stdOut := ioutil.Discard - stdErr := ioutil.Discard + stdOut := io.Discard + stdErr := io.Discard if mg.Verbose() { stdOut = os.Stdout stdErr = os.Stderr diff --git a/dev-tools/mage/kubernetes/kuberemote.go b/dev-tools/mage/kubernetes/kuberemote.go index e3062f00d1ad..fb028dc94db3 100644 --- a/dev-tools/mage/kubernetes/kuberemote.go +++ b/dev-tools/mage/kubernetes/kuberemote.go @@ -23,14 +23,14 @@ import ( "crypto/rand" "crypto/rsa" "crypto/x509" - "encoding/hex" "encoding/pem" "fmt" "io" - "io/ioutil" + "log" "net" "net/http" "net/url" + "os" "os/exec" "strings" "time" @@ -127,11 +127,17 @@ func (r *KubeRemote) Run(env map[string]string, stdout io.Writer, stderr io.Writ if err != nil { return err } - go f.ForwardPorts() + go func() { + if err := f.ForwardPorts(); err != nil { + log.Printf("forward port error: %v\n", err) + } + }() <-readyChannel // perform the rsync - r.rsync(randomPort, stderr, stderr) + if err := r.rsync(randomPort, stderr, stderr, r.syncDir, r.destDir); err != nil { + return fmt.Errorf("rsync failed: %w", err) + } // stop port forwarding close(stopChannel) @@ -258,14 +264,14 @@ func (r *KubeRemote) portForward(ports []string, stopChannel, readyChannel chan } path := fmt.Sprintf("/api/v1/namespaces/%s/pods/%s/portforward", r.namespace, r.name) - hostIP := strings.TrimLeft(r.cfg.Host, "https://") + hostIP := strings.TrimPrefix(r.cfg.Host, "https://") serverURL := url.URL{Scheme: "https", Path: path, Host: hostIP} dialer := spdy.NewDialer(upgrader, &http.Client{Transport: roundTripper}, http.MethodPost, &serverURL) return portforward.New(dialer, ports, stopChannel, readyChannel, stdout, stderr) } // rsync performs the rsync of sync directory to destination directory inside of the pod. -func (r *KubeRemote) rsync(port uint16, stdout, stderr io.Writer) error { +func (r *KubeRemote) rsync(port uint16, stdout, stderr io.Writer, src string, dst string) error { privateKeyFile, err := createTempFile(r.privateKey) if err != nil { return err @@ -274,8 +280,8 @@ func (r *KubeRemote) rsync(port uint16, stdout, stderr io.Writer) error { rsh := fmt.Sprintf("ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -p %d -i %s", port, privateKeyFile) args := []string{ "--rsh", rsh, - "-a", fmt.Sprintf("%s/", r.syncDir), - fmt.Sprintf("root@localhost:%s", r.destDir), + "-a", fmt.Sprintf("%s/", src), + fmt.Sprintf("root@localhost:%s", dst), } cmd := exec.Command("rsync", args...) cmd.Stdout = stdout @@ -491,6 +497,10 @@ func createPodManifest(name string, image string, env map[string]string, cmd []s Name: "destdir", MountPath: destDir, }, + { + Name: "gomodcache", + MountPath: "/go/pkg/mod", + }, }, }, }, @@ -510,6 +520,14 @@ func createPodManifest(name string, image string, env map[string]string, cmd []s EmptyDir: &apiv1.EmptyDirVolumeSource{}, }, }, + { + Name: "gomodcache", + VolumeSource: apiv1.VolumeSource{ + HostPath: &apiv1.HostPathVolumeSource{ + Path: "/go/pkg/mod", + }, + }, + }, }, }, } @@ -542,7 +560,7 @@ func isInitContainersReady(pod *apiv1.Pod) bool { } func isScheduled(pod *apiv1.Pod) bool { - if &pod.Status != nil && len(pod.Status.Conditions) > 0 { + if len(pod.Status.Conditions) > 0 { for _, condition := range pod.Status.Conditions { if condition.Type == apiv1.PodScheduled && condition.Status == apiv1.ConditionTrue { @@ -554,18 +572,15 @@ func isScheduled(pod *apiv1.Pod) bool { } func isInitContainersRunning(pod *apiv1.Pod) bool { - if &pod.Status != nil { - if len(pod.Spec.InitContainers) != len(pod.Status.InitContainerStatuses) { + if len(pod.Spec.InitContainers) != len(pod.Status.InitContainerStatuses) { + return false + } + for _, status := range pod.Status.InitContainerStatuses { + if status.State.Running == nil { return false } - for _, status := range pod.Status.InitContainerStatuses { - if status.State.Running == nil { - return false - } - } - return true } - return false + return true } func containerRunning(containerName string) func(watch.Event) (bool, error) { @@ -620,9 +635,7 @@ func podDone(event watch.Event) (bool, error) { } func createTempFile(content []byte) (string, error) { - randBytes := make([]byte, 16) - rand.Read(randBytes) - tmpfile, err := ioutil.TempFile("", hex.EncodeToString(randBytes)) + tmpfile, err := os.CreateTemp("", "kuberemote-") if err != nil { return "", err } diff --git a/dev-tools/packaging/templates/ironbank/auditbeat/Dockerfile b/dev-tools/packaging/templates/ironbank/auditbeat/Dockerfile index b675b42cc968..893e84d57e36 100644 --- a/dev-tools/packaging/templates/ironbank/auditbeat/Dockerfile +++ b/dev-tools/packaging/templates/ironbank/auditbeat/Dockerfile @@ -4,7 +4,7 @@ ################################################################################ ARG BASE_REGISTRY=registry1.dsop.io ARG BASE_IMAGE=redhat/ubi/ubi9 -ARG BASE_TAG=9.4 +ARG BASE_TAG=9.5 FROM ${BASE_REGISTRY}/${BASE_IMAGE}:${BASE_TAG} as builder diff --git a/dev-tools/packaging/templates/ironbank/auditbeat/hardening_manifest.yaml b/dev-tools/packaging/templates/ironbank/auditbeat/hardening_manifest.yaml index dc633355fa75..ff5c9bb42ed9 100644 --- a/dev-tools/packaging/templates/ironbank/auditbeat/hardening_manifest.yaml +++ b/dev-tools/packaging/templates/ironbank/auditbeat/hardening_manifest.yaml @@ -14,7 +14,7 @@ tags: # Build args passed to Dockerfile ARGs args: BASE_IMAGE: "redhat/ubi/ubi9" - BASE_TAG: "9.4" + BASE_TAG: "9.5" ELASTIC_STACK: "{{ beat_version }}" ELASTIC_PRODUCT: "auditbeat" @@ -52,9 +52,6 @@ resources: # List of project maintainers maintainers: - - email: "nassim.kammah@elastic.co" - name: "Nassim Kammah" - username: "nassim.kammah" - email: "julien.lind@elastic.co" name: "Julien lind" username: "julien.lind" diff --git a/dev-tools/packaging/templates/ironbank/filebeat/Dockerfile b/dev-tools/packaging/templates/ironbank/filebeat/Dockerfile index c0738aca6c43..dc4f7bb49ea9 100644 --- a/dev-tools/packaging/templates/ironbank/filebeat/Dockerfile +++ b/dev-tools/packaging/templates/ironbank/filebeat/Dockerfile @@ -4,7 +4,7 @@ ################################################################################ ARG BASE_REGISTRY=registry1.dsop.io ARG BASE_IMAGE=redhat/ubi/ubi9 -ARG BASE_TAG=9.4 +ARG BASE_TAG=9.5 FROM ${BASE_REGISTRY}/${BASE_IMAGE}:${BASE_TAG} as builder diff --git a/dev-tools/packaging/templates/ironbank/filebeat/hardening_manifest.yaml b/dev-tools/packaging/templates/ironbank/filebeat/hardening_manifest.yaml index dce9bcee5b0b..1f89df0d0ce5 100644 --- a/dev-tools/packaging/templates/ironbank/filebeat/hardening_manifest.yaml +++ b/dev-tools/packaging/templates/ironbank/filebeat/hardening_manifest.yaml @@ -14,7 +14,7 @@ tags: # Build args passed to Dockerfile ARGs args: BASE_IMAGE: "redhat/ubi/ubi9" - BASE_TAG: "9.4" + BASE_TAG: "9.5" ELASTIC_STACK: "{{ beat_version }}" ELASTIC_PRODUCT: "filebeat" @@ -52,9 +52,6 @@ resources: # List of project maintainers maintainers: - - email: "nassim.kammah@elastic.co" - name: "Nassim Kammah" - username: "nassim.kammah" - email: "julien.lind@elastic.co" name: "Julien lind" username: "julien.lind" diff --git a/dev-tools/packaging/templates/ironbank/heartbeat/Dockerfile b/dev-tools/packaging/templates/ironbank/heartbeat/Dockerfile index bd384920ad30..c71357b8478e 100644 --- a/dev-tools/packaging/templates/ironbank/heartbeat/Dockerfile +++ b/dev-tools/packaging/templates/ironbank/heartbeat/Dockerfile @@ -4,7 +4,7 @@ ################################################################################ ARG BASE_REGISTRY=registry1.dsop.io ARG BASE_IMAGE=redhat/ubi/ubi9 -ARG BASE_TAG=9.4 +ARG BASE_TAG=9.5 FROM ${BASE_REGISTRY}/${BASE_IMAGE}:${BASE_TAG} as prep_files diff --git a/dev-tools/packaging/templates/ironbank/heartbeat/hardening_manifest.yaml b/dev-tools/packaging/templates/ironbank/heartbeat/hardening_manifest.yaml index 8c08b0020c29..18c4ee47b367 100644 --- a/dev-tools/packaging/templates/ironbank/heartbeat/hardening_manifest.yaml +++ b/dev-tools/packaging/templates/ironbank/heartbeat/hardening_manifest.yaml @@ -14,7 +14,7 @@ tags: # Build args passed to Dockerfile ARGs args: BASE_IMAGE: "redhat/ubi/ubi9" - BASE_TAG: "9.4" + BASE_TAG: "9.5" ELASTIC_STACK: "{{ beat_version }}" ELASTIC_PRODUCT: "heartbeat" @@ -52,9 +52,6 @@ resources: # List of project maintainers maintainers: - - email: "nassim.kammah@elastic.co" - name: "Nassim Kammah" - username: "nassim.kammah" - email: "julien.lind@elastic.co" name: "Julien lind" username: "julien.lind" diff --git a/dev-tools/packaging/templates/ironbank/metricbeat/Dockerfile b/dev-tools/packaging/templates/ironbank/metricbeat/Dockerfile index 54394e24b1d4..cee8fe1fe6fa 100644 --- a/dev-tools/packaging/templates/ironbank/metricbeat/Dockerfile +++ b/dev-tools/packaging/templates/ironbank/metricbeat/Dockerfile @@ -4,7 +4,7 @@ ################################################################################ ARG BASE_REGISTRY=registry1.dsop.io ARG BASE_IMAGE=redhat/ubi/ubi9 -ARG BASE_TAG=9.4 +ARG BASE_TAG=9.5 FROM ${BASE_REGISTRY}/${BASE_IMAGE}:${BASE_TAG} as builder diff --git a/dev-tools/packaging/templates/ironbank/metricbeat/hardening_manifest.yaml b/dev-tools/packaging/templates/ironbank/metricbeat/hardening_manifest.yaml index 299d443b412c..6635eb872770 100644 --- a/dev-tools/packaging/templates/ironbank/metricbeat/hardening_manifest.yaml +++ b/dev-tools/packaging/templates/ironbank/metricbeat/hardening_manifest.yaml @@ -14,7 +14,7 @@ tags: # Build args passed to Dockerfile ARGs args: BASE_IMAGE: "redhat/ubi/ubi9" - BASE_TAG: "9.4" + BASE_TAG: "9.5" ELASTIC_STACK: "{{ beat_version }}" ELASTIC_PRODUCT: "metricbeat" @@ -52,9 +52,6 @@ resources: # List of project maintainers maintainers: - - email: "nassim.kammah@elastic.co" - name: "Nassim Kammah" - username: "nassim.kammah" - email: "julien.lind@elastic.co" name: "Julien lind" username: "julien.lind" diff --git a/dev-tools/packaging/templates/ironbank/packetbeat/Dockerfile b/dev-tools/packaging/templates/ironbank/packetbeat/Dockerfile index 8d6750c1a331..e7a025ef6aa0 100644 --- a/dev-tools/packaging/templates/ironbank/packetbeat/Dockerfile +++ b/dev-tools/packaging/templates/ironbank/packetbeat/Dockerfile @@ -4,7 +4,7 @@ ################################################################################ ARG BASE_REGISTRY=registry1.dsop.io ARG BASE_IMAGE=redhat/ubi/ubi9 -ARG BASE_TAG=9.4 +ARG BASE_TAG=9.5 FROM ${BASE_REGISTRY}/${BASE_IMAGE}:${BASE_TAG} as builder diff --git a/dev-tools/packaging/templates/ironbank/packetbeat/hardening_manifest.yaml b/dev-tools/packaging/templates/ironbank/packetbeat/hardening_manifest.yaml index c7a6c9490bb6..d7b97a92f87d 100644 --- a/dev-tools/packaging/templates/ironbank/packetbeat/hardening_manifest.yaml +++ b/dev-tools/packaging/templates/ironbank/packetbeat/hardening_manifest.yaml @@ -14,7 +14,7 @@ tags: # Build args passed to Dockerfile ARGs args: BASE_IMAGE: "redhat/ubi/ubi9" - BASE_TAG: "9.4" + BASE_TAG: "9.5" ELASTIC_STACK: "{{ beat_version }}" ELASTIC_PRODUCT: "packetbeat" @@ -52,9 +52,6 @@ resources: # List of project maintainers maintainers: - - email: "nassim.kammah@elastic.co" - name: "Nassim Kammah" - username: "nassim.kammah" - email: "julien.lind@elastic.co" name: "Julien lind" username: "julien.lind" diff --git a/docs/devguide/documentation.asciidoc b/docs/devguide/documentation.asciidoc index d81f79ccb40e..82e12a2721bb 100644 --- a/docs/devguide/documentation.asciidoc +++ b/docs/devguide/documentation.asciidoc @@ -69,7 +69,7 @@ doc collector scripts to regenerate the docs. Make sure you <> and use the correct Go version. The Go version is listed in the `version.asciidoc` file -for the branch you want to update. +for the branch you want to update. To run the docs collector scripts, change to the beats directory and run: @@ -108,7 +108,6 @@ generates * `auditbeat/docs/fields.asciidoc` * `filebeat/docs/fields.asciidoc` -* `functionbeat/docs/fields.asciidoc` * `heartbeat/docs/fields.asciidoc` * `metricbeat/docs/fields.asciidoc` * `packetbeat/docs/fields.asciidoc` diff --git a/docs/devguide/testing.asciidoc b/docs/devguide/testing.asciidoc index 9488fe47dcee..07f2ae21025c 100644 --- a/docs/devguide/testing.asciidoc +++ b/docs/devguide/testing.asciidoc @@ -25,6 +25,8 @@ Integration tests are labelled with the `//go:build integration` build tag and u To run the integration tests use the `mage goIntegTest` target, which will start the required services using https://docs.docker.com/compose/[docker-compose] and run all integration tests. +It is also possible to run module specific integration tests. For example, to run kafka only tests use `MODULE=kafka mage integTest -v` + It is possible to start the `docker-compose` services manually to allow selecting which specific tests should be run. An example follows for filebeat: [source,bash] diff --git a/filebeat/autodiscover/builder/hints/logs_test.go b/filebeat/autodiscover/builder/hints/logs_test.go index 5e76c8d53440..402ceadfde44 100644 --- a/filebeat/autodiscover/builder/hints/logs_test.go +++ b/filebeat/autodiscover/builder/hints/logs_test.go @@ -18,6 +18,7 @@ package hints import ( + "os" "path/filepath" "testing" @@ -30,8 +31,10 @@ import ( "github.com/elastic/elastic-agent-libs/paths" ) -func TestMain(t *testing.M) { +func TestMain(m *testing.M) { InitializeModule() + + os.Exit(m.Run()) } func TestGenerateHints(t *testing.T) { diff --git a/filebeat/beater/filebeat.go b/filebeat/beater/filebeat.go index 815b6fabfde2..4909941b90ae 100644 --- a/filebeat/beater/filebeat.go +++ b/filebeat/beater/filebeat.go @@ -32,6 +32,7 @@ import ( "github.com/elastic/beats/v7/filebeat/fileset" _ "github.com/elastic/beats/v7/filebeat/include" "github.com/elastic/beats/v7/filebeat/input" + "github.com/elastic/beats/v7/filebeat/input/filestream" "github.com/elastic/beats/v7/filebeat/input/filestream/takeover" v2 "github.com/elastic/beats/v7/filebeat/input/v2" "github.com/elastic/beats/v7/filebeat/input/v2/compat" @@ -271,10 +272,18 @@ func (fb *Filebeat) Run(b *beat.Beat) error { waitEvents := newSignalWait() // count active events for waiting on shutdown + var reg *monitoring.Registry + + if b.Info.Monitoring.Namespace != nil { + reg = b.Info.Monitoring.Namespace.GetRegistry().GetRegistry("stats") + if reg == nil { + reg = b.Info.Monitoring.Namespace.GetRegistry().NewRegistry("stats") + } + } wgEvents := &eventCounter{ - count: monitoring.NewInt(nil, "filebeat.events.active"), // Gauge - added: monitoring.NewUint(nil, "filebeat.events.added"), - done: monitoring.NewUint(nil, "filebeat.events.done"), + count: monitoring.NewInt(reg, "filebeat.events.active"), // Gauge + added: monitoring.NewUint(reg, "filebeat.events.added"), + done: monitoring.NewUint(reg, "filebeat.events.done"), } finishedLogger := newFinishedLogger(wgEvents) @@ -291,6 +300,11 @@ func (fb *Filebeat) Run(b *beat.Beat) error { } defer stateStore.Close() + err = filestream.ValidateInputIDs(config.Inputs, logp.NewLogger("input.filestream")) + if err != nil { + logp.Err("invalid filestream configuration: %+v", err) + return err + } err = processLogInputTakeOver(stateStore, config) if err != nil { logp.Err("Failed to attempt filestream state take over: %+v", err) diff --git a/filebeat/channel/outlet.go b/filebeat/channel/outlet.go index fd5c9b12fc15..257470463961 100644 --- a/filebeat/channel/outlet.go +++ b/filebeat/channel/outlet.go @@ -18,8 +18,9 @@ package channel import ( + "sync/atomic" + "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/common/atomic" ) type outlet struct { @@ -31,15 +32,14 @@ type outlet struct { func newOutlet(client beat.Client) *outlet { o := &outlet{ client: client, - isOpen: atomic.MakeBool(true), done: make(chan struct{}), } + o.isOpen.Store(true) return o } func (o *outlet) Close() error { - isOpen := o.isOpen.Swap(false) - if isOpen { + if o.isOpen.Swap(false) { close(o.done) return o.client.Close() } diff --git a/filebeat/docs/filebeat-options.asciidoc b/filebeat/docs/filebeat-options.asciidoc index 3b1d274d59bd..5e77999a00b3 100644 --- a/filebeat/docs/filebeat-options.asciidoc +++ b/filebeat/docs/filebeat-options.asciidoc @@ -95,6 +95,7 @@ You can configure {beatname_uc} to use the following inputs: * <<{beatname_lc}-input-syslog>> * <<{beatname_lc}-input-tcp>> * <<{beatname_lc}-input-udp>> +* <<{beatname_lc}-input-unifiedlogs>> * <<{beatname_lc}-input-unix>> * <<{beatname_lc}-input-winlog>> @@ -158,6 +159,8 @@ include::inputs/input-tcp.asciidoc[] include::inputs/input-udp.asciidoc[] +include::../../x-pack/filebeat/docs/inputs/input-unifiedlogs.asciidoc[] + include::inputs/input-unix.asciidoc[] include::inputs/input-winlog.asciidoc[] diff --git a/filebeat/docs/include/use-journald.asciidoc b/filebeat/docs/include/use-journald.asciidoc new file mode 100644 index 000000000000..acfc8b2d94ac --- /dev/null +++ b/filebeat/docs/include/use-journald.asciidoc @@ -0,0 +1,4 @@ +*`var.use_journald`*:: + +A boolean that when set to `true` will read logs from Journald. When +Journald is used all events contain the tag `journald`. \ No newline at end of file diff --git a/filebeat/docs/inputs/input-kafka.asciidoc b/filebeat/docs/inputs/input-kafka.asciidoc index ee0cd7842a46..360218bb74b0 100644 --- a/filebeat/docs/inputs/input-kafka.asciidoc +++ b/filebeat/docs/inputs/input-kafka.asciidoc @@ -89,7 +89,7 @@ The Kafka client id (optional). [float] ===== `version` -The version of the Kafka protocol to use (defaults to `"1.0.0"`). +The version of the Kafka protocol to use (defaults to `"2.1.0"`). When using Kafka 4.0 and newer, the version must be set to at least `"2.1.0"`. [float] ===== `initial_offset` diff --git a/filebeat/docs/modules/system.asciidoc b/filebeat/docs/modules/system.asciidoc index 1866f2d5c259..f0fa06b8c4f5 100644 --- a/filebeat/docs/modules/system.asciidoc +++ b/filebeat/docs/modules/system.asciidoc @@ -64,11 +64,13 @@ include::../include/config-option-intro.asciidoc[] ==== `syslog` fileset settings include::../include/var-paths.asciidoc[] +include::../include/use-journald.asciidoc[] [float] ==== `auth` fileset settings include::../include/var-paths.asciidoc[] +include::../include/use-journald.asciidoc[] *`var.tags`*:: diff --git a/filebeat/filebeat.reference.yml b/filebeat/filebeat.reference.yml index 14e9f276fb49..a8fc37fbbe8b 100644 --- a/filebeat/filebeat.reference.yml +++ b/filebeat/filebeat.reference.yml @@ -21,6 +21,9 @@ filebeat.modules: # Filebeat will choose the paths depending on your OS. #var.paths: + # Use journald to collect system logs + #var.use_journald: false + # Input configuration (advanced). Any input configuration option # can be added under this section. #input: @@ -33,6 +36,9 @@ filebeat.modules: # Filebeat will choose the paths depending on your OS. #var.paths: + # Use journald to collect auth logs + #var.use_journald: false + # Input configuration (advanced). Any input configuration option # can be added under this section. #input: diff --git a/filebeat/input/filestream/config.go b/filebeat/input/filestream/config.go index 1cb8fa5da979..2860dd673c23 100644 --- a/filebeat/input/filestream/config.go +++ b/filebeat/input/filestream/config.go @@ -19,6 +19,7 @@ package filestream import ( "fmt" + "strings" "time" "github.com/dustin/go-humanize" @@ -27,6 +28,7 @@ import ( "github.com/elastic/beats/v7/libbeat/reader/parser" "github.com/elastic/beats/v7/libbeat/reader/readfile" conf "github.com/elastic/elastic-agent-libs/config" + "github.com/elastic/elastic-agent-libs/logp" ) // Config stores the options of a file stream. @@ -142,3 +144,60 @@ func (c *config) Validate() error { return nil } + +// ValidateInputIDs checks all filestream inputs to ensure all input IDs are +// unique. If there is a duplicated ID, it logs an error containing the offending +// input configurations and returns an error containing the duplicated IDs. +// A single empty ID is a valid ID as it's unique, however multiple empty IDs +// are not unique and are therefore are treated as any other duplicated ID. +func ValidateInputIDs(inputs []*conf.C, logger *logp.Logger) error { + duplicatedConfigs := make(map[string][]*conf.C) + var duplicates []string + for _, input := range inputs { + fsInput := struct { + ID string `config:"id"` + Type string `config:"type"` + }{} + err := input.Unpack(&fsInput) + if err != nil { + return fmt.Errorf("failed to unpack filestream input configuration: %w", err) + } + if fsInput.Type == "filestream" { + duplicatedConfigs[fsInput.ID] = append(duplicatedConfigs[fsInput.ID], input) + // we just need to collect the duplicated IDs once, therefore collect + // it only the first time we see a duplicated ID. + if len(duplicatedConfigs[fsInput.ID]) == 2 { + duplicates = append(duplicates, fsInput.ID) + } + } + } + + if len(duplicates) != 0 { + jsonDupCfg := collectOffendingInputs(duplicates, duplicatedConfigs) + logger.Errorw("filestream inputs with duplicated IDs", "inputs", jsonDupCfg) + var quotedDuplicates []string + for _, dup := range duplicates { + quotedDuplicates = append(quotedDuplicates, fmt.Sprintf("%q", dup)) + } + return fmt.Errorf("filestream inputs validation error: filestream inputs with duplicated IDs: %v", strings.Join(quotedDuplicates, ",")) + } + + return nil +} + +func collectOffendingInputs(duplicates []string, ids map[string][]*conf.C) []map[string]interface{} { + var cfgs []map[string]interface{} + + for _, id := range duplicates { + for _, dupcfgs := range ids[id] { + toJson := map[string]interface{}{} + err := dupcfgs.Unpack(&toJson) + if err != nil { + toJson[id] = fmt.Sprintf("failed to unpack config: %v", err) + } + cfgs = append(cfgs, toJson) + } + } + + return cfgs +} diff --git a/filebeat/input/filestream/config_test.go b/filebeat/input/filestream/config_test.go index 6cf045060c94..729b712d58ea 100644 --- a/filebeat/input/filestream/config_test.go +++ b/filebeat/input/filestream/config_test.go @@ -18,9 +18,16 @@ package filestream import ( + "encoding/json" + "strings" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.uber.org/zap/zaptest/observer" + + conf "github.com/elastic/elastic-agent-libs/config" + "github.com/elastic/elastic-agent-libs/logp" ) func TestConfigValidate(t *testing.T) { @@ -30,3 +37,186 @@ func TestConfigValidate(t *testing.T) { require.Error(t, err) }) } + +func TestValidateInputIDs(t *testing.T) { + tcs := []struct { + name string + cfg []string + assertErr func(t *testing.T, err error) + assertLogs func(t *testing.T, buff *observer.ObservedLogs) + }{ + { + name: "empty config", + cfg: []string{""}, + assertErr: func(t *testing.T, err error) { + assert.NoError(t, err, "empty config should not return an error") + }, + }, + { + name: "one empty ID is allowed", + cfg: []string{` +type: filestream +`, ` +type: filestream +id: some-id-1 +`, ` +type: filestream +id: some-id-2 +`, + }, + assertErr: func(t *testing.T, err error) { + assert.NoError(t, err, "one empty id is allowed") + }, + }, + { + name: "duplicated empty ID", + cfg: []string{` +type: filestream +paths: + - "/tmp/empty-1" +`, ` +type: filestream +paths: + - "/tmp/empty-2" +`, ` +type: filestream +id: unique-id-1 +`, ` +type: filestream +id: unique-id-2 +`, ` +type: filestream +id: unique-ID +`, + }, + assertErr: func(t *testing.T, err error) { + assert.ErrorContains(t, err, `filestream inputs with duplicated IDs: ""`) + + }, + assertLogs: func(t *testing.T, obs *observer.ObservedLogs) { + want := `[{"paths":["/tmp/empty-1"],"type":"filestream"},{"paths":["/tmp/empty-2"],"type":"filestream"}]` + + logs := obs.TakeAll() + require.Len(t, logs, 1, "there should be only one log entry") + + got, err := json.Marshal(logs[0].ContextMap()["inputs"]) + require.NoError(t, err, "could not marshal duplicated IDs inputs") + assert.Equal(t, want, string(got)) + }, + }, { + name: "duplicated IDs", + cfg: []string{` +type: filestream +id: duplicated-id-1 +`, ` +type: filestream +id: duplicated-id-1 +`, ` +type: filestream +id: duplicated-id-2 +`, ` +type: filestream +id: duplicated-id-2 +`, ` +type: filestream +id: duplicated-id-2 +`, ` +type: filestream +id: unique-ID +`, + }, + assertErr: func(t *testing.T, err error) { + assert.ErrorContains(t, err, "filestream inputs with duplicated IDs") + assert.ErrorContains(t, err, "duplicated-id-1") + assert.ErrorContains(t, err, "duplicated-id-2") + assert.Equal(t, strings.Count(err.Error(), "duplicated-id-1"), 1, "each IDs should appear only once") + assert.Equal(t, strings.Count(err.Error(), "duplicated-id-2"), 1, "each IDs should appear only once") + + }, + assertLogs: func(t *testing.T, obs *observer.ObservedLogs) { + want := `[{"id":"duplicated-id-1","type":"filestream"},{"id":"duplicated-id-1","type":"filestream"},{"id":"duplicated-id-2","type":"filestream"},{"id":"duplicated-id-2","type":"filestream"},{"id":"duplicated-id-2","type":"filestream"}]` + + logs := obs.TakeAll() + require.Len(t, logs, 1, "there should be only one log entry") + + got, err := json.Marshal(logs[0].ContextMap()["inputs"]) + require.NoError(t, err, "could not marshal duplicated IDs inputs") + assert.Equal(t, want, string(got)) + }, + }, + { + name: "duplicated IDs and empty ID", + cfg: []string{` +type: filestream +`, ` +type: filestream +`, ` +type: filestream +id: duplicated-id-1 +`, ` +type: filestream +id: duplicated-id-1 +`, ` +type: filestream +id: duplicated-id-2 +`, ` +type: filestream +id: duplicated-id-2 +`, ` +type: filestream +id: unique-ID +`, + }, + assertErr: func(t *testing.T, err error) { + assert.ErrorContains(t, err, "filestream inputs with duplicated IDs") + }, + assertLogs: func(t *testing.T, obs *observer.ObservedLogs) { + want := `[{"type":"filestream"},{"type":"filestream"},{"id":"duplicated-id-1","type":"filestream"},{"id":"duplicated-id-1","type":"filestream"},{"id":"duplicated-id-2","type":"filestream"},{"id":"duplicated-id-2","type":"filestream"}]` + + logs := obs.TakeAll() + require.Len(t, logs, 1, "there should be only one log entry") + + got, err := json.Marshal(logs[0].ContextMap()["inputs"]) + require.NoError(t, err, "could not marshal duplicated IDs inputs") + assert.Equal(t, want, string(got)) + + }, + }, + { + name: "only unique IDs", + cfg: []string{` +type: filestream +id: unique-id-1 +`, ` +type: filestream +id: unique-id-2 +`, ` +type: filestream +id: unique-id-3 +`, + }, + assertErr: func(t *testing.T, err error) { + assert.NoError(t, err, "only unique IDs should not return an error") + }, + }, + } + + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + var inputs []*conf.C + for _, c := range tc.cfg { + cfg, err := conf.NewConfigFrom(c) + require.NoError(t, err, "could not create input configuration") + inputs = append(inputs, cfg) + } + err := logp.DevelopmentSetup(logp.ToObserverOutput()) + require.NoError(t, err, "could not setup log for development") + + err = ValidateInputIDs(inputs, logp.L()) + tc.assertErr(t, err) + if tc.assertLogs != nil { + tc.assertLogs(t, logp.ObserverLogs()) + } + }) + } +} diff --git a/filebeat/input/filestream/fswatch_test.go b/filebeat/input/filestream/fswatch_test.go index 528caec79de3..9fae0481ca6a 100644 --- a/filebeat/input/filestream/fswatch_test.go +++ b/filebeat/input/filestream/fswatch_test.go @@ -36,7 +36,6 @@ import ( ) func TestFileWatcher(t *testing.T) { - t.Skip("Flaky test: https://github.com/elastic/beats/issues/41209") dir := t.TempDir() paths := []string{filepath.Join(dir, "*.log")} cfgStr := ` @@ -261,10 +260,10 @@ scanner: paths := []string{filepath.Join(dir, "*.log")} cfgStr := ` scanner: - check_interval: 10ms + check_interval: 50ms ` - ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) + ctx, cancel := context.WithTimeout(context.Background(), 1000*time.Millisecond) defer cancel() logp.DevelopmentSetup(logp.ToObserverOutput()) diff --git a/filebeat/input/filestream/input_integration_test.go b/filebeat/input/filestream/input_integration_test.go index 79658970c3ff..80327d8bcf2c 100644 --- a/filebeat/input/filestream/input_integration_test.go +++ b/filebeat/input/filestream/input_integration_test.go @@ -30,6 +30,7 @@ import ( "testing" "time" + "github.com/gofrs/uuid/v5" "github.com/stretchr/testify/require" "golang.org/x/text/encoding" "golang.org/x/text/encoding/unicode" @@ -49,8 +50,9 @@ func TestFilestreamCloseRenamed(t *testing.T) { // than close.on_state_change.check_interval to make sure // the Harvester detects the rename first thus allowing // the output to receive the event and then close the source file. + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{env.abspath(testlogName) + "*"}, "prospector.scanner.check_interval": "10ms", "close.on_state_change.check_interval": "1ms", @@ -65,7 +67,7 @@ func TestFilestreamCloseRenamed(t *testing.T) { // first event has made it successfully env.waitUntilEventCount(1) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(testlines)) + env.requireOffsetInRegistry(testlogName, id, len(testlines)) testlogNameRotated := "test.log.rotated" env.mustRenameFile(testlogName, testlogNameRotated) @@ -78,8 +80,8 @@ func TestFilestreamCloseRenamed(t *testing.T) { cancelInput() env.waitUntilInputStops() - env.requireOffsetInRegistry(testlogNameRotated, "fake-ID", len(testlines)) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(newerTestlines)) + env.requireOffsetInRegistry(testlogNameRotated, id, len(testlines)) + env.requireOffsetInRegistry(testlogName, id, len(newerTestlines)) } func TestFilestreamMetadataUpdatedOnRename(t *testing.T) { @@ -90,8 +92,9 @@ func TestFilestreamMetadataUpdatedOnRename(t *testing.T) { env := newInputTestingEnvironment(t) testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{env.abspath(testlogName) + "*"}, "prospector.scanner.check_interval": "1ms", }) @@ -103,20 +106,20 @@ func TestFilestreamMetadataUpdatedOnRename(t *testing.T) { env.startInput(ctx, inp) env.waitUntilEventCount(1) - env.waitUntilMetaInRegistry(testlogName, "fake-ID", fileMeta{Source: env.abspath(testlogName), IdentifierName: "native"}) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(testline)) + env.waitUntilMetaInRegistry(testlogName, id, fileMeta{Source: env.abspath(testlogName), IdentifierName: "native"}) + env.requireOffsetInRegistry(testlogName, id, len(testline)) testlogNameRenamed := "test.log.renamed" env.mustRenameFile(testlogName, testlogNameRenamed) // check if the metadata is updated and cursor data stays the same - env.waitUntilMetaInRegistry(testlogNameRenamed, "fake-ID", fileMeta{Source: env.abspath(testlogNameRenamed), IdentifierName: "native"}) - env.requireOffsetInRegistry(testlogNameRenamed, "fake-ID", len(testline)) + env.waitUntilMetaInRegistry(testlogNameRenamed, id, fileMeta{Source: env.abspath(testlogNameRenamed), IdentifierName: "native"}) + env.requireOffsetInRegistry(testlogNameRenamed, id, len(testline)) env.mustAppendToFile(testlogNameRenamed, testline) env.waitUntilEventCount(2) - env.requireOffsetInRegistry(testlogNameRenamed, "fake-ID", len(testline)*2) + env.requireOffsetInRegistry(testlogNameRenamed, id, len(testline)*2) cancelInput() env.waitUntilInputStops() @@ -127,8 +130,9 @@ func TestFilestreamCloseRemoved(t *testing.T) { env := newInputTestingEnvironment(t) testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{env.abspath(testlogName) + "*"}, "prospector.scanner.check_interval": "24h", "close.on_state_change.check_interval": "1ms", @@ -144,7 +148,7 @@ func TestFilestreamCloseRemoved(t *testing.T) { // first event has made it successfully env.waitUntilEventCount(1) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(testlines)) + env.requireOffsetInRegistry(testlogName, id, len(testlines)) fi, err := os.Stat(env.abspath(testlogName)) if err != nil { @@ -158,8 +162,8 @@ func TestFilestreamCloseRemoved(t *testing.T) { cancelInput() env.waitUntilInputStops() - id := getIDFromPath(env.abspath(testlogName), "fake-ID", fi) - env.requireOffsetInRegistryByID(id, len(testlines)) + idFromPath := getIDFromPath(env.abspath(testlogName), id, fi) + env.requireOffsetInRegistryByID(idFromPath, len(testlines)) } // test_close_eof from test_harvester.py @@ -167,8 +171,9 @@ func TestFilestreamCloseEOF(t *testing.T) { env := newInputTestingEnvironment(t) testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{env.abspath(testlogName)}, "prospector.scanner.check_interval": "24h", "close.reader.on_eof": "true", @@ -183,7 +188,7 @@ func TestFilestreamCloseEOF(t *testing.T) { // first event has made it successfully env.waitUntilEventCount(1) - env.requireOffsetInRegistry(testlogName, "fake-ID", expectedOffset) + env.requireOffsetInRegistry(testlogName, id, expectedOffset) // the second log line will not be picked up as scan_interval is set to one day. env.mustWriteToFile(testlogName, []byte("first line\nsecond log line\n")) @@ -194,7 +199,7 @@ func TestFilestreamCloseEOF(t *testing.T) { cancelInput() env.waitUntilInputStops() - env.requireOffsetInRegistry(testlogName, "fake-ID", expectedOffset) + env.requireOffsetInRegistry(testlogName, id, expectedOffset) } // test_empty_lines from test_harvester.py @@ -202,8 +207,9 @@ func TestFilestreamEmptyLine(t *testing.T) { env := newInputTestingEnvironment(t) testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{env.abspath(testlogName)}, "prospector.scanner.check_interval": "1ms", }) @@ -215,7 +221,7 @@ func TestFilestreamEmptyLine(t *testing.T) { env.mustWriteToFile(testlogName, testlines) env.waitUntilEventCount(2) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(testlines)) + env.requireOffsetInRegistry(testlogName, id, len(testlines)) moreTestlines := []byte("\nafter an empty line\n") env.mustAppendToFile(testlogName, moreTestlines) @@ -230,7 +236,7 @@ func TestFilestreamEmptyLine(t *testing.T) { cancelInput() env.waitUntilInputStops() - env.requireOffsetInRegistry(testlogName, "fake-ID", len(testlines)+len(moreTestlines)) + env.requireOffsetInRegistry(testlogName, id, len(testlines)+len(moreTestlines)) } // test_empty_lines_only from test_harvester.py @@ -240,8 +246,9 @@ func TestFilestreamEmptyLinesOnly(t *testing.T) { env := newInputTestingEnvironment(t) testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{env.abspath(testlogName)}, "prospector.scanner.check_interval": "1ms", }) @@ -255,7 +262,7 @@ func TestFilestreamEmptyLinesOnly(t *testing.T) { cancelInput() env.waitUntilInputStops() - env.requireNoEntryInRegistry(testlogName, "fake-ID") + env.requireNoEntryInRegistry(testlogName, id) } // test_bom_utf8 from test_harvester.py @@ -263,8 +270,9 @@ func TestFilestreamBOMUTF8(t *testing.T) { env := newInputTestingEnvironment(t) testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{env.abspath(testlogName)}, }) @@ -305,8 +313,9 @@ func TestFilestreamUTF16BOMs(t *testing.T) { env := newInputTestingEnvironment(t) testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{env.abspath(testlogName)}, "encoding": name, }) @@ -337,8 +346,9 @@ func TestFilestreamCloseTimeout(t *testing.T) { env := newInputTestingEnvironment(t) testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{env.abspath(testlogName)}, "prospector.scanner.check_interval": "24h", "close.on_state_change.check_interval": "100ms", @@ -352,7 +362,7 @@ func TestFilestreamCloseTimeout(t *testing.T) { env.startInput(ctx, inp) env.waitUntilEventCount(1) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(testlines)) + env.requireOffsetInRegistry(testlogName, id, len(testlines)) env.waitUntilHarvesterIsDone() env.mustWriteToFile(testlogName, []byte("first line\nsecond log line\n")) @@ -362,7 +372,7 @@ func TestFilestreamCloseTimeout(t *testing.T) { cancelInput() env.waitUntilInputStops() - env.requireOffsetInRegistry(testlogName, "fake-ID", len(testlines)) + env.requireOffsetInRegistry(testlogName, id, len(testlines)) } // test_close_inactive from test_input.py @@ -370,8 +380,9 @@ func TestFilestreamCloseAfterInterval(t *testing.T) { env := newInputTestingEnvironment(t) testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{env.abspath(testlogName)}, "prospector.scanner.check_interval": "24h", "close.on_state_change.check_interval": "100ms", @@ -385,7 +396,7 @@ func TestFilestreamCloseAfterInterval(t *testing.T) { env.startInput(ctx, inp) env.waitUntilEventCount(3) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(testlines)) + env.requireOffsetInRegistry(testlogName, id, len(testlines)) env.waitUntilHarvesterIsDone() cancelInput() @@ -397,8 +408,9 @@ func TestFilestreamCloseAfterIntervalRemoved(t *testing.T) { env := newInputTestingEnvironment(t) testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{env.abspath(testlogName)}, "prospector.scanner.check_interval": "24h", "close.on_state_change.check_interval": "10ms", @@ -415,7 +427,7 @@ func TestFilestreamCloseAfterIntervalRemoved(t *testing.T) { env.startInput(ctx, inp) env.waitUntilEventCount(3) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(testlines)) + env.requireOffsetInRegistry(testlogName, id, len(testlines)) env.mustRemoveFile(testlogName) @@ -429,8 +441,9 @@ func TestFilestreamCloseAfterIntervalRenamed(t *testing.T) { env := newInputTestingEnvironment(t) testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{env.abspath(testlogName)}, "prospector.scanner.check_interval": "24h", "close.on_state_change.check_interval": "10ms", @@ -447,7 +460,7 @@ func TestFilestreamCloseAfterIntervalRenamed(t *testing.T) { env.startInput(ctx, inp) env.waitUntilEventCount(3) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(testlines)) + env.requireOffsetInRegistry(testlogName, id, len(testlines)) newFileName := "test_rotated.log" env.mustRenameFile(testlogName, newFileName) @@ -463,8 +476,9 @@ func TestFilestreamCloseAfterIntervalRotatedAndRemoved(t *testing.T) { env := newInputTestingEnvironment(t) testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{env.abspath(testlogName)}, "prospector.scanner.check_interval": "24h", "close.on_state_change.check_interval": "10ms", @@ -481,7 +495,7 @@ func TestFilestreamCloseAfterIntervalRotatedAndRemoved(t *testing.T) { env.startInput(ctx, inp) env.waitUntilEventCount(3) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(testlines)) + env.requireOffsetInRegistry(testlogName, id, len(testlines)) newFileName := "test_rotated.log" env.mustRenameFile(testlogName, newFileName) @@ -498,8 +512,9 @@ func TestFilestreamCloseAfterIntervalRotatedAndNewRemoved(t *testing.T) { env := newInputTestingEnvironment(t) testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{env.abspath(testlogName)}, "prospector.scanner.check_interval": "1ms", "close.on_state_change.check_interval": "10ms", @@ -516,7 +531,7 @@ func TestFilestreamCloseAfterIntervalRotatedAndNewRemoved(t *testing.T) { env.startInput(ctx, inp) env.waitUntilEventCount(3) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(testlines)) + env.requireOffsetInRegistry(testlogName, id, len(testlines)) newFileName := "test_rotated.log" env.mustRenameFile(testlogName, newFileName) @@ -541,8 +556,9 @@ func TestFilestreamTruncatedFileOpen(t *testing.T) { env := newInputTestingEnvironment(t) testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{env.abspath(testlogName)}, "prospector.scanner.check_interval": "1ms", "prospector.scanner.resend_on_touch": "true", @@ -555,7 +571,7 @@ func TestFilestreamTruncatedFileOpen(t *testing.T) { env.mustWriteToFile(testlogName, testlines) env.waitUntilEventCount(3) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(testlines)) + env.requireOffsetInRegistry(testlogName, id, len(testlines)) env.mustTruncateFile(testlogName, 0) time.Sleep(5 * time.Millisecond) @@ -566,7 +582,7 @@ func TestFilestreamTruncatedFileOpen(t *testing.T) { cancelInput() env.waitUntilInputStops() - env.requireOffsetInRegistry(testlogName, "fake-ID", len(truncatedTestLines)) + env.requireOffsetInRegistry(testlogName, id, len(truncatedTestLines)) } // test_truncated_file_closed from test_harvester.py @@ -574,8 +590,9 @@ func TestFilestreamTruncatedFileClosed(t *testing.T) { env := newInputTestingEnvironment(t) testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{env.abspath(testlogName)}, "prospector.scanner.check_interval": "1ms", "prospector.scanner.resend_on_touch": "true", @@ -589,7 +606,7 @@ func TestFilestreamTruncatedFileClosed(t *testing.T) { env.mustWriteToFile(testlogName, testlines) env.waitUntilEventCount(3) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(testlines)) + env.requireOffsetInRegistry(testlogName, id, len(testlines)) env.waitUntilHarvesterIsDone() @@ -602,7 +619,7 @@ func TestFilestreamTruncatedFileClosed(t *testing.T) { cancelInput() env.waitUntilInputStops() - env.requireOffsetInRegistry(testlogName, "fake-ID", len(truncatedTestLines)) + env.requireOffsetInRegistry(testlogName, id, len(truncatedTestLines)) } // test_truncate from test_harvester.py @@ -611,8 +628,9 @@ func TestFilestreamTruncateWithSymlink(t *testing.T) { testlogName := "test.log" symlinkName := "test.log.symlink" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{ env.abspath(testlogName), env.abspath(symlinkName), @@ -632,18 +650,18 @@ func TestFilestreamTruncateWithSymlink(t *testing.T) { env.waitUntilEventCount(3) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(lines)) + env.requireOffsetInRegistry(testlogName, id, len(lines)) // remove symlink env.mustRemoveFile(symlinkName) env.mustTruncateFile(testlogName, 0) - env.waitUntilOffsetInRegistry(testlogName, "fake-ID", 0, 10*time.Second) + env.waitUntilOffsetInRegistry(testlogName, id, 0, 10*time.Second) moreLines := []byte("forth line\nfifth line\n") env.mustWriteToFile(testlogName, moreLines) env.waitUntilEventCount(5) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(moreLines)) + env.requireOffsetInRegistry(testlogName, id, len(moreLines)) cancelInput() env.waitUntilInputStops() @@ -655,8 +673,9 @@ func TestFilestreamTruncateBigScannerInterval(t *testing.T) { env := newInputTestingEnvironment(t) testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{env.abspath(testlogName)}, "prospector.scanner.check_interval": "5s", "prospector.scanner.resend_on_touch": "true", @@ -669,7 +688,7 @@ func TestFilestreamTruncateBigScannerInterval(t *testing.T) { env.mustWriteToFile(testlogName, testlines) env.waitUntilEventCount(3) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(testlines)) + env.requireOffsetInRegistry(testlogName, id, len(testlines)) env.mustTruncateFile(testlogName, 0) @@ -686,8 +705,9 @@ func TestFilestreamTruncateCheckOffset(t *testing.T) { env := newInputTestingEnvironment(t) testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{env.abspath(testlogName)}, "prospector.scanner.check_interval": "1ms", "prospector.scanner.resend_on_touch": "true", @@ -700,11 +720,11 @@ func TestFilestreamTruncateCheckOffset(t *testing.T) { env.mustWriteToFile(testlogName, testlines) env.waitUntilEventCount(3) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(testlines)) + env.requireOffsetInRegistry(testlogName, id, len(testlines)) env.mustTruncateFile(testlogName, 0) - env.waitUntilOffsetInRegistry(testlogName, "fake-ID", 0, 10*time.Second) + env.waitUntilOffsetInRegistry(testlogName, id, 0, 10*time.Second) cancelInput() env.waitUntilInputStops() @@ -715,8 +735,9 @@ func TestFilestreamTruncateBlockedOutput(t *testing.T) { env.pipeline = &mockPipelineConnector{blocking: true} testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{env.abspath(testlogName)}, "prospector.scanner.check_interval": "200ms", }) @@ -734,7 +755,7 @@ func TestFilestreamTruncateBlockedOutput(t *testing.T) { env.pipeline.clients[0].canceler() env.waitUntilEventCount(2) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(testlines)) + env.requireOffsetInRegistry(testlogName, id, len(testlines)) // extra lines are appended after first line is processed // so it can interfere with the truncation of the file @@ -742,7 +763,7 @@ func TestFilestreamTruncateBlockedOutput(t *testing.T) { env.mustTruncateFile(testlogName, 0) - env.waitUntilOffsetInRegistry(testlogName, "fake-ID", 0, 10*time.Second) + env.waitUntilOffsetInRegistry(testlogName, id, 0, 10*time.Second) // all newly started client has to be cancelled so events can be processed env.pipeline.cancelAllClients() @@ -753,7 +774,7 @@ func TestFilestreamTruncateBlockedOutput(t *testing.T) { env.mustWriteToFile(testlogName, truncatedTestLines) env.waitUntilEventCount(3) - env.waitUntilOffsetInRegistry(testlogName, "fake-ID", len(truncatedTestLines), 10*time.Second) + env.waitUntilOffsetInRegistry(testlogName, id, len(truncatedTestLines), 10*time.Second) cancelInput() env.waitUntilInputStops() @@ -765,8 +786,9 @@ func TestFilestreamSymlinksEnabled(t *testing.T) { testlogName := "test.log" symlinkName := "test.log.symlink" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{ env.abspath(symlinkName), }, @@ -786,7 +808,7 @@ func TestFilestreamSymlinksEnabled(t *testing.T) { cancelInput() env.waitUntilInputStops() - env.requireOffsetInRegistry(testlogName, "fake-ID", len(testlines)) + env.requireOffsetInRegistry(testlogName, id, len(testlines)) } // test_symlink_rotated from test_harvester.py @@ -796,8 +818,9 @@ func TestFilestreamSymlinkRotated(t *testing.T) { firstTestlogName := "test1.log" secondTestlogName := "test2.log" symlinkName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{ env.abspath(symlinkName), }, @@ -820,7 +843,7 @@ func TestFilestreamSymlinkRotated(t *testing.T) { env.waitUntilEventCount(1) expectedOffset := len(commonLine) + 2 - env.requireOffsetInRegistry(firstTestlogName, "fake-ID", expectedOffset) + env.requireOffsetInRegistry(firstTestlogName, id, expectedOffset) // rotate symlink env.mustRemoveFile(symlinkName) @@ -830,8 +853,8 @@ func TestFilestreamSymlinkRotated(t *testing.T) { env.mustAppendToFile(secondTestlogName, []byte(moreLines)) env.waitUntilEventCount(4) - env.requireOffsetInRegistry(firstTestlogName, "fake-ID", expectedOffset) - env.requireOffsetInRegistry(secondTestlogName, "fake-ID", expectedOffset+len(moreLines)) + env.requireOffsetInRegistry(firstTestlogName, id, expectedOffset) + env.requireOffsetInRegistry(secondTestlogName, id, expectedOffset+len(moreLines)) cancelInput() env.waitUntilInputStops() @@ -845,8 +868,9 @@ func TestFilestreamSymlinkRemoved(t *testing.T) { testlogName := "test.log" symlinkName := "test.log.symlink" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{ env.abspath(symlinkName), }, @@ -866,7 +890,7 @@ func TestFilestreamSymlinkRemoved(t *testing.T) { env.waitUntilEventCount(1) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(line)) + env.requireOffsetInRegistry(testlogName, id, len(line)) // remove symlink env.mustRemoveFile(symlinkName) @@ -874,7 +898,7 @@ func TestFilestreamSymlinkRemoved(t *testing.T) { env.mustAppendToFile(testlogName, line) env.waitUntilEventCount(2) - env.requireOffsetInRegistry(testlogName, "fake-ID", 2*len(line)) + env.requireOffsetInRegistry(testlogName, id, 2*len(line)) cancelInput() env.waitUntilInputStops() @@ -888,8 +912,9 @@ func TestFilestreamTruncate(t *testing.T) { testlogName := "test.log" symlinkName := "test.log.symlink" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "fake-ID", + "id": id, "paths": []string{ env.abspath("*"), }, @@ -908,12 +933,12 @@ func TestFilestreamTruncate(t *testing.T) { env.waitUntilEventCount(3) - env.requireOffsetInRegistry(testlogName, "fake-ID", len(lines)) + env.requireOffsetInRegistry(testlogName, id, len(lines)) // remove symlink env.mustRemoveFile(symlinkName) env.mustTruncateFile(testlogName, 0) - env.waitUntilOffsetInRegistry(testlogName, "fake-ID", 0, 10*time.Second) + env.waitUntilOffsetInRegistry(testlogName, id, 0, 10*time.Second) // recreate symlink env.mustSymlink(testlogName, symlinkName) @@ -921,7 +946,7 @@ func TestFilestreamTruncate(t *testing.T) { moreLines := []byte("forth line\nfifth line\n") env.mustWriteToFile(testlogName, moreLines) - env.waitUntilOffsetInRegistry(testlogName, "fake-ID", len(moreLines), 10*time.Second) + env.waitUntilOffsetInRegistry(testlogName, id, len(moreLines), 10*time.Second) cancelInput() env.waitUntilInputStops() @@ -982,8 +1007,9 @@ func TestRotatingCloseInactiveLargerWriteRate(t *testing.T) { env := newInputTestingEnvironment(t) testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "my-id", + "id": id, "paths": []string{ env.abspath("*"), }, @@ -1028,8 +1054,9 @@ func TestRotatingCloseInactiveLowWriteRate(t *testing.T) { env := newInputTestingEnvironment(t) testlogName := "test.log" + id := "fake-ID-" + uuid.Must(uuid.NewV4()).String() inp := env.mustCreateInput(map[string]interface{}{ - "id": "my-id", + "id": id, "paths": []string{ env.abspath("*"), }, diff --git a/filebeat/input/filestream/internal/input-logfile/harvester_test.go b/filebeat/input/filestream/internal/input-logfile/harvester_test.go index d8800c85996d..6f5938e308a0 100644 --- a/filebeat/input/filestream/internal/input-logfile/harvester_test.go +++ b/filebeat/input/filestream/internal/input-logfile/harvester_test.go @@ -23,6 +23,7 @@ import ( "fmt" "strings" "sync" + "sync/atomic" "testing" "time" @@ -32,7 +33,6 @@ import ( "github.com/elastic/beats/v7/filebeat/input/filestream/internal/task" input "github.com/elastic/beats/v7/filebeat/input/v2" "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/libbeat/tests/resources" "github.com/elastic/elastic-agent-libs/logp" ) @@ -128,7 +128,7 @@ func TestDefaultHarvesterGroup(t *testing.T) { t.Run("assert a harvester is only started if harvester limit haven't been reached", func(t *testing.T) { var wg sync.WaitGroup - var harvesterRunningCount atomic.Int + var harvesterRunningCount atomic.Int64 var harvester1Finished, harvester2Finished atomic.Bool done1, done2 := make(chan struct{}), make(chan struct{}) diff --git a/filebeat/input/filestream/internal/input-logfile/store.go b/filebeat/input/filestream/internal/input-logfile/store.go index 024ca5c9bfdd..14c7869d0877 100644 --- a/filebeat/input/filestream/internal/input-logfile/store.go +++ b/filebeat/input/filestream/internal/input-logfile/store.go @@ -21,9 +21,9 @@ import ( "fmt" "strings" "sync" + "sync/atomic" "time" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/libbeat/common/cleanup" "github.com/elastic/beats/v7/libbeat/common/transform/typeconv" "github.com/elastic/beats/v7/libbeat/statestore" @@ -461,14 +461,14 @@ func (r *resource) isDeleted() bool { // Retain is used to indicate that 'resource' gets an additional 'owner'. // Owners of an resource can be active inputs or pending update operations // not yet written to disk. -func (r *resource) Retain() { r.pending.Inc() } +func (r *resource) Retain() { r.pending.Add(1) } // Release reduced the owner ship counter of the resource. -func (r *resource) Release() { r.pending.Dec() } +func (r *resource) Release() { r.pending.Add(^uint64(0)) } // UpdatesReleaseN is used to release ownership of N pending update operations. func (r *resource) UpdatesReleaseN(n uint) { - r.pending.Sub(uint64(n)) + r.pending.Add(^uint64(n - 1)) } // Finished returns true if the resource is not in use and if there are no pending updates diff --git a/filebeat/input/kafka/config.go b/filebeat/input/kafka/config.go index 107d765344ba..c1db26733538 100644 --- a/filebeat/input/kafka/config.go +++ b/filebeat/input/kafka/config.go @@ -22,8 +22,6 @@ import ( "fmt" "time" - "github.com/Shopify/sarama" - "github.com/elastic/beats/v7/libbeat/common/cfgwarn" "github.com/elastic/beats/v7/libbeat/common/kafka" "github.com/elastic/beats/v7/libbeat/common/transport/kerberos" @@ -31,6 +29,7 @@ import ( "github.com/elastic/elastic-agent-libs/monitoring" "github.com/elastic/elastic-agent-libs/monitoring/adapter" "github.com/elastic/elastic-agent-libs/transport/tlscommon" + "github.com/elastic/sarama" ) type kafkaInputConfig struct { @@ -110,7 +109,7 @@ var ( // were chosen to match sarama's defaults. func defaultConfig() kafkaInputConfig { return kafkaInputConfig{ - Version: kafka.Version("1.0.0"), + Version: kafka.Version("2.1.0"), InitialOffset: initialOffsetOldest, ClientID: "filebeat", ConnectBackoff: 30 * time.Second, @@ -241,8 +240,8 @@ func (off *initialOffset) Unpack(value string) error { func (st rebalanceStrategy) asSaramaStrategy() sarama.BalanceStrategy { return map[rebalanceStrategy]sarama.BalanceStrategy{ - rebalanceStrategyRange: sarama.BalanceStrategyRange, - rebalanceStrategyRoundRobin: sarama.BalanceStrategyRoundRobin, + rebalanceStrategyRange: sarama.NewBalanceStrategyRange(), + rebalanceStrategyRoundRobin: sarama.NewBalanceStrategyRoundRobin(), }[st] } diff --git a/filebeat/input/kafka/input.go b/filebeat/input/kafka/input.go index e2a04b5fa499..3f330587f826 100644 --- a/filebeat/input/kafka/input.go +++ b/filebeat/input/kafka/input.go @@ -25,13 +25,11 @@ import ( "io" "strings" "sync" + "sync/atomic" "time" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/elastic-agent-libs/mapstr" - "github.com/Shopify/sarama" - input "github.com/elastic/beats/v7/filebeat/input/v2" "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/beats/v7/libbeat/common/acker" @@ -42,6 +40,7 @@ import ( "github.com/elastic/beats/v7/libbeat/reader/parser" conf "github.com/elastic/elastic-agent-libs/config" "github.com/elastic/elastic-agent-libs/logp" + "github.com/elastic/sarama" ) const pluginName = "kafka" @@ -392,9 +391,10 @@ func (l *listFromFieldReader) Next() (reader.Message, error) { timestamp, kafkaFields := composeEventMetadata(l.claim, l.groupHandler, msg) messages := l.parseMultipleMessages(msg.Value) - neededAcks := atomic.MakeInt(len(messages)) + neededAcks := atomic.Int64{} + neededAcks.Add(int64(len(messages))) ackHandler := func() { - if neededAcks.Dec() == 0 { + if neededAcks.Add(-1) == 0 { l.groupHandler.ack(msg) } } diff --git a/filebeat/input/kafka/kafka_integration_test.go b/filebeat/input/kafka/kafka_integration_test.go index 0728004c16da..cc8b29361da9 100644 --- a/filebeat/input/kafka/kafka_integration_test.go +++ b/filebeat/input/kafka/kafka_integration_test.go @@ -35,9 +35,10 @@ import ( "github.com/elastic/elastic-agent-libs/logp" "github.com/elastic/elastic-agent-libs/mapstr" - "github.com/Shopify/sarama" "github.com/stretchr/testify/assert" + "github.com/elastic/sarama" + "github.com/elastic/beats/v7/libbeat/beat" _ "github.com/elastic/beats/v7/libbeat/outputs/codec/format" _ "github.com/elastic/beats/v7/libbeat/outputs/codec/json" @@ -460,7 +461,8 @@ func findMessage(t *testing.T, text string, msgs []testMessage) *testMessage { var msg *testMessage for _, m := range msgs { if text == m.message { - msg = &m + mCopy := m + msg = &mCopy break } } @@ -605,8 +607,10 @@ func run(t *testing.T, cfg *conf.C, client *beattest.ChanClient) (*kafkaInput, f t.Cleanup(cancel) pipeline := beattest.ConstClient(client) - input := inp.(*kafkaInput) - go input.Run(ctx, pipeline) + input, _ := inp.(*kafkaInput) + go func() { + _ = input.Run(ctx, pipeline) + }() return input, cancel } diff --git a/filebeat/input/log/input.go b/filebeat/input/log/input.go index ad93632b372c..e2090f6ebb88 100644 --- a/filebeat/input/log/input.go +++ b/filebeat/input/log/input.go @@ -25,6 +25,7 @@ import ( "sort" "strings" "sync" + "sync/atomic" "time" "github.com/gofrs/uuid/v5" @@ -35,7 +36,6 @@ import ( "github.com/elastic/beats/v7/filebeat/input/file" "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/beats/v7/libbeat/common" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/libbeat/common/cfgwarn" "github.com/elastic/beats/v7/libbeat/management/status" conf "github.com/elastic/elastic-agent-libs/config" @@ -737,8 +737,8 @@ func (p *Input) createHarvester(logger *logp.Logger, state file.State, onTermina // startHarvester starts a new harvester with the given offset // In case the HarvesterLimit is reached, an error is returned func (p *Input) startHarvester(logger *logp.Logger, state file.State, offset int64) error { - if p.numHarvesters.Inc() > p.config.HarvesterLimit && p.config.HarvesterLimit > 0 { - p.numHarvesters.Dec() + if p.numHarvesters.Add(1) > p.config.HarvesterLimit && p.config.HarvesterLimit > 0 { + p.numHarvesters.Add(^uint32(0)) harvesterSkipped.Add(1) return errHarvesterLimit } @@ -747,15 +747,15 @@ func (p *Input) startHarvester(logger *logp.Logger, state file.State, offset int state.Offset = offset // Create harvester with state - h, err := p.createHarvester(logger, state, func() { p.numHarvesters.Dec() }) + h, err := p.createHarvester(logger, state, func() { p.numHarvesters.Add(^uint32(0)) }) if err != nil { - p.numHarvesters.Dec() + p.numHarvesters.Add(^uint32(0)) return err } err = h.Setup() if err != nil { - p.numHarvesters.Dec() + p.numHarvesters.Add(^uint32(0)) return fmt.Errorf("error setting up harvester: %w", err) } @@ -765,7 +765,7 @@ func (p *Input) startHarvester(logger *logp.Logger, state file.State, offset int h.SendStateUpdate() if err = p.harvesters.Start(h); err != nil { - p.numHarvesters.Dec() + p.numHarvesters.Add(^uint32(0)) } return err } diff --git a/filebeat/input/v2/input-cursor/store.go b/filebeat/input/v2/input-cursor/store.go index cc755f046cac..a53bc77a79f9 100644 --- a/filebeat/input/v2/input-cursor/store.go +++ b/filebeat/input/v2/input-cursor/store.go @@ -20,9 +20,9 @@ package cursor import ( "strings" "sync" + "sync/atomic" "time" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/libbeat/common/cleanup" "github.com/elastic/beats/v7/libbeat/common/transform/typeconv" "github.com/elastic/beats/v7/libbeat/statestore" @@ -235,14 +235,14 @@ func (r *resource) IsNew() bool { // Retain is used to indicate that 'resource' gets an additional 'owner'. // Owners of an resource can be active inputs or pending update operations // not yet written to disk. -func (r *resource) Retain() { r.pending.Inc() } +func (r *resource) Retain() { r.pending.Add(1) } // Release reduced the owner ship counter of the resource. -func (r *resource) Release() { r.pending.Dec() } +func (r *resource) Release() { r.pending.Add(^uint64(0)) } // UpdatesReleaseN is used to release ownership of N pending update operations. func (r *resource) UpdatesReleaseN(n uint) { - r.pending.Sub(uint64(n)) + r.pending.Add(^uint64(n - 1)) } // Finished returns true if the resource is not in use and if there are no pending updates @@ -290,7 +290,7 @@ func readStates(log *logp.Logger, store *statestore.Store, prefix string) (*stat } err := store.Each(func(key string, dec statestore.ValueDecoder) (bool, error) { - if !strings.HasPrefix(string(key), keyPrefix) { + if !strings.HasPrefix(key, keyPrefix) { return true, nil } diff --git a/filebeat/input/v2/input-stateless/stateless_test.go b/filebeat/input/v2/input-stateless/stateless_test.go index 2febcb7e1b6d..731577e76c34 100644 --- a/filebeat/input/v2/input-stateless/stateless_test.go +++ b/filebeat/input/v2/input-stateless/stateless_test.go @@ -22,6 +22,7 @@ import ( "errors" "runtime" "sync" + "sync/atomic" "testing" "github.com/stretchr/testify/require" @@ -29,7 +30,6 @@ import ( v2 "github.com/elastic/beats/v7/filebeat/input/v2" stateless "github.com/elastic/beats/v7/filebeat/input/v2/input-stateless" "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/common/atomic" pubtest "github.com/elastic/beats/v7/libbeat/publisher/testing" conf "github.com/elastic/elastic-agent-libs/config" "github.com/elastic/elastic-agent-libs/mapstr" @@ -111,12 +111,12 @@ func TestStateless_Run(t *testing.T) { defer cancel() // connector creates a client the blocks forever until the shutdown signal is received - var publishCalls atomic.Int + var publishCalls atomic.Int64 connector := pubtest.FakeConnector{ ConnectFunc: func(config beat.ClientConfig) (beat.Client, error) { return &pubtest.FakeClient{ PublishFunc: func(event beat.Event) { - publishCalls.Inc() + publishCalls.Add(1) // Unlock Publish once the input has been cancelled <-ctx.Done() }, @@ -141,24 +141,24 @@ func TestStateless_Run(t *testing.T) { // validate require.Equal(t, context.Canceled, err) - require.Equal(t, 1, publishCalls.Load()) + require.Equal(t, int64(1), publishCalls.Load()) }) t.Run("do not start input of pipeline connection fails", func(t *testing.T) { errOpps := errors.New("oops") connector := pubtest.FailingConnector(errOpps) - var run atomic.Int + var run atomic.Int64 input := createConfiguredInput(t, constInputManager(&fakeStatelessInput{ OnRun: func(_ v2.Context, publisher stateless.Publisher) error { - run.Inc() + run.Add(1) return nil }, }), nil) err := input.Run(v2.Context{}, connector) require.True(t, errors.Is(err, errOpps)) - require.Equal(t, 0, run.Load()) + require.Equal(t, int64(0), run.Load()) }) } diff --git a/filebeat/input/winlog/input.go b/filebeat/input/winlog/input.go index 945dd0e34765..ab925cbdd3c6 100644 --- a/filebeat/input/winlog/input.go +++ b/filebeat/input/winlog/input.go @@ -26,7 +26,6 @@ import ( input "github.com/elastic/beats/v7/filebeat/input/v2" cursor "github.com/elastic/beats/v7/filebeat/input/v2/input-cursor" "github.com/elastic/beats/v7/libbeat/feature" - "github.com/elastic/beats/v7/libbeat/management/status" "github.com/elastic/elastic-agent-libs/logp" "github.com/elastic/go-concert/ctxtool" "github.com/elastic/go-concert/timed" @@ -40,10 +39,6 @@ type eventlogRunner struct{} const pluginName = "winlog" -const channelNotFoundError = "Encountered channel not found error when opening Windows Event Log" -const eventLogReadingError = "Error occurred while reading from Windows Event Log" -const resetError = "Error resetting Windows Event Log handle" - // Plugin create a stateful input Plugin collecting logs from Windows Event Logs. func Plugin(log *logp.Logger, store cursor.StateStore) input.Plugin { return input.Plugin{ @@ -104,7 +99,6 @@ func (eventlogRunner) Run( // Flag used to detect repeat "channel not found" errors, eliminating log spam. channelNotFoundErrDetected := false - ctx.UpdateStatus(status.Running, "") runLoop: for { @@ -115,9 +109,6 @@ runLoop: evtCheckpoint := initCheckpoint(log, cursor) openErr := api.Open(evtCheckpoint) - // Mark the input running. - // Status will be changed to "Degraded" if any error are encountered during opening/reading - ctx.UpdateStatus(status.Running, "") switch { case eventlog.IsRecoverable(openErr): @@ -126,16 +117,14 @@ runLoop: continue case !api.IsFile() && eventlog.IsChannelNotFound(openErr): if !channelNotFoundErrDetected { - log.Errorw(channelNotFoundError, "error", openErr) + log.Errorw("Encountered channel not found error when opening Windows Event Log", "error", openErr) } else { - log.Debugw(channelNotFoundError, "error", openErr) + log.Debugw("Encountered channel not found error when opening Windows Event Log", "error", openErr) } - ctx.UpdateStatus(status.Degraded, fmt.Sprintf("%s: %v", channelNotFoundError, openErr)) channelNotFoundErrDetected = true _ = timed.Wait(cancelCtx, 5*time.Second) continue case openErr != nil: - ctx.UpdateStatus(status.Degraded, fmt.Sprintf("failed to open Windows Event Log channel %q: %v", api.Channel(), openErr)) return fmt.Errorf("failed to open Windows Event Log channel %q: %w", api.Channel(), openErr) } channelNotFoundErrDetected = false @@ -148,16 +137,14 @@ runLoop: if eventlog.IsRecoverable(err) { log.Errorw("Encountered recoverable error when reading from Windows Event Log", "error", err) if resetErr := api.Reset(); resetErr != nil { - log.Errorw(resetError, "error", resetErr) - ctx.UpdateStatus(status.Degraded, fmt.Sprintf("%s: %v", resetError, resetErr)) + log.Errorw("Error resetting Windows Event Log handle", "error", resetErr) } continue runLoop } if !api.IsFile() && eventlog.IsChannelNotFound(err) { log.Errorw("Encountered channel not found error when reading from Windows Event Log", "error", err) if resetErr := api.Reset(); resetErr != nil { - log.Errorw(resetError, "error", resetErr) - ctx.UpdateStatus(status.Degraded, fmt.Sprintf("%s: %v", resetError, resetErr)) + log.Errorw("Error resetting Windows Event Log handle", "error", resetErr) } continue runLoop } @@ -173,8 +160,7 @@ runLoop: return nil } - log.Errorw(eventLogReadingError, "error", err) - ctx.UpdateStatus(status.Degraded, fmt.Sprintf("%s: %v", eventLogReadingError, err)) + log.Errorw("Error occurred while reading from Windows Event Log", "error", err) return err } if len(records) == 0 { @@ -187,7 +173,6 @@ runLoop: if err := publisher.Publish(event, record.Offset); err != nil { // Publisher indicates disconnect when returning an error. // stop trying to publish records and quit - ctx.UpdateStatus(status.Degraded, fmt.Sprintf("Error occurred while publishing from winlog: %v", err)) return err } } diff --git a/filebeat/inputsource/common/streaming/listener.go b/filebeat/inputsource/common/streaming/listener.go index ce0f69d030e6..5816c1fa81c9 100644 --- a/filebeat/inputsource/common/streaming/listener.go +++ b/filebeat/inputsource/common/streaming/listener.go @@ -26,9 +26,9 @@ import ( "net" "strings" "sync" + "sync/atomic" "github.com/elastic/beats/v7/filebeat/inputsource" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/elastic-agent-libs/logp" "github.com/elastic/go-concert/ctxtool" ) @@ -44,7 +44,7 @@ type Listener struct { wg sync.WaitGroup log *logp.Logger ctx ctxtool.CancelContext - clientsCount atomic.Int + clientsCount atomic.Int64 handlerFactory HandlerFactory listenerFactory ListenerFactory } @@ -190,10 +190,10 @@ func (l *Listener) handleConnection(conn net.Conn) { defer cancel() // Track number of clients. - l.clientsCount.Inc() + l.clientsCount.Add(1) log.Debugw("New client connection", "active_clients", l.clientsCount.Load()) defer func() { - l.clientsCount.Dec() + l.clientsCount.Add(-1) log.Debugw("Client disconnected", "active_clients", l.clientsCount.Load()) }() diff --git a/filebeat/module/system/README.md b/filebeat/module/system/README.md new file mode 100644 index 000000000000..2471264cfcf2 --- /dev/null +++ b/filebeat/module/system/README.md @@ -0,0 +1,14 @@ +# Journald tests (Debian 12) +The tests for the journald input (currently only used for Debian 12 +testing) require journal files (test files ending in `.journal`), those +files are generated using `systemd-journal-remote` (see the [Journald +input README.md](../../input/journald/README.md) for more details). + +The source for those journal files are the `.export` files in the test +folder. Those files are the raw output of `journalctl -o export`. They +are added here because journal files format change with different +versions of journald, which can cause `journalclt` to fail reading +them, which leads to test failures. So if tests start failing because +`journalctl` cannot read the journal files as expected, new ones can +easily be generated with the same version of journalctl used on CI +and the original dataset. diff --git a/filebeat/module/system/_meta/config.reference.yml b/filebeat/module/system/_meta/config.reference.yml index 3c7a0b43d499..7536f2136396 100644 --- a/filebeat/module/system/_meta/config.reference.yml +++ b/filebeat/module/system/_meta/config.reference.yml @@ -7,6 +7,9 @@ # Filebeat will choose the paths depending on your OS. #var.paths: + # Use journald to collect system logs + #var.use_journald: false + # Input configuration (advanced). Any input configuration option # can be added under this section. #input: @@ -19,6 +22,9 @@ # Filebeat will choose the paths depending on your OS. #var.paths: + # Use journald to collect auth logs + #var.use_journald: false + # Input configuration (advanced). Any input configuration option # can be added under this section. #input: diff --git a/filebeat/module/system/_meta/config.yml b/filebeat/module/system/_meta/config.yml index c1fe882374d3..00856cbe016f 100644 --- a/filebeat/module/system/_meta/config.yml +++ b/filebeat/module/system/_meta/config.yml @@ -7,6 +7,9 @@ # Filebeat will choose the paths depending on your OS. #var.paths: + # Use journald to collect system logs + #var.use_journald: false + # Authorization logs auth: enabled: false @@ -14,3 +17,6 @@ # Set custom paths for the log files. If left empty, # Filebeat will choose the paths depending on your OS. #var.paths: + + # Use journald to collect auth logs + #var.use_journald: false diff --git a/filebeat/module/system/_meta/docs.asciidoc b/filebeat/module/system/_meta/docs.asciidoc index 6d9209eafe20..b510e0104347 100644 --- a/filebeat/module/system/_meta/docs.asciidoc +++ b/filebeat/module/system/_meta/docs.asciidoc @@ -57,11 +57,13 @@ include::../include/config-option-intro.asciidoc[] ==== `syslog` fileset settings include::../include/var-paths.asciidoc[] +include::../include/use-journald.asciidoc[] [float] ==== `auth` fileset settings include::../include/var-paths.asciidoc[] +include::../include/use-journald.asciidoc[] *`var.tags`*:: diff --git a/filebeat/module/system/auth/config/auth.yml b/filebeat/module/system/auth/config/auth.yml index 466b55078af5..7e7cc6bf4fd2 100644 --- a/filebeat/module/system/auth/config/auth.yml +++ b/filebeat/module/system/auth/config/auth.yml @@ -1,14 +1,22 @@ +{{ if .use_journald }} +type: journald +id: system-auth +facilities: + - 4 + - 10 +{{ else }} type: log paths: {{ range $i, $path := .paths }} - {{$path}} {{ end }} exclude_files: [".gz$"] - multiline: pattern: "^\\s" match: after +{{ end }} +# Common configuration processors: - add_locale: ~ diff --git a/filebeat/module/system/auth/ingest/entrypoint.yml b/filebeat/module/system/auth/ingest/entrypoint.yml new file mode 100644 index 000000000000..75ed68b6f9a3 --- /dev/null +++ b/filebeat/module/system/auth/ingest/entrypoint.yml @@ -0,0 +1,9 @@ +description: Entrypoint Pipeline for system/auth Filebeat module +processors: + - pipeline: + if: ctx?.input?.type == "journald" + name: '{< IngestPipeline "journald" >}' + + - pipeline: + if: ctx?.input?.type == "log" + name: '{< IngestPipeline "files" >}' diff --git a/filebeat/module/system/auth/ingest/pipeline.yml b/filebeat/module/system/auth/ingest/files.yml similarity index 88% rename from filebeat/module/system/auth/ingest/pipeline.yml rename to filebeat/module/system/auth/ingest/files.yml index c89ef94b28a7..39611f484a82 100644 --- a/filebeat/module/system/auth/ingest/pipeline.yml +++ b/filebeat/module/system/auth/ingest/files.yml @@ -18,18 +18,9 @@ processors: TIMESTAMP: (?:%{TIMESTAMP_ISO8601}|%{SYSLOGTIMESTAMP}) patterns: - '^%{TIMESTAMP:system.auth.timestamp} %{SYSLOGHOST:host.hostname}? %{DATA:process.name}(?:\[%{POSINT:process.pid:long}\])?:%{SPACE}%{GREEDYMULTILINE:_temp.message}$' - - grok: + - pipeline: description: Grok specific auth messages. - tag: grok-specific-messages - field: _temp.message - ignore_missing: true - patterns: - - '^%{DATA:system.auth.ssh.event} %{DATA:system.auth.ssh.method} for (invalid user)?%{DATA:user.name} from %{IPORHOST:source.address} port %{NUMBER:source.port:long} ssh2(: %{GREEDYDATA:system.auth.ssh.signature})?' - - '^%{DATA:system.auth.ssh.event} user %{DATA:user.name} from %{IPORHOST:source.address}' - - '^Did not receive identification string from %{IPORHOST:system.auth.ssh.dropped_ip}' - - '^%{DATA:user.name} :( %{DATA:system.auth.sudo.error} ;)? TTY=%{DATA:system.auth.sudo.tty} ; PWD=%{DATA:system.auth.sudo.pwd} ; USER=%{DATA:system.auth.sudo.user} ; COMMAND=%{GREEDYDATA:system.auth.sudo.command}' - - '^new group: name=%{DATA:group.name}, GID=%{NUMBER:group.id}' - - '^new user: name=%{DATA:user.name}, UID=%{NUMBER:user.id}, GID=%{NUMBER:group.id}, home=%{DATA:system.auth.useradd.home}, shell=%{DATA:system.auth.useradd.shell}$' + name: '{< IngestPipeline "grok-auth-messages" >}' on_failure: - rename: description: Leave the unmatched content in message. diff --git a/filebeat/module/system/auth/ingest/grok-auth-messages.yml b/filebeat/module/system/auth/ingest/grok-auth-messages.yml new file mode 100644 index 000000000000..fc09abbff5e7 --- /dev/null +++ b/filebeat/module/system/auth/ingest/grok-auth-messages.yml @@ -0,0 +1,14 @@ +description: Journald Pipeline for system/auth Filebeat module +processors: + - grok: + description: Grok specific auth messages. + tag: grok-specific-messages + field: _temp.message + ignore_missing: true + patterns: + - '^%{DATA:system.auth.ssh.event} %{DATA:system.auth.ssh.method} for (invalid user)?%{DATA:user.name} from %{IPORHOST:source.address} port %{NUMBER:source.port:long} ssh2(: %{GREEDYDATA:system.auth.ssh.signature})?' + - '^%{DATA:system.auth.ssh.event} user %{DATA:user.name} from %{IPORHOST:source.address}' + - '^Did not receive identification string from %{IPORHOST:system.auth.ssh.dropped_ip}' + - '^%{DATA:user.name} :( %{DATA:system.auth.sudo.error} ;)? TTY=%{DATA:system.auth.sudo.tty} ; PWD=%{DATA:system.auth.sudo.pwd} ; USER=%{DATA:system.auth.sudo.user} ; COMMAND=%{GREEDYDATA:system.auth.sudo.command}' + - '^new group: name=%{DATA:group.name}, GID=%{NUMBER:group.id}' + - '^new user: name=%{DATA:user.name}, UID=%{NUMBER:user.id}, GID=%{NUMBER:group.id}, home=%{DATA:system.auth.useradd.home}, shell=%{DATA:system.auth.useradd.shell}$' diff --git a/filebeat/module/system/auth/ingest/journald.yml b/filebeat/module/system/auth/ingest/journald.yml new file mode 100644 index 000000000000..c6f84f9af135 --- /dev/null +++ b/filebeat/module/system/auth/ingest/journald.yml @@ -0,0 +1,205 @@ +description: Journald Pipeline for system/auth Filebeat module +processors: + - set: + field: event.ingested + copy_from: _ingest.timestamp + - rename: + field: "journald.process.name" + target_field: process.name + - set: + field: "process.pid" + copy_from: "journald.pid" + ignore_failure: true + - rename: + field: message + target_field: _temp.message + - pipeline: + description: Grok specific auth messages. + name: '{< IngestPipeline "grok-auth-messages" >}' + ignore_failure: true + - rename: + field: _temp.message + target_field: message + - grok: + description: Grok usernames from PAM messages. + tag: grok-pam-users + field: message + ignore_missing: true + ignore_failure: true + patterns: + - 'for user %{QUOTE}?%{DATA:_temp.foruser}%{QUOTE}? by %{QUOTE}?%{DATA:_temp.byuser}%{QUOTE}?(?:\(uid=%{NUMBER:_temp.byuid}\))?$' + - 'for user %{QUOTE}?%{DATA:_temp.foruser}%{QUOTE}?$' + - 'by user %{QUOTE}?%{DATA:_temp.byuser}%{QUOTE}?$' + - '%{BOUNDARY} user %{QUOTE}%{DATA:_temp.user}%{QUOTE}' + pattern_definitions: + QUOTE: "['\"]" + BOUNDARY: "(?- + if (ctx.system.auth.ssh.event == "Accepted") { + ctx.event.type = ["info"]; + ctx.event.category = ["authentication", "session"]; + ctx.event.action = "ssh_login"; + ctx.event.outcome = "success"; + } else if (ctx.system.auth.ssh.event == "Invalid" || ctx.system.auth.ssh.event == "Failed") { + ctx.event.type = ["info"]; + ctx.event.category = ["authentication"]; + ctx.event.action = "ssh_login"; + ctx.event.outcome = "failure"; + } + - append: + field: event.category + value: iam + if: ctx.process?.name != null && ['groupadd', 'groupdel', 'groupmod', 'useradd', 'userdel', 'usermod'].contains(ctx.process.name) + - set: + field: event.outcome + value: success + if: ctx.process?.name != null && (ctx.message == null || !ctx.message.contains("fail")) && ['groupadd', 'groupdel', 'groupmod', 'useradd', 'userdel', 'usermod'].contains(ctx.process.name) + - set: + field: event.outcome + value: failure + if: ctx.process?.name != null && (ctx.message != null && ctx.message.contains("fail")) && ['groupadd', 'groupdel', 'groupmod', 'useradd', 'userdel', 'usermod'].contains(ctx.process.name) + - append: + field: event.type + value: user + if: ctx.process?.name != null && ['useradd', 'userdel', 'usermod'].contains(ctx.process.name) + - append: + field: event.type + value: group + if: ctx.process?.name != null && ['groupadd', 'groupdel', 'groupmod'].contains(ctx.process.name) + - append: + field: event.type + value: creation + if: ctx.process?.name != null && ['useradd', 'groupadd'].contains(ctx.process.name) + - append: + field: event.type + value: deletion + if: ctx.process?.name != null && ['userdel', 'groupdel'].contains(ctx.process.name) + - append: + field: event.type + value: change + if: ctx.process?.name != null && ['usermod', 'groupmod'].contains(ctx.process.name) + - append: + field: related.user + value: "{{{ user.name }}}" + allow_duplicates: false + if: ctx.user?.name != null && ctx.user?.name != '' + - append: + field: related.user + value: "{{{ user.effective.name }}}" + allow_duplicates: false + if: ctx.user?.effective?.name != null && ctx.user?.effective?.name != '' + - append: + field: related.ip + value: "{{{ source.ip }}}" + allow_duplicates: false + if: ctx.source?.ip != null && ctx.source?.ip != '' + - append: + field: related.hosts + value: "{{{ host.hostname }}}" + allow_duplicates: false + if: ctx.host?.hostname != null && ctx.host?.hostname != '' + - set: + field: ecs.version + value: 8.0.0 + - remove: + field: event.original + if: "ctx?.tags == null || !(ctx.tags.contains('preserve_original_event'))" + ignore_failure: true + ignore_missing: true + - remove: + description: Remove the extra fields added by the Journald input + ignore_missing: true + field: + - journald + - process.thread + - syslog + - systemd + - message_id +on_failure: + - set: + field: error.message + value: '{{{ _ingest.on_failure_message }}}' diff --git a/filebeat/module/system/auth/manifest.yml b/filebeat/module/system/auth/manifest.yml index bf1a3623cf15..5fe9ef9be8b9 100644 --- a/filebeat/module/system/auth/manifest.yml +++ b/filebeat/module/system/auth/manifest.yml @@ -12,6 +12,13 @@ var: os.windows: [] - name: tags default: [] + - name: use_journald + default: false + +ingest_pipeline: + - ingest/entrypoint.yml + - ingest/files.yml + - ingest/journald.yml + - ingest/grok-auth-messages.yml -ingest_pipeline: ingest/pipeline.yml input: config/auth.yml diff --git a/filebeat/module/system/auth/test/debian-12.export b/filebeat/module/system/auth/test/debian-12.export new file mode 100644 index 000000000000..583416f6c7b5 Binary files /dev/null and b/filebeat/module/system/auth/test/debian-12.export differ diff --git a/filebeat/module/system/auth/test/debian-12.journal b/filebeat/module/system/auth/test/debian-12.journal new file mode 100644 index 000000000000..3195198e6041 Binary files /dev/null and b/filebeat/module/system/auth/test/debian-12.journal differ diff --git a/filebeat/module/system/auth/test/debian-12.journal-expected.json b/filebeat/module/system/auth/test/debian-12.journal-expected.json new file mode 100644 index 000000000000..2ef69b76b22a --- /dev/null +++ b/filebeat/module/system/auth/test/debian-12.journal-expected.json @@ -0,0 +1,383 @@ +[ + { + "event.action": "ssh_login", + "event.category": [ + "authentication", + "session" + ], + "event.dataset": "system.auth", + "event.kind": "event", + "event.module": "system", + "event.outcome": "success", + "event.timezone": "-02:00", + "event.type": [ + "info" + ], + "fileset.name": "auth", + "host.hostname": "vagrant-debian-12", + "host.id": "5e6dc8fe417f4ea383e2afaa731f5d8a", + "input.type": "journald", + "log.syslog.facility.code": 4, + "log.syslog.priority": 6, + "message": "Accepted publickey for vagrant from 10.0.2.2 port 48274 ssh2: ED25519 SHA256:k1kjhwoH/H3w31MbGOIGd7qxrkSQJnoAN0eYJVHDmmI", + "process.args": [ + "\"sshd: vagrant [priv]\"" + ], + "process.args_count": 1, + "process.command_line": "\"sshd: vagrant [priv]\"", + "process.name": "sshd", + "process.pid": 26538, + "related.hosts": [ + "vagrant-debian-12" + ], + "related.ip": [ + "10.0.2.2" + ], + "related.user": [ + "vagrant" + ], + "service.type": "system", + "source.address": "10.0.2.2", + "source.ip": "10.0.2.2", + "source.port": 48274, + "system.auth.ssh.event": "Accepted", + "system.auth.ssh.method": "publickey", + "system.auth.ssh.signature": "ED25519 SHA256:k1kjhwoH/H3w31MbGOIGd7qxrkSQJnoAN0eYJVHDmmI", + "user.group.id": "0", + "user.id": "0", + "user.name": "vagrant" + }, + { + "event.action": "ssh_login", + "event.category": [ + "authentication", + "session" + ], + "event.dataset": "system.auth", + "event.kind": "event", + "event.module": "system", + "event.outcome": "success", + "event.timezone": "-02:00", + "event.type": [ + "info" + ], + "fileset.name": "auth", + "host.hostname": "vagrant-debian-12", + "host.id": "5e6dc8fe417f4ea383e2afaa731f5d8a", + "input.type": "journald", + "log.syslog.facility.code": 4, + "log.syslog.priority": 6, + "message": "Accepted password for vagrant from 192.168.42.119 port 55310 ssh2", + "process.args": [ + "\"sshd: vagrant [priv]\"" + ], + "process.args_count": 1, + "process.command_line": "\"sshd: vagrant [priv]\"", + "process.name": "sshd", + "process.pid": 1710, + "related.hosts": [ + "vagrant-debian-12" + ], + "related.ip": [ + "192.168.42.119" + ], + "related.user": [ + "vagrant" + ], + "service.type": "system", + "source.address": "192.168.42.119", + "source.ip": "192.168.42.119", + "source.port": 55310, + "system.auth.ssh.event": "Accepted", + "system.auth.ssh.method": "password", + "user.group.id": "0", + "user.id": "0", + "user.name": "vagrant" + }, + { + "event.action": "ssh_login", + "event.category": [ + "authentication" + ], + "event.dataset": "system.auth", + "event.kind": "event", + "event.module": "system", + "event.outcome": "failure", + "event.timezone": "-02:00", + "event.type": [ + "info" + ], + "fileset.name": "auth", + "host.hostname": "vagrant-debian-12", + "host.id": "5e6dc8fe417f4ea383e2afaa731f5d8a", + "input.type": "journald", + "log.syslog.facility.code": 4, + "log.syslog.priority": 6, + "message": "Invalid user test from 192.168.42.119 port 48890", + "process.args": [ + "\"sshd: unknown [priv]\"" + ], + "process.args_count": 1, + "process.command_line": "\"sshd: unknown [priv]\"", + "process.name": "sshd", + "process.pid": 1721, + "related.hosts": [ + "vagrant-debian-12" + ], + "related.ip": [ + "192.168.42.119" + ], + "related.user": [ + "test" + ], + "service.type": "system", + "source.address": "192.168.42.119", + "source.ip": "192.168.42.119", + "system.auth.ssh.event": "Invalid", + "user.group.id": "0", + "user.id": "0", + "user.name": "test" + }, + { + "event.action": "ssh_login", + "event.category": [ + "authentication" + ], + "event.dataset": "system.auth", + "event.kind": "event", + "event.module": "system", + "event.outcome": "failure", + "event.timezone": "-02:00", + "event.type": [ + "info" + ], + "fileset.name": "auth", + "host.hostname": "vagrant-debian-12", + "host.id": "5e6dc8fe417f4ea383e2afaa731f5d8a", + "input.type": "journald", + "log.syslog.facility.code": 4, + "log.syslog.priority": 6, + "message": "Failed password for root from 192.168.42.119 port 46632 ssh2", + "process.args": [ + "\"sshd: root [priv]\"" + ], + "process.args_count": 1, + "process.command_line": "\"sshd: root [priv]\"", + "process.name": "sshd", + "process.pid": 1723, + "related.hosts": [ + "vagrant-debian-12" + ], + "related.ip": [ + "192.168.42.119" + ], + "related.user": [ + "root" + ], + "service.type": "system", + "source.address": "192.168.42.119", + "source.ip": "192.168.42.119", + "source.port": 46632, + "system.auth.ssh.event": "Failed", + "system.auth.ssh.method": "password", + "user.group.id": "0", + "user.id": "0", + "user.name": "root" + }, + { + "event.action": "ssh_login", + "event.category": [ + "authentication" + ], + "event.dataset": "system.auth", + "event.kind": "event", + "event.module": "system", + "event.outcome": "failure", + "event.timezone": "-02:00", + "event.type": [ + "info" + ], + "fileset.name": "auth", + "host.hostname": "vagrant-debian-12", + "host.id": "5e6dc8fe417f4ea383e2afaa731f5d8a", + "input.type": "journald", + "log.syslog.facility.code": 4, + "log.syslog.priority": 6, + "message": "Failed password for root from 192.168.42.119 port 46632 ssh2", + "process.args": [ + "\"sshd: root [priv]\"" + ], + "process.args_count": 1, + "process.command_line": "\"sshd: root [priv]\"", + "process.name": "sshd", + "process.pid": 1723, + "related.hosts": [ + "vagrant-debian-12" + ], + "related.ip": [ + "192.168.42.119" + ], + "related.user": [ + "root" + ], + "service.type": "system", + "source.address": "192.168.42.119", + "source.ip": "192.168.42.119", + "source.port": 46632, + "system.auth.ssh.event": "Failed", + "system.auth.ssh.method": "password", + "user.group.id": "0", + "user.id": "0", + "user.name": "root" + }, + { + "event.action": "ssh_login", + "event.category": [ + "authentication" + ], + "event.dataset": "system.auth", + "event.kind": "event", + "event.module": "system", + "event.outcome": "failure", + "event.timezone": "-02:00", + "event.type": [ + "info" + ], + "fileset.name": "auth", + "host.hostname": "vagrant-debian-12", + "host.id": "5e6dc8fe417f4ea383e2afaa731f5d8a", + "input.type": "journald", + "log.syslog.facility.code": 4, + "log.syslog.priority": 6, + "message": "Failed password for root from 192.168.42.119 port 46632 ssh2", + "process.args": [ + "\"sshd: root [priv]\"" + ], + "process.args_count": 1, + "process.command_line": "\"sshd: root [priv]\"", + "process.name": "sshd", + "process.pid": 1723, + "related.hosts": [ + "vagrant-debian-12" + ], + "related.ip": [ + "192.168.42.119" + ], + "related.user": [ + "root" + ], + "service.type": "system", + "source.address": "192.168.42.119", + "source.ip": "192.168.42.119", + "source.port": 46632, + "system.auth.ssh.event": "Failed", + "system.auth.ssh.method": "password", + "user.group.id": "0", + "user.id": "0", + "user.name": "root" + }, + { + "event.dataset": "system.auth", + "event.kind": "event", + "event.module": "system", + "event.timezone": "-02:00", + "fileset.name": "auth", + "host.hostname": "vagrant-debian-12", + "host.id": "5e6dc8fe417f4ea383e2afaa731f5d8a", + "input.type": "journald", + "log.syslog.facility.code": 10, + "log.syslog.priority": 5, + "message": " vagrant : TTY=pts/2 ; PWD=/home/vagrant ; USER=root ; COMMAND=/usr/bin/emacs /etc/ssh/sshd_config", + "process.args": [ + "sudo", + "emacs", + "/etc/ssh/sshd_config" + ], + "process.args_count": 3, + "process.command_line": "sudo emacs /etc/ssh/sshd_config", + "process.name": "sudo", + "process.pid": 1582, + "related.hosts": [ + "vagrant-debian-12" + ], + "related.user": [ + " vagrant", + "root" + ], + "service.type": "system", + "system.auth.sudo.command": "/usr/bin/emacs /etc/ssh/sshd_config", + "system.auth.sudo.pwd": "/home/vagrant", + "system.auth.sudo.tty": "pts/2", + "system.auth.sudo.user": "root", + "user.effective.name": "root", + "user.group.id": "1000", + "user.id": "1000", + "user.name": " vagrant" + }, + { + "event.category": [ + "iam" + ], + "event.dataset": "system.auth", + "event.kind": "event", + "event.module": "system", + "event.outcome": "success", + "event.timezone": "-02:00", + "event.type": [ + "creation", + "group" + ], + "fileset.name": "auth", + "group.id": "1001", + "group.name": "test", + "host.hostname": "vagrant-debian-12", + "host.id": "5e6dc8fe417f4ea383e2afaa731f5d8a", + "input.type": "journald", + "log.syslog.facility.code": 10, + "log.syslog.priority": 6, + "message": "new group: name=test, GID=1001", + "process.args": [ + "/sbin/groupadd", + "-g", + "1001", + "test" + ], + "process.args_count": 4, + "process.command_line": "/sbin/groupadd -g 1001 test", + "process.name": "groupadd", + "process.pid": 1743, + "related.hosts": [ + "vagrant-debian-12" + ], + "service.type": "system", + "user.effective.group.id": "0", + "user.effective.id": "0", + "user.id": "1000" + }, + { + "event.dataset": "system.auth", + "event.kind": "event", + "event.module": "system", + "event.timezone": "-02:00", + "fileset.name": "auth", + "host.hostname": "vagrant-debian-12", + "host.id": "5e6dc8fe417f4ea383e2afaa731f5d8a", + "input.type": "journald", + "log.syslog.facility.code": 4, + "log.syslog.priority": 6, + "message": "Session 8 logged out. Waiting for processes to exit.", + "process.args": [ + "/lib/systemd/systemd-logind" + ], + "process.args_count": 1, + "process.command_line": "/lib/systemd/systemd-logind", + "process.name": "systemd-logind", + "process.pid": 316, + "related.hosts": [ + "vagrant-debian-12" + ], + "service.type": "system", + "user.group.id": "0", + "user.id": "0" + } +] \ No newline at end of file diff --git a/filebeat/module/system/syslog/config/syslog.yml b/filebeat/module/system/syslog/config/syslog.yml index e7f238d8af83..90fdd719b9f7 100644 --- a/filebeat/module/system/syslog/config/syslog.yml +++ b/filebeat/module/system/syslog/config/syslog.yml @@ -1,4 +1,22 @@ +{{ if .use_journald }} +type: journald +id: system-syslog +facilities: + - 0 + - 1 + - 2 + - 3 + - 5 + - 6 + - 7 + - 8 + - 9 + - 11 + - 12 + - 15 +{{ else }} type: log +id: system-syslog paths: {{ range $i, $path := .paths }} - {{$path}} @@ -7,6 +25,9 @@ exclude_files: [".gz$"] multiline: pattern: "^\\s" match: after +{{ end }} + +# Common configuration processors: - add_locale: ~ - add_fields: diff --git a/filebeat/module/system/syslog/ingest/entrypoint.yml b/filebeat/module/system/syslog/ingest/entrypoint.yml new file mode 100644 index 000000000000..42a0f4ebb82c --- /dev/null +++ b/filebeat/module/system/syslog/ingest/entrypoint.yml @@ -0,0 +1,9 @@ +description: Entrypoint Pipeline for system/syslog Filebeat module +processors: + - pipeline: + if: ctx?.input?.type == "journald" + name: '{< IngestPipeline "journald" >}' + + - pipeline: + if: ctx?.input?.type == "log" + name: '{< IngestPipeline "files" >}' diff --git a/filebeat/module/system/syslog/ingest/pipeline.yml b/filebeat/module/system/syslog/ingest/files.yml similarity index 100% rename from filebeat/module/system/syslog/ingest/pipeline.yml rename to filebeat/module/system/syslog/ingest/files.yml diff --git a/filebeat/module/system/syslog/ingest/journald.yml b/filebeat/module/system/syslog/ingest/journald.yml new file mode 100644 index 000000000000..38b87dc8e0a2 --- /dev/null +++ b/filebeat/module/system/syslog/ingest/journald.yml @@ -0,0 +1,34 @@ +description: Journald Pipeline for system/syslog Filebeat module +processors: + - set: + field: event.ingested + copy_from: _ingest.timestamp + - set: + field: "process.pid" + copy_from: "journald.pid" + ignore_failure: true + - set: + field: "process.name" + copy_from: "journald.process.name" + ignore_failure: true + - set: + field: event.kind + value: event + - append: + field: related.hosts + value: "{{host.hostname}}" + if: "ctx.host?.hostname != null && ctx.host?.hostname != ''" + allow_duplicates: false + - remove: + description: Remove the extra fields added by the Journald input + ignore_missing: true + field: + - journald + - process.thread + - syslog + - systemd + - message_id +on_failure: + - set: + field: error.message + value: '{{ _ingest.on_failure_message }}' diff --git a/filebeat/module/system/syslog/manifest.yml b/filebeat/module/system/syslog/manifest.yml index 39a34e56ca3a..a53715ceb7b8 100644 --- a/filebeat/module/system/syslog/manifest.yml +++ b/filebeat/module/system/syslog/manifest.yml @@ -8,6 +8,12 @@ var: os.darwin: - /var/log/system.log* os.windows: [] + - name: use_journald + default: false + +ingest_pipeline: + - ingest/entrypoint.yml + - ingest/files.yml + - ingest/journald.yml -ingest_pipeline: ingest/pipeline.yml input: config/syslog.yml diff --git a/filebeat/module/system/syslog/test/debian-12.export b/filebeat/module/system/syslog/test/debian-12.export new file mode 100644 index 000000000000..780bd46990ec Binary files /dev/null and b/filebeat/module/system/syslog/test/debian-12.export differ diff --git a/filebeat/module/system/syslog/test/debian-12.journal b/filebeat/module/system/syslog/test/debian-12.journal new file mode 100644 index 000000000000..f4c01a22c3f7 Binary files /dev/null and b/filebeat/module/system/syslog/test/debian-12.journal differ diff --git a/filebeat/module/system/syslog/test/debian-12.journal-expected.json b/filebeat/module/system/syslog/test/debian-12.journal-expected.json new file mode 100644 index 000000000000..b75cce10fc8a --- /dev/null +++ b/filebeat/module/system/syslog/test/debian-12.journal-expected.json @@ -0,0 +1,62 @@ +[ + { + "event.dataset": "system.syslog", + "event.kind": "event", + "event.module": "system", + "event.timezone": "-02:00", + "fileset.name": "syslog", + "host.hostname": "vagrant-debian-12", + "host.id": "5e6dc8fe417f4ea383e2afaa731f5d8a", + "input.type": "journald", + "log.syslog.facility.code": 3, + "log.syslog.priority": 6, + "message": "Stopped target getty.target - Login Prompts.", + "process.args": [ + "/sbin/init" + ], + "process.args_count": 1, + "process.command_line": "/sbin/init", + "process.name": "systemd", + "process.pid": 1, + "related.hosts": [ + "vagrant-debian-12" + ], + "service.type": "system", + "user.group.id": "0", + "user.id": "0" + }, + { + "event.dataset": "system.syslog", + "event.kind": "event", + "event.module": "system", + "event.timezone": "-02:00", + "fileset.name": "syslog", + "host.hostname": "vagrant-debian-12", + "host.id": "5e6dc8fe417f4ea383e2afaa731f5d8a", + "input.type": "journald", + "log.syslog.facility.code": 0, + "log.syslog.priority": 6, + "message": "Console: switching to colour frame buffer device 160x50", + "related.hosts": [ + "vagrant-debian-12" + ], + "service.type": "system" + }, + { + "event.dataset": "system.syslog", + "event.kind": "event", + "event.module": "system", + "event.timezone": "-02:00", + "fileset.name": "syslog", + "host.hostname": "bookworm", + "host.id": "5e6dc8fe417f4ea383e2afaa731f5d8a", + "input.type": "journald", + "log.syslog.facility.code": 0, + "log.syslog.priority": 6, + "message": "thermal_sys: Registered thermal governor 'power_allocator'", + "related.hosts": [ + "bookworm" + ], + "service.type": "system" + } +] \ No newline at end of file diff --git a/filebeat/modules.d/system.yml.disabled b/filebeat/modules.d/system.yml.disabled index 1302c6374da8..fc4debca3bf6 100644 --- a/filebeat/modules.d/system.yml.disabled +++ b/filebeat/modules.d/system.yml.disabled @@ -10,6 +10,9 @@ # Filebeat will choose the paths depending on your OS. #var.paths: + # Use journald to collect system logs + #var.use_journald: false + # Authorization logs auth: enabled: false @@ -17,3 +20,6 @@ # Set custom paths for the log files. If left empty, # Filebeat will choose the paths depending on your OS. #var.paths: + + # Use journald to collect auth logs + #var.use_journald: false diff --git a/filebeat/processor/add_kubernetes_metadata/matchers_test.go b/filebeat/processor/add_kubernetes_metadata/matchers_test.go index 1b2191278673..ccae66f8002f 100644 --- a/filebeat/processor/add_kubernetes_metadata/matchers_test.go +++ b/filebeat/processor/add_kubernetes_metadata/matchers_test.go @@ -19,6 +19,7 @@ package add_kubernetes_metadata import ( "fmt" + "os" "runtime" "testing" @@ -36,6 +37,8 @@ const puid = "005f3b90-4b9d-12f8-acf0-31020a840133" func TestMain(m *testing.M) { InitializeModule() + + os.Exit(m.Run()) } func TestLogsPathMatcher_InvalidSource1(t *testing.T) { diff --git a/filebeat/tests/integration/filestream_test.go b/filebeat/tests/integration/filestream_test.go index 3ddb04a2c20c..45cf99fbfb61 100644 --- a/filebeat/tests/integration/filestream_test.go +++ b/filebeat/tests/integration/filestream_test.go @@ -26,6 +26,9 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/elastic/beats/v7/libbeat/tests/integration" ) @@ -105,3 +108,166 @@ func TestFilestreamCleanInactive(t *testing.T) { registryFile := filepath.Join(filebeat.TempDir(), "data", "registry", "filebeat", "log.json") filebeat.WaitFileContains(registryFile, `"op":"remove"`, time.Second) } + +func TestFilestreamValidationPreventsFilebeatStart(t *testing.T) { + duplicatedIDs := ` +filebeat.inputs: + - type: filestream + id: duplicated-id-1 + enabled: true + paths: + - /tmp/*.log + - type: filestream + id: duplicated-id-1 + enabled: true + paths: + - /var/log/*.log + +output.discard.enabled: true +logging: + level: debug + metrics: + enabled: false +` + emptyID := ` +filebeat.inputs: + - type: filestream + enabled: true + paths: + - /tmp/*.log + - type: filestream + enabled: true + paths: + - /var/log/*.log + +output.discard.enabled: true +logging: + level: debug + metrics: + enabled: false +` + multipleDuplicatedIDs := ` +filebeat.inputs: + - type: filestream + enabled: true + paths: + - /tmp/*.log + - type: filestream + enabled: true + paths: + - /var/log/*.log + + - type: filestream + id: duplicated-id-1 + enabled: true + paths: + - /tmp/duplicated-id-1.log + - type: filestream + id: duplicated-id-1 + enabled: true + paths: + - /tmp/duplicated-id-1-2.log + + + - type: filestream + id: unique-id-1 + enabled: true + paths: + - /tmp/unique-id-1.log + - type: filestream + id: unique-id-2 + enabled: true + paths: + - /var/log/unique-id-2.log + +output.discard.enabled: true +logging: + level: debug + metrics: + enabled: false +` + tcs := []struct { + name string + cfg string + }{ + { + name: "duplicated IDs", + cfg: duplicatedIDs, + }, + { + name: "duplicated empty ID", + cfg: emptyID, + }, + { + name: "two inputs without ID and duplicated IDs", + cfg: multipleDuplicatedIDs, + }, + } + + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + filebeat := integration.NewBeat( + t, + "filebeat", + "../../filebeat.test", + ) + + // Write configuration file and start Filebeat + filebeat.WriteConfigFile(tc.cfg) + filebeat.Start() + + // Wait for error log + filebeat.WaitForLogs( + "filestream inputs validation error", + 10*time.Second, + "Filebeat did not log a filestream input validation error") + + proc, err := filebeat.Process.Wait() + require.NoError(t, err, "filebeat process.Wait returned an error") + assert.False(t, proc.Success(), "filebeat should have failed to start") + + }) + } +} + +func TestFilestreamValidationSucceeds(t *testing.T) { + cfg := ` +filebeat.inputs: + - type: filestream + enabled: true + paths: + - /var/log/*.log + + - type: filestream + id: unique-id-1 + enabled: true + paths: + - /tmp/unique-id-1.log + - type: filestream + id: unique-id-2 + enabled: true + paths: + - /var/log/unique-id-2.log + +output.discard.enabled: true +logging: + level: debug + metrics: + enabled: false +` + filebeat := integration.NewBeat( + t, + "filebeat", + "../../filebeat.test", + ) + + // Write configuration file and start Filebeat + filebeat.WriteConfigFile(cfg) + filebeat.Start() + + // Wait for error log + filebeat.WaitForLogs( + "Input 'filestream' starting", + 10*time.Second, + "Filebeat did log a validation error") +} diff --git a/filebeat/tests/integration/translate_ldap_attribute_test.go b/filebeat/tests/integration/translate_ldap_attribute_test.go index e2b0f877efc3..376be5e36a23 100644 --- a/filebeat/tests/integration/translate_ldap_attribute_test.go +++ b/filebeat/tests/integration/translate_ldap_attribute_test.go @@ -64,7 +64,7 @@ logging: processors: - add_fields: - fields: + fields: guid: '%s' - translate_ldap_attribute: field: fields.guid @@ -120,7 +120,7 @@ func TestTranslateGUIDWithLDAP(t *testing.T) { filebeat.WaitFileContains( outputFile, fmt.Sprintf(`"fields":{"guid":"%s","common_name":["User1","user01"]}`, entryUUID), - 10*time.Second, + 20*time.Second, ) } diff --git a/filebeat/tests/system/test_modules.py b/filebeat/tests/system/test_modules.py index db8022b372fc..f5e7bdc2c391 100644 --- a/filebeat/tests/system/test_modules.py +++ b/filebeat/tests/system/test_modules.py @@ -196,7 +196,7 @@ def run_on_file(self, module, fileset, test_file, cfgfile): cmd.append("{module}.{fileset}.var.use_journald=true".format( module=module, fileset=fileset)) cmd.append("-M") - cmd.append("{module}.{fileset}.input.journald.paths=[{test_file}]".format( + cmd.append("{module}.{fileset}.input.paths=[{test_file}]".format( module=module, fileset=fileset, test_file=test_file)) else: cmd.append("-M") diff --git a/go.mod b/go.mod index ebafd4e4ec08..77abb4800d16 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( code.cloudfoundry.org/go-loggregator v7.4.0+incompatible code.cloudfoundry.org/rfc5424 v0.0.0-20180905210152-236a6d29298a // indirect github.com/Azure/azure-event-hubs-go/v3 v3.6.1 - github.com/Azure/azure-sdk-for-go v65.0.0+incompatible + github.com/Azure/azure-sdk-for-go v68.0.0+incompatible github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/Azure/go-autorest/autorest v0.11.29 github.com/Azure/go-autorest/autorest/date v0.3.0 @@ -18,12 +18,10 @@ require ( github.com/Microsoft/go-winio v0.6.2 github.com/PaesslerAG/gval v1.2.2 github.com/PaesslerAG/jsonpath v0.1.1 - github.com/Shopify/sarama v1.27.0 github.com/StackExchange/wmi v1.2.1 github.com/akavel/rsrc v0.8.0 // indirect github.com/apoydence/eachers v0.0.0-20181020210610-23942921fe77 // indirect github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 - github.com/aws/aws-lambda-go v1.44.0 github.com/aws/aws-sdk-go-v2 v1.30.5 github.com/aws/aws-sdk-go-v2/config v1.27.29 github.com/aws/aws-sdk-go-v2/credentials v1.17.29 @@ -40,7 +38,6 @@ require ( github.com/aws/aws-sdk-go-v2/service/sqs v1.34.5 github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 - github.com/bsm/sarama-cluster v2.1.14-0.20180625083203-7e67d87a6b3f+incompatible github.com/cavaliergopher/rpm v1.2.0 github.com/cespare/xxhash/v2 v2.3.0 github.com/cloudfoundry-community/go-cfclient v0.0.0-20190808214049-35bcce23fc5f @@ -49,7 +46,6 @@ require ( github.com/containerd/fifo v1.1.0 github.com/coreos/go-systemd/v22 v22.5.0 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f - github.com/denisenkom/go-mssqldb v0.12.3 github.com/devigned/tab v0.1.2-0.20190607222403-0c15cf42f9a2 github.com/digitalocean/go-libvirt v0.0.0-20240709142323-d8406205c752 github.com/docker/docker v27.3.1+incompatible @@ -60,18 +56,18 @@ require ( github.com/dop251/goja v0.0.0-20200831102558-9af81ddcf0e1 github.com/dop251/goja_nodejs v0.0.0-20171011081505-adff31b136e6 github.com/dustin/go-humanize v1.0.1 - github.com/eapache/go-resiliency v1.2.0 + github.com/eapache/go-resiliency v1.7.0 github.com/eclipse/paho.mqtt.golang v1.3.5 github.com/elastic/elastic-agent-client/v7 v7.15.0 github.com/elastic/go-concert v0.3.0 - github.com/elastic/go-libaudit/v2 v2.5.0 + github.com/elastic/go-libaudit/v2 v2.6.1 github.com/elastic/go-licenser v0.4.2 github.com/elastic/go-lookslike v1.0.1 github.com/elastic/go-lumber v0.1.2-0.20220819171948-335fde24ea0f - github.com/elastic/go-perf v0.0.0-20191212140718-9c656876f595 - github.com/elastic/go-seccomp-bpf v1.4.0 + github.com/elastic/go-perf v0.0.0-20241029065020-30bec95324b8 + github.com/elastic/go-seccomp-bpf v1.5.0 github.com/elastic/go-structform v0.0.10 - github.com/elastic/go-sysinfo v1.14.2 + github.com/elastic/go-sysinfo v1.15.0 github.com/elastic/go-ucfg v0.8.8 github.com/elastic/gosigar v0.14.3 github.com/fatih/color v1.16.0 @@ -85,17 +81,15 @@ require ( github.com/godror/godror v0.33.2 github.com/gofrs/flock v0.8.1 github.com/gogo/protobuf v1.3.2 - github.com/golang/mock v1.6.0 github.com/golang/snappy v0.0.4 github.com/gomodule/redigo v1.8.3 - github.com/google/flatbuffers v23.5.26+incompatible + github.com/google/flatbuffers v24.3.25+incompatible github.com/google/go-cmp v0.6.0 github.com/google/gopacket v1.1.19 github.com/google/uuid v1.6.0 // indirect github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75 github.com/h2non/filetype v1.1.1 github.com/hashicorp/go-retryablehttp v0.7.7 - github.com/hashicorp/golang-lru v0.6.0 github.com/hashicorp/nomad/api v0.0.0-20240717122358-3d93bd3778f3 github.com/hectane/go-acl v0.0.0-20190604041725-da78bae5fc95 github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd @@ -133,13 +127,13 @@ require ( go.etcd.io/bbolt v1.3.10 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 - golang.org/x/crypto v0.27.0 + golang.org/x/crypto v0.28.0 golang.org/x/mod v0.21.0 - golang.org/x/net v0.29.0 + golang.org/x/net v0.30.0 golang.org/x/oauth2 v0.22.0 golang.org/x/sync v0.8.0 - golang.org/x/sys v0.25.0 - golang.org/x/text v0.18.0 + golang.org/x/sys v0.26.0 + golang.org/x/text v0.19.0 golang.org/x/time v0.6.0 golang.org/x/tools v0.25.0 google.golang.org/api v0.191.0 @@ -147,10 +141,6 @@ require ( google.golang.org/grpc v1.66.0 google.golang.org/protobuf v1.34.2 gopkg.in/inf.v0 v0.9.1 - gopkg.in/jcmturner/aescts.v1 v1.0.1 // indirect - gopkg.in/jcmturner/dnsutils.v1 v1.0.1 // indirect - gopkg.in/jcmturner/goidentity.v3 v3.0.0 // indirect - gopkg.in/jcmturner/gokrb5.v7 v7.5.0 gopkg.in/yaml.v2 v2.4.0 gotest.tools/gotestsum v1.7.0 howett.net/plist v1.0.1 @@ -176,28 +166,25 @@ require ( github.com/Azure/azure-storage-blob-go v0.15.0 github.com/Azure/go-autorest/autorest/adal v0.9.24 github.com/aerospike/aerospike-client-go/v7 v7.7.1 - github.com/apache/arrow/go/v14 v14.0.2 + github.com/apache/arrow/go/v17 v17.0.0 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.13 github.com/aws/aws-sdk-go-v2/service/apigateway v1.25.8 github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.22.8 - github.com/aws/aws-sdk-go-v2/service/cloudformation v1.53.5 github.com/aws/aws-sdk-go-v2/service/health v1.26.4 - github.com/aws/aws-sdk-go-v2/service/kinesis v1.29.5 github.com/aws/smithy-go v1.20.4 - github.com/awslabs/goformation/v7 v7.14.9 - github.com/awslabs/kinesis-aggregation/go/v2 v2.0.0-20220623125934-28468a6701b5 - github.com/dgraph-io/badger/v4 v4.2.1-0.20240828131336-2725dc8ed5c2 + github.com/dgraph-io/badger/v4 v4.4.0 github.com/elastic/bayeux v1.0.5 github.com/elastic/ebpfevents v0.6.0 github.com/elastic/elastic-agent-autodiscover v0.9.0 - github.com/elastic/elastic-agent-libs v0.17.3 - github.com/elastic/elastic-agent-system-metrics v0.11.4 + github.com/elastic/elastic-agent-libs v0.17.4 + github.com/elastic/elastic-agent-system-metrics v0.11.5 github.com/elastic/go-elasticsearch/v8 v8.14.0 github.com/elastic/go-quark v0.2.0 github.com/elastic/go-sfdc v0.0.0-20241010131323-8e176480d727 - github.com/elastic/mito v1.15.0 + github.com/elastic/mito v1.16.0 github.com/elastic/mock-es v0.0.0-20240712014503-e5b47ece0015 + github.com/elastic/sarama v1.19.1-0.20241120141909-c7eabfcee7e5 github.com/elastic/tk-btf v0.1.0 github.com/elastic/toutoumomoma v0.0.0-20240626215117-76e39db18dfb github.com/foxcpp/go-mockdns v0.0.0-20201212160233-ede2f9158d15 @@ -209,13 +196,17 @@ require ( github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 + github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/icholy/digest v0.1.22 + github.com/jcmturner/gokrb5/v8 v8.4.4 + github.com/klauspost/compress v1.17.11 github.com/meraki/dashboard-api-go/v3 v3.0.9 + github.com/microsoft/go-mssqldb v1.7.2 github.com/otiai10/copy v1.12.0 - github.com/pierrec/lz4/v4 v4.1.18 + github.com/pierrec/lz4/v4 v4.1.21 github.com/pkg/xattr v0.4.9 github.com/prometheus/prometheus v0.54.1 - github.com/shirou/gopsutil/v3 v3.22.10 + github.com/shirou/gopsutil/v4 v4.24.7 github.com/tklauser/go-sysconf v0.3.12 github.com/xdg-go/scram v1.1.2 github.com/zyedidia/generic v1.2.1 @@ -227,7 +218,8 @@ require ( go.opentelemetry.io/collector/consumer v0.109.0 go.opentelemetry.io/collector/pdata v1.15.0 go.opentelemetry.io/collector/receiver v0.109.0 - golang.org/x/term v0.24.0 + go.uber.org/mock v0.5.0 + golang.org/x/term v0.25.0 google.golang.org/genproto/googleapis/api v0.0.0-20240725223205-93522f1f2a9f gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) @@ -253,10 +245,10 @@ require ( github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c // indirect - github.com/andybalholm/brotli v1.0.5 // indirect + github.com/andybalholm/brotli v1.1.0 // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/apache/arrow/go/v15 v15.0.2 // indirect - github.com/apache/thrift v0.19.0 // indirect + github.com/apache/thrift v0.20.0 // indirect github.com/armon/go-radix v1.0.0 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 // indirect @@ -277,11 +269,11 @@ require ( github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 // indirect github.com/cyphar/filepath-securejoin v0.2.5 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/dgraph-io/ristretto v0.1.2-0.20240116140435-c67e07994f91 // indirect + github.com/dgraph-io/ristretto/v2 v2.0.0 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/dnephin/pflag v1.0.7 // indirect github.com/docker/go-metrics v0.0.1 // indirect - github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect + github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect github.com/eapache/queue v1.1.0 // indirect github.com/elastic/elastic-transport-go/v8 v8.6.0 // indirect github.com/elastic/go-windows v1.0.2 // indirect @@ -301,10 +293,10 @@ require ( github.com/go-openapi/jsonreference v0.20.4 // indirect github.com/go-openapi/swag v0.22.9 // indirect github.com/go-resty/resty/v2 v2.13.1 // indirect - github.com/goccy/go-json v0.10.2 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/godror/knownpb v0.1.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect - github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect + github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect @@ -320,22 +312,21 @@ require ( github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect - github.com/hashicorp/go-uuid v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/go-version v1.2.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect - github.com/jcmturner/gofork v1.0.0 // indirect - github.com/jcmturner/gokrb5/v8 v8.4.2 // indirect + github.com/jcmturner/gofork v1.7.6 // indirect + github.com/jcmturner/goidentity/v6 v6.0.1 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/klauspost/asmfmt v1.3.2 // indirect - github.com/klauspost/compress v1.17.9 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/kortschak/utter v1.5.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect @@ -357,21 +348,20 @@ require ( github.com/morikuni/aec v1.0.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect + github.com/onsi/ginkgo/v2 v2.17.1 // indirect + github.com/onsi/gomega v1.33.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect - github.com/pierrec/lz4 v2.6.0+incompatible // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/prometheus/client_golang v1.20.2 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/sergi/go-diff v1.3.1 // indirect - github.com/shirou/gopsutil/v4 v4.24.7 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/tklauser/numcpus v0.6.1 // indirect - github.com/vishvananda/netlink v1.2.1-beta.2 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect @@ -388,7 +378,7 @@ require ( go.opentelemetry.io/otel/metric v1.29.0 // indirect go.opentelemetry.io/otel/trace v1.29.0 // indirect go.uber.org/ratelimit v0.3.1 // indirect - golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect gopkg.in/yaml.v3 v3.0.1 // indirect @@ -409,13 +399,10 @@ require ( github.com/google/gofuzz v1.2.0 // indirect github.com/moby/term v0.5.0 // indirect github.com/yuin/gopher-lua v1.1.1 // indirect - gopkg.in/jcmturner/rpc.v1 v1.1.0 // indirect ) replace ( github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/consumption/armconsumption => github.com/elastic/azure-sdk-for-go/sdk/resourcemanager/consumption/armconsumption v1.1.0-elastic - - github.com/Shopify/sarama => github.com/elastic/sarama v1.19.1-0.20220310193331-ebc2b0d8eef3 github.com/apoydence/eachers => github.com/poy/eachers v0.0.0-20181020210610-23942921fe77 //indirect, see https://github.com/elastic/beats/pull/29780 for details. github.com/dop251/goja => github.com/elastic/goja v0.0.0-20190128172624-dd2ac4456e20 github.com/fsnotify/fsevents => github.com/elastic/fsevents v0.0.0-20181029231046-e1d381a4d270 @@ -423,5 +410,4 @@ replace ( github.com/google/gopacket => github.com/elastic/gopacket v1.1.20-0.20241002174017-e8c5fda595e6 github.com/insomniacslk/dhcp => github.com/elastic/dhcp v0.0.0-20200227161230-57ec251c7eb3 // indirect github.com/meraki/dashboard-api-go/v3 => github.com/tommyers-elastic/dashboard-api-go/v3 v3.0.0-20240913150833-a945473a8f25 - github.com/snowflakedb/gosnowflake => github.com/snowflakedb/gosnowflake v1.6.19 ) diff --git a/go.sum b/go.sum index 56c592bb507e..2e45c13cbd3c 100644 --- a/go.sum +++ b/go.sum @@ -46,15 +46,12 @@ github.com/Azure/azure-event-hubs-go/v3 v3.6.1 h1:vSiMmn3tOwgiLyfnmhT5K6Of/3QWRL github.com/Azure/azure-event-hubs-go/v3 v3.6.1/go.mod h1:i2NByb9Pr2na7y8wi/XefEVKkuA2CDUjCNoWQJtTsGo= github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U= github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k= -github.com/Azure/azure-sdk-for-go v65.0.0+incompatible h1:HzKLt3kIwMm4KeJYTdx9EbjRYTySD/t8i1Ee/W5EGXw= -github.com/Azure/azure-sdk-for-go v65.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.13.0 h1:GJHeeA2N7xrG3q30L2UXDyuWRzDM900/65j70wcM4Ww= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.13.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= -github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= github.com/Azure/azure-sdk-for-go/sdk/messaging/azeventhubs v1.2.1 h1:0f6XnzroY1yCQQwxGf/n/2xlaBF02Qhof2as99dGNsY= @@ -75,6 +72,10 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1. github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0 h1:PiSrjRPpkQNjrM8H0WwKMnZUdu1RGMtd/LdGKUrOo+c= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0/go.mod h1:oDrbWx4ewMylP7xHivfgixbfGBT6APAwsSoHRKotnIc= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1/go.mod h1:GpPjLhVR9dnUoJMyHWSPy71xY9/lcmpzIPZXmF0FCVY= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.0 h1:Be6KInmFEKV81c0pOAEbRYehLMwmmGI1exuFj248AMk= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.0/go.mod h1:WCPBHsOXfBVnivScjs2ypRfimjEW0qPVLGgJkZlrIOA= github.com/Azure/azure-storage-blob-go v0.15.0 h1:rXtgp8tN1p29GvpGgfJetavIG0V7OgcSXPpwp3tx6qk= @@ -113,6 +114,8 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzS github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/IBM/sarama v1.43.3 h1:Yj6L2IaNvb2mRBop39N7mmJAHBVY3dTPncr3qGVkxPA= +github.com/IBM/sarama v1.43.3/go.mod h1:FVIRaLrhK3Cla/9FfRF5X9Zua2KpS3SYIXxhac1H+FQ= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c h1:RGWPOewvKIROun94nF7v2cua9qP+thov/7M50KEoeSU= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= @@ -128,8 +131,6 @@ github.com/PaesslerAG/jsonpath v0.1.1 h1:c1/AToHQMVsduPAa4Vh6xp2U0evy4t8SWp8imEs github.com/PaesslerAG/jsonpath v0.1.1/go.mod h1:lVboNxFGal/VwW6d9JzIy56bUsYAP6tH/x80vjnCseY= github.com/PaloAltoNetworks/pango v0.10.2 h1:Tjn6vIzzAq6Dd7N0mDuiP8w8pz8k5W9zz/TTSUQCsQY= github.com/PaloAltoNetworks/pango v0.10.2/go.mod h1:GztcRnVLur7G+VFG7Z5ZKNFgScLtsycwPMp1qVebE5g= -github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/aerospike/aerospike-client-go/v7 v7.7.1 h1:lcskBtPZYe6ESObhIEQEp4XO1axYZpaFD3ie4iwr6tg= @@ -140,23 +141,20 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= -github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= -github.com/apache/arrow/go/v14 v14.0.2 h1:N8OkaJEOfI3mEZt07BIkvo4sC6XDbL+48MBPWO5IONw= -github.com/apache/arrow/go/v14 v14.0.2/go.mod h1:u3fgh3EdgN/YQ8cVQRguVW3R+seMybFg8QBQ5LU+eBY= github.com/apache/arrow/go/v15 v15.0.2 h1:60IliRbiyTWCWjERBCkO1W4Qun9svcYoZrSLcyOsMLE= github.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+yea1jass9YXgjA= -github.com/apache/thrift v0.19.0 h1:sOqkWPzMj7w6XaYbJQG7m4sGqVolaW/0D28Ln7yPzMk= -github.com/apache/thrift v0.19.0/go.mod h1:SUALL216IiaOw2Oy+5Vs9lboJ/t9g40C+G07Dc0QC1I= +github.com/apache/arrow/go/v17 v17.0.0 h1:RRR2bdqKcdbss9Gxy2NS/hK8i4LDMh23L6BbkN5+F54= +github.com/apache/arrow/go/v17 v17.0.0/go.mod h1:jR7QHkODl15PfYyjM2nU+yTLScZ/qfj7OSUZmJ8putc= +github.com/apache/thrift v0.20.0 h1:631+KvYbsBZxmuJjYwhezVsrfc/TbqtZV4QcxOX1fOI= +github.com/apache/thrift v0.20.0/go.mod h1:hOk1BQqcp2OLzGsyVXdfMk7YFlMxK3aoEVhjD06QhB8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/aws/aws-lambda-go v1.44.0 h1:Xp9PANXKsSJ23IhE4ths592uWTCEewswPhSH9qpAuQQ= -github.com/aws/aws-lambda-go v1.44.0/go.mod h1:dpMpZgvWx5vuQJfBt0zqBha60q7Dd7RfgJv23DymV8A= -github.com/aws/aws-sdk-go-v2 v1.9.0/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= github.com/aws/aws-sdk-go-v2 v1.30.5 h1:mWSRTwQAb0aLE17dSzztCVJWI9+cRMgqebndjwDyK0g= github.com/aws/aws-sdk-go-v2 v1.30.5/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4 h1:70PVAiL15/aBMh5LThwgXdSQorVr91L127ttckI9QQU= @@ -181,8 +179,6 @@ github.com/aws/aws-sdk-go-v2/service/apigateway v1.25.8 h1:CgEyY7gfTf7lHYcCi7+w6 github.com/aws/aws-sdk-go-v2/service/apigateway v1.25.8/go.mod h1:z99ur4Ha5540t8hb5XtqV/UMOnEoEZK22lhr5ZBS0zw= github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.22.8 h1:SWBNBbVbThg5Hdi3hWbVaDFjV/OyPbuqZLu4N+mj/Es= github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.22.8/go.mod h1:lz2IT8gzzSwao0Pa6uMSdCIPsprmgCkW83q6sHGZFDw= -github.com/aws/aws-sdk-go-v2/service/cloudformation v1.53.5 h1:YeTVIy7cJLeahs7K0jQGDGAd1YYND/to/z8N3kqZBhY= -github.com/aws/aws-sdk-go-v2/service/cloudformation v1.53.5/go.mod h1:y45SdA9v+dLlweaqwAQMoFeXqdRvgwevafa2X8iTqZQ= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.40.5 h1:/YvqO1j75i4leoV+Z3a5s/dAlEszf2wTKBW8jc3Gd4s= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.40.5/go.mod h1:maEDlnDRdhsc0xrUljh3dUJbej11AHz+VTQJsNw1QmE= github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.37.5 h1:cQpWa19MrnwPcHQfDjLy6GJLo6lpgbMNix4pt5zLuK0= @@ -205,9 +201,6 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 h1:tJ5RnkHC github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18/go.mod h1:++NHzT+nAF7ZPrHPsA+ENvsXkOO8wEu+C6RXltAG4/c= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.16 h1:jg16PhLPUiHIj8zYIW6bqzeQSuHVEiWnGA0Brz5Xv2I= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.16/go.mod h1:Uyk1zE1VVdsHSU7096h/rwnXDzOzYQVl+FNPhPw7ShY= -github.com/aws/aws-sdk-go-v2/service/kinesis v1.6.0/go.mod h1:9O7UG2pELnP0hq35+Gd7XDjOLBkg7tmgRQ0y14ZjoJI= -github.com/aws/aws-sdk-go-v2/service/kinesis v1.29.5 h1:iirGMva2IXw4kcqsvuF+uc8ARweuVqoQJjzRZGaiV1E= -github.com/aws/aws-sdk-go-v2/service/kinesis v1.29.5/go.mod h1:pKTvEQz1PcNd+gKArVyeHpVM63AWnFqYyg07WAQQANQ= github.com/aws/aws-sdk-go-v2/service/organizations v1.30.3 h1:gYS53GRIaSesL04BlZA9MEBzDlENidWR/JDBXhZonFs= github.com/aws/aws-sdk-go-v2/service/organizations v1.30.3/go.mod h1:qdJX3WZbuAan5dXCoinnJjuY1QERCpv3glXeI3+wbeA= github.com/aws/aws-sdk-go-v2/service/rds v1.82.2 h1:kO/fQcueYZvuL5kPzTPQ503cKZj8jyBNg1MlnIqpFPg= @@ -224,13 +217,8 @@ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 h1:SKvPgvdvmiTWoi0GAJ7AsJfO github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5/go.mod h1:20sz31hv/WsPa3HhU3hfrIet2kxM4Pe0r20eBZ20Tac= github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 h1:OMsEmCyz2i89XwRwPouAJvhj81wINh+4UK+k/0Yo/q8= github.com/aws/aws-sdk-go-v2/service/sts v1.30.5/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0= -github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4= github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= -github.com/awslabs/goformation/v7 v7.14.9 h1:sZjjpTqXrcBDz4Fi07JWTT7zKM68XsQkW/7iLAJbA/M= -github.com/awslabs/goformation/v7 v7.14.9/go.mod h1:7obldQ8NQ/AkMsgL5K3l4lRMDFB6kCGUloz5dURcXIs= -github.com/awslabs/kinesis-aggregation/go/v2 v2.0.0-20220623125934-28468a6701b5 h1:lxW5Q6K2IisyF5tlr6Ts0W4POGWQZco05MJjFmoeIHs= -github.com/awslabs/kinesis-aggregation/go/v2 v2.0.0-20220623125934-28468a6701b5/go.mod h1:0Qr1uMHFmHsIYMcG4T7BJ9yrJtWadhOmpABCX69dwuc= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -242,8 +230,6 @@ github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDb github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/bluekeyes/go-gitdiff v0.7.1 h1:graP4ElLRshr8ecu0UtqfNTCHrtSyZd3DABQm/DWesQ= github.com/bluekeyes/go-gitdiff v0.7.1/go.mod h1:QpfYYO1E0fTVHVZAZKiRjtSGY9823iCdvGXBcEzHGbM= -github.com/bsm/sarama-cluster v2.1.14-0.20180625083203-7e67d87a6b3f+incompatible h1:4g18+HnTDwEtO0n7K8B1Kjq+04MEKJRkhJNQ/hb9d5A= -github.com/bsm/sarama-cluster v2.1.14-0.20180625083203-7e67d87a6b3f+incompatible/go.mod h1:r7ao+4tTNXvWm+VRpRJchr2kQhqxgmAp2iEX5W96gMM= github.com/cavaliergopher/rpm v1.2.0 h1:s0h+QeVK252QFTolkhGiMeQ1f+tMeIMhGl8B1HUmGUc= github.com/cavaliergopher/rpm v1.2.0/go.mod h1:R0q3vTqa7RUvPofAZYrnjJ63hh2vngjFfphuXiExVos= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= @@ -274,7 +260,6 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo= @@ -283,14 +268,12 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw= -github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo= github.com/devigned/tab v0.1.2-0.20190607222403-0c15cf42f9a2 h1:6+hM8KeYKV0Z9EIINNqIEDyyIRAcNc2FW+/TUYNmWyw= github.com/devigned/tab v0.1.2-0.20190607222403-0c15cf42f9a2/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= -github.com/dgraph-io/badger/v4 v4.2.1-0.20240828131336-2725dc8ed5c2 h1:1JGAkmP07Stzb04z4nQYkqtXglMlU0F3Jx5ROqGMLtQ= -github.com/dgraph-io/badger/v4 v4.2.1-0.20240828131336-2725dc8ed5c2/go.mod h1:Sc0T595g8zqAQRDf44n+z3wG4BOqLwceaFntt8KPxUM= -github.com/dgraph-io/ristretto v0.1.2-0.20240116140435-c67e07994f91 h1:Pux6+xANi0I7RRo5E1gflI4EZ2yx3BGZ75JkAIvGEOA= -github.com/dgraph-io/ristretto v0.1.2-0.20240116140435-c67e07994f91/go.mod h1:swkazRqnUf1N62d0Nutz7KIj2UKqsm/H8tD0nBJAXqM= +github.com/dgraph-io/badger/v4 v4.4.0 h1:rA48XiDynZLyMdlaJl67p9+lqfqwxlgKtCpYLAio7Zk= +github.com/dgraph-io/badger/v4 v4.4.0/go.mod h1:sONMmPPfbnj9FPwS/etCqky/ULth6CQJuAZSuWCmixE= +github.com/dgraph-io/ristretto/v2 v2.0.0 h1:l0yiSOtlJvc0otkqyMaDNysg8E9/F/TYZwMbxscNOAQ= +github.com/dgraph-io/ristretto/v2 v2.0.0/go.mod h1:FVFokF2dRqXyPyeMnK1YDy8Fc6aTe0IKgbcd03CYeEk= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/digitalocean/go-libvirt v0.0.0-20240709142323-d8406205c752 h1:NI7XEcHzWVvBfVjSVK6Qk4wmrUfoyQxCNpBjrHelZFk= @@ -301,7 +284,6 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/dnephin/pflag v1.0.7 h1:oxONGlWxhmUct0YzKTgrpQv9AUA1wtPBn7zuSjJqptk= github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE= github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI= @@ -320,10 +302,10 @@ github.com/dop251/goja_nodejs v0.0.0-20171011081505-adff31b136e6 h1:RrkoB0pT3gnj github.com/dop251/goja_nodejs v0.0.0-20171011081505-adff31b136e6/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q= -github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA= +github.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= +github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4ALJ04o5Qqpdz8XLIpNA3WM/iSIXqxtqo7UGVws= +github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/eclipse/paho.mqtt.golang v1.3.5 h1:sWtmgNxYM9P2sP+xEItMozsR3w0cqZFlqnNN1bdl41Y= @@ -340,10 +322,10 @@ github.com/elastic/elastic-agent-autodiscover v0.9.0 h1:+iWIKh0u3e8I+CJa3FfWe9h0 github.com/elastic/elastic-agent-autodiscover v0.9.0/go.mod h1:5iUxLHhVdaGSWYTveSwfJEY4RqPXTG13LPiFoxcpFd4= github.com/elastic/elastic-agent-client/v7 v7.15.0 h1:nDB7v8TBoNuD6IIzC3z7Q0y+7bMgXoT2DsHfolO2CHE= github.com/elastic/elastic-agent-client/v7 v7.15.0/go.mod h1:6h+f9QdIr3GO2ODC0Y8+aEXRwzbA5W4eV4dd/67z7nI= -github.com/elastic/elastic-agent-libs v0.17.3 h1:q79P05dhQkc5REzieVkkD9oRKrnptKY4MC6Typ+d8bc= -github.com/elastic/elastic-agent-libs v0.17.3/go.mod h1:5CR02awPrBr+tfmjBBK+JI+dMmHNQjpVY24J0wjbC7M= -github.com/elastic/elastic-agent-system-metrics v0.11.4 h1:Z/8CML5RKvGpi6/QUFok1K3EriBAv2kUAXnsk8hCifk= -github.com/elastic/elastic-agent-system-metrics v0.11.4/go.mod h1:TTW2ysv78uHBQ68hG8TXiaX1m6f29ZHgGWb8XONYsU8= +github.com/elastic/elastic-agent-libs v0.17.4 h1:kWK5Kn2EQjM97yHqbeXv+cFAIti4IiI9Qj8huM+lZzE= +github.com/elastic/elastic-agent-libs v0.17.4/go.mod h1:5CR02awPrBr+tfmjBBK+JI+dMmHNQjpVY24J0wjbC7M= +github.com/elastic/elastic-agent-system-metrics v0.11.5 h1:JSjXFEn8uYZ9hoC/GxZNMgJ622UoP96sjYP/49/Uvuo= +github.com/elastic/elastic-agent-system-metrics v0.11.5/go.mod h1:nzkrGajQA29YNcfP62gfzhxX9an3/xdQ3RmfQNw9YTI= github.com/elastic/elastic-transport-go/v8 v8.6.0 h1:Y2S/FBjx1LlCv5m6pWAF2kDJAHoSjSRSJCApolgfthA= github.com/elastic/elastic-transport-go/v8 v8.6.0/go.mod h1:YLHer5cj0csTzNFXoNQ8qhtGY1GTvSqPnKWKaqQE3Hk= github.com/elastic/fsevents v0.0.0-20181029231046-e1d381a4d270 h1:cWPqxlPtir4RoQVCpGSRXmLqjEHpJKbR60rxh1nQZY4= @@ -354,27 +336,26 @@ github.com/elastic/go-concert v0.3.0 h1:Y66JFn3ENndpHErOhTASu8/Fz1SSsLZicPufCmvQ github.com/elastic/go-concert v0.3.0/go.mod h1:UWt1MB5HxxZ85hKynLaYl/AaLIKFx0WiBP2uJSRfduA= github.com/elastic/go-elasticsearch/v8 v8.14.0 h1:1ywU8WFReLLcxE1WJqii3hTtbPUE2hc38ZK/j4mMFow= github.com/elastic/go-elasticsearch/v8 v8.14.0/go.mod h1:WRvnlGkSuZyp83M2U8El/LGXpCjYLrvlkSgkAH4O5I4= -github.com/elastic/go-libaudit/v2 v2.5.0 h1:5OK919QRnGtcjVBz3n/cs5F42im1mPlVTA9TyIn2K54= -github.com/elastic/go-libaudit/v2 v2.5.0/go.mod h1:AjlnhinP+kKQuUJoXLVrqxBM8uyhQmkzoV6jjsCFP4Q= -github.com/elastic/go-licenser v0.4.1/go.mod h1:V56wHMpmdURfibNBggaSBfqgPxyT1Tldns1i87iTEvU= +github.com/elastic/go-libaudit/v2 v2.6.1 h1:eN7tobGizmB+OJpCuG7gvPX7Nxni//H47uvMDXlMrI0= +github.com/elastic/go-libaudit/v2 v2.6.1/go.mod h1:8205nkf2oSrXFlO4H5j8/cyVMoSF3Y7jt+FjgS4ubQU= github.com/elastic/go-licenser v0.4.2 h1:bPbGm8bUd8rxzSswFOqvQh1dAkKGkgAmrPxbUi+Y9+A= github.com/elastic/go-licenser v0.4.2/go.mod h1:W8eH6FaZDR8fQGm+7FnVa7MxI1b/6dAqxz+zPB8nm5c= github.com/elastic/go-lookslike v1.0.1 h1:qVieyn6i/kx4xntar1cEB0qrGHVGNCX5KC8czAaTW/0= github.com/elastic/go-lookslike v1.0.1/go.mod h1:iSXdN6mmM0UVwbup8BY39Tyb51Dd+nX3eBsi5EgBAEo= github.com/elastic/go-lumber v0.1.2-0.20220819171948-335fde24ea0f h1:TsPpU5EAwlt7YZoupKlxZ093qTZYdGou3EhfTF1U0B4= github.com/elastic/go-lumber v0.1.2-0.20220819171948-335fde24ea0f/go.mod h1:HHaWnZamYKWsR9/eZNHqRHob8iQDKnchHmmskT/SKko= -github.com/elastic/go-perf v0.0.0-20191212140718-9c656876f595 h1:q8n4QjcLa4q39Q3fqHRknTBXBtegjriHFrB42YKgXGI= -github.com/elastic/go-perf v0.0.0-20191212140718-9c656876f595/go.mod h1:s09U1b4P1ZxnKx2OsqY7KlHdCesqZWIhyq0Gs/QC/Us= +github.com/elastic/go-perf v0.0.0-20241029065020-30bec95324b8 h1:FD01NjsTes0RxZVQ22ebNYJA4KDdInVnR9cn1hmaMwA= +github.com/elastic/go-perf v0.0.0-20241029065020-30bec95324b8/go.mod h1:Nt+pnRYvf0POC+7pXsrv8ubsEOSsaipJP0zlz1Ms1RM= github.com/elastic/go-quark v0.2.0 h1:r2BL4NzvhESrrL/yA3AcHt8mwF7fvQDssBAUiOL1sdg= github.com/elastic/go-quark v0.2.0/go.mod h1:/ngqgumD/Z5vnFZ4XPN2kCbxnEfG5/Uc+bRvOBabVVA= -github.com/elastic/go-seccomp-bpf v1.4.0 h1:6y3lYrEHrLH9QzUgOiK8WDqmPaMnnB785WxibCNIOH4= -github.com/elastic/go-seccomp-bpf v1.4.0/go.mod h1:wIMxjTbKpWGQk4CV9WltlG6haB4brjSH/dvAohBPM1I= +github.com/elastic/go-seccomp-bpf v1.5.0 h1:gJV+U1iP+YC70ySyGUUNk2YLJW5/IkEw4FZBJfW8ZZY= +github.com/elastic/go-seccomp-bpf v1.5.0/go.mod h1:umdhQ/3aybliBF2jjiZwS492I/TOKz+ZRvsLT3hVe1o= github.com/elastic/go-sfdc v0.0.0-20241010131323-8e176480d727 h1:yuiN60oaQUz2PtNpNhDI2H6zrCdfiiptmNdwV5WUaKA= github.com/elastic/go-sfdc v0.0.0-20241010131323-8e176480d727/go.mod h1:sw1pzz4pIqzDQxFWt3dFoG2uIUFAfThxlMfWpjH590E= github.com/elastic/go-structform v0.0.10 h1:oy08o/Ih2hHTkNcRY/1HhaYvIp5z6t8si8gnCJPDo1w= github.com/elastic/go-structform v0.0.10/go.mod h1:CZWf9aIRYY5SuKSmOhtXScE5uQiLZNqAFnwKR4OrIM4= -github.com/elastic/go-sysinfo v1.14.2 h1:DeIy+pVfdRsd08Nx2Xjh+dUS+jrEEI7LGc29U/BKVWo= -github.com/elastic/go-sysinfo v1.14.2/go.mod h1:jPSuTgXG+dhhh0GKIyI2Cso+w5lPJ5PvVqKlL8LV/Hk= +github.com/elastic/go-sysinfo v1.15.0 h1:54pRFlAYUlVNQ2HbXzLVZlV+fxS7Eax49stzg95M4Xw= +github.com/elastic/go-sysinfo v1.15.0/go.mod h1:jPSuTgXG+dhhh0GKIyI2Cso+w5lPJ5PvVqKlL8LV/Hk= github.com/elastic/go-ucfg v0.8.8 h1:54KIF/2zFKfl0MzsSOCGOsZ3O2bnjFQJ0nDJcLhviyk= github.com/elastic/go-ucfg v0.8.8/go.mod h1:4E8mPOLSUV9hQ7sgLEJ4bvt0KhMuDJa8joDT2QGAEKA= github.com/elastic/go-windows v1.0.2 h1:yoLLsAsV5cfg9FLhZ9EXZ2n2sQFKeDYrHenkcivY4vI= @@ -385,14 +366,14 @@ github.com/elastic/gopacket v1.1.20-0.20241002174017-e8c5fda595e6 h1:VgOx6omXIMK github.com/elastic/gopacket v1.1.20-0.20241002174017-e8c5fda595e6/go.mod h1:riddUzxTSBpJXk3qBHtYr4qOhFhT6k/1c0E3qkQjQpA= github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/uo= github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= -github.com/elastic/mito v1.15.0 h1:MicOxLSVkgU2Aonbh3i+++66Wl5wvD8y9gALK8PQDYs= -github.com/elastic/mito v1.15.0/go.mod h1:J+wCf4HccW2YoSFmZMGu+d06gN+WmnIlj5ehBqine74= +github.com/elastic/mito v1.16.0 h1:7UYy1OpJ8rlr4nzy/HDYQHuHjUIDMCofk5ICalYC2LA= +github.com/elastic/mito v1.16.0/go.mod h1:J+wCf4HccW2YoSFmZMGu+d06gN+WmnIlj5ehBqine74= github.com/elastic/mock-es v0.0.0-20240712014503-e5b47ece0015 h1:z8cC8GASpPo8yKlbnXI36HQ/BM9wYjhBPNbDjAWm0VU= github.com/elastic/mock-es v0.0.0-20240712014503-e5b47ece0015/go.mod h1:qH9DX/Dmflz6EAtaks/+2SsdQzecVAKE174Zl66hk7E= github.com/elastic/pkcs8 v1.0.0 h1:HhitlUKxhN288kcNcYkjW6/ouvuwJWd9ioxpjnD9jVA= github.com/elastic/pkcs8 v1.0.0/go.mod h1:ipsZToJfq1MxclVTwpG7U/bgeDtf+0HkUiOxebk95+0= -github.com/elastic/sarama v1.19.1-0.20220310193331-ebc2b0d8eef3 h1:FzA0/n4iMt8ojGDGRoiFPSHFvvdVIvxOxyLtiFnrLBM= -github.com/elastic/sarama v1.19.1-0.20220310193331-ebc2b0d8eef3/go.mod h1:mdtqvCSg8JOxk8PmpTNGyo6wzd4BMm4QXSfDnTXmgkE= +github.com/elastic/sarama v1.19.1-0.20241120141909-c7eabfcee7e5 h1:U7rts7RrrzQSDKkMuECpw9QCafSn2nRp36eRnWyR14E= +github.com/elastic/sarama v1.19.1-0.20241120141909-c7eabfcee7e5/go.mod h1:EEdpKWvuZ46X7OEOENvSH5jEJXosi4fn7xjIeTajf+M= github.com/elastic/tk-btf v0.1.0 h1:T4rbsnfaRH/MZKSLwZFd3sndt/NexsQb0IXWtMQ9PAA= github.com/elastic/tk-btf v0.1.0/go.mod h1:caLQPEcMbyKmPUQb2AsbX3ZAj1yCz06lOxfhn0esLR8= github.com/elastic/toutoumomoma v0.0.0-20240626215117-76e39db18dfb h1:8SvKmGOYyxKi6jB0nvV1lpxEHfIS6tQ40x1BXBhKMsE= @@ -424,7 +405,6 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/foxcpp/go-mockdns v0.0.0-20201212160233-ede2f9158d15 h1:nLPjjvpUAODOR6vY/7o0hBIk8iTr19Fvmf8aFx/kC7A= github.com/foxcpp/go-mockdns v0.0.0-20201212160233-ede2f9158d15/go.mod h1:tPg4cp4nseejPd+UKxtCVQ2hUxNTZ7qQZJa7CLriIeo= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= @@ -471,8 +451,8 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEe github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gocarina/gocsv v0.0.0-20170324095351-ffef3ffc77be h1:zXHeEEJ231bTf/IXqvCfeaqjLpXsq42ybLoT4ROSR6Y= github.com/gocarina/gocsv v0.0.0-20170324095351-ffef3ffc77be/go.mod h1:/oj50ZdPq/cUjA02lMZhijk5kR31SEydKyqah1OgBuo= -github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -492,8 +472,8 @@ github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOW github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -514,18 +494,16 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v1.8.3 h1:HR0kYDX2RJZvAup8CsiJwxB4dTCSC0AaUq6S4SiLwUc= github.com/gomodule/redigo v1.8.3/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= github.com/google/cel-go v0.19.0 h1:vVgaZoHPBDd1lXCYGQOh5A06L4EtuIfmqQ/qnSXSKiU= github.com/google/cel-go v0.19.0/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= -github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg= -github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI= +github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -535,7 +513,6 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -575,7 +552,9 @@ github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= @@ -604,13 +583,14 @@ github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISH github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= -github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/nomad/api v0.0.0-20240717122358-3d93bd3778f3 h1:fgVfQ4AC1avVOnu2cfms8VAiD8lUq3vWI8mTocOXN/w= github.com/hashicorp/nomad/api v0.0.0-20240717122358-3d93bd3778f3/go.mod h1:svtxn6QnrQ69P23VvIWMR34tg3vmwLz4UdUzm1dSCgE= github.com/hectane/go-acl v0.0.0-20190604041725-da78bae5fc95 h1:S4qyfL2sEm5Budr4KVMyEniCy+PbS55651I/a+Kn/NQ= @@ -627,12 +607,12 @@ github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFK github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= -github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8= -github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= -github.com/jcmturner/gokrb5/v8 v8.4.2 h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJzodkA= -github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= +github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -665,11 +645,10 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4= github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= -github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kortschak/utter v1.5.0 h1:1vHGHPZmJ6zU5XbfllIAG3eQBoHT97ePrZJ+pT3RoiQ= github.com/kortschak/utter v1.5.0/go.mod h1:vSmSjbyrlKjjsL71193LmzBOKgwePk9DH6uFaWHIInc= @@ -706,6 +685,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/microsoft/go-mssqldb v1.7.2 h1:CHkFJiObW7ItKTJfHo1QX7QBBD1iV+mn1eOyRP3b/PA= +github.com/microsoft/go-mssqldb v1.7.2/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA= github.com/miekg/dns v1.1.22/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= @@ -742,7 +723,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/montanaflynn/stats v0.7.0 h1:r3y12KyNxj/Sb/iOE46ws+3mS1+MZca1wlHQFPsY/JU= github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= @@ -778,13 +758,10 @@ github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAq github.com/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2 h1:CXwSGu/LYmbjEab5aMCs5usQRVBGThelUKBNnoSOuso= github.com/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2/go.mod h1:L3UMQOThbttwfYRNFOWLLVXMhk5Lkio4GGOtw5UrxS0= github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= -github.com/pierrec/lz4 v2.6.0+incompatible h1:Ix9yFKn1nSPBLFl/yZknTp8TU5G4Ps0JDmguYK6iH1A= -github.com/pierrec/lz4 v2.6.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= -github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= +github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrre/gotestcover v0.0.0-20160517101806-924dca7d15f0 h1:i5VIxp6QB8oWZ8IkK8zrDgeT6ORGIUeiN+61iETwJbI= github.com/pierrre/gotestcover v0.0.0-20160517101806-924dca7d15f0/go.mod h1:4xpMLz7RBWyB+ElzHu8Llua96TRCB3YwX+l5EP1wmHk= -github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -834,8 +811,6 @@ github.com/samuel/go-thrift v0.0.0-20140522043831-2187045faa54/go.mod h1:Vrkh1pn github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= -github.com/shirou/gopsutil/v3 v3.22.10 h1:4KMHdfBRYXGF9skjDWiL4RA2N+E8dRdodU/bOZpPoVg= -github.com/shirou/gopsutil/v3 v3.22.10/go.mod h1:QNza6r4YQoydyCfo6rH0blGfKahgibh4dQmV5xdFkQk= github.com/shirou/gopsutil/v4 v4.24.7 h1:V9UGTK4gQ8HvcnPKf6Zt3XHyQq/peaekfxpJ2HSocJk= github.com/shirou/gopsutil/v4 v4.24.7/go.mod h1:0uW/073rP7FYLOkvxolUQM5rMOLTNmRXnFKafpb71rw= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= @@ -868,7 +843,6 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -876,10 +850,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= -github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tommyers-elastic/dashboard-api-go/v3 v3.0.0-20240913150833-a945473a8f25 h1:o24r+NDexzdlwgqI0Dglq2I/cdONYRACikcUmYmovtQ= @@ -889,11 +861,9 @@ github.com/tsg/go-daemon v0.0.0-20200207173439-e704b93fd89b/go.mod h1:jAqhj/JBVC github.com/ugorji/go v1.1.8/go.mod h1:0lNM99SwWUIRhCXnigEMClngXBk/EmpTXa7mgiewYWA= github.com/ugorji/go/codec v1.1.8 h1:4dryPvxMP9OtkjIbuNeK2nb27M38XMHLGlfNSNph/5s= github.com/ugorji/go/codec v1.1.8/go.mod h1:X00B19HDtwvKbQY2DcYjvZxKQp8mzrJoQ6EgoIY/D2E= +github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs= -github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= -github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vmware/govmomi v0.39.0 h1:soLZ08Q2zvjRSinNup8xVlw0KDDCJPPA1rIDmBhi7As= @@ -904,19 +874,15 @@ github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= -github.com/xdg/scram v1.0.3/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= -github.com/xdg/stringprep v1.0.3/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk= github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= -github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= @@ -988,8 +954,9 @@ go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0 go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/ratelimit v0.3.1 h1:K4qVE+byfv/B3tC+4nYWP7v/6SimcO7HzHekoMNBma0= @@ -1005,10 +972,7 @@ golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= @@ -1016,22 +980,20 @@ golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 h1:/RIbNt/Zr7rVhIkQhooTxCxFcdWLGIKnZA4IXNFSrvo= -golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= @@ -1058,16 +1020,15 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= @@ -1103,7 +1064,6 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1113,9 +1073,6 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211102192858-4dd72447c267/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1132,8 +1089,8 @@ golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -1143,8 +1100,8 @@ golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= -golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= -golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -1156,8 +1113,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= @@ -1176,9 +1133,7 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200821192610-3366bbee4705/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= @@ -1189,8 +1144,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -gonum.org/v1/gonum v0.12.0 h1:xKuo6hzt+gMav00meVPUlXwSdoEJP46BR+wdxQEFK2o= -gonum.org/v1/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY= +gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ= +gonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo= google.golang.org/api v0.191.0 h1:cJcF09Z+4HAB2t5qTQM1ZtfL/PemsLFkcFG67qq2afk= google.golang.org/api v0.191.0/go.mod h1:tD5dsFGxFza0hnQveGfVk9QQYKcfp+VzgRqyXFxE0+E= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -1221,7 +1176,6 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 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/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= @@ -1239,16 +1193,6 @@ gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaD gopkg.in/hjson/hjson-go.v3 v3.0.1/go.mod h1:X6zrTSVeImfwfZLfgQdInl9mWjqPqgH90jom9nym/lw= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/jcmturner/aescts.v1 v1.0.1 h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hrEw= -gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= -gopkg.in/jcmturner/dnsutils.v1 v1.0.1 h1:cIuC1OLRGZrld+16ZJvvZxVJeKPsvd5eUIvxfoN5hSM= -gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= -gopkg.in/jcmturner/goidentity.v3 v3.0.0 h1:1duIyWiTaYvVx3YX2CYtpJbUFd7/UuPYCfgXtQ3VTbI= -gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= -gopkg.in/jcmturner/gokrb5.v7 v7.5.0 h1:a9tsXlIDD9SKxotJMK3niV7rPZAJeX2aD/0yg3qlIrg= -gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= -gopkg.in/jcmturner/rpc.v1 v1.1.0 h1:QHIUxTX1ISuAv9dD2wJ9HWQVuWDX/Zc0PfeC2tjc4rU= -gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= gopkg.in/mcuadros/go-syslog.v2 v2.3.0 h1:kcsiS+WsTKyIEPABJBJtoG0KkOS6yzvJ+/eZlhD79kk= gopkg.in/mcuadros/go-syslog.v2 v2.3.0/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= @@ -1263,7 +1207,6 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/gotestsum v1.7.0 h1:RwpqwwFKBAa2h+F6pMEGpE707Edld0etUD3GhqqhDNc= diff --git a/heartbeat/monitors/factory_test.go b/heartbeat/monitors/factory_test.go index e32ac671c8eb..72db7cdf7312 100644 --- a/heartbeat/monitors/factory_test.go +++ b/heartbeat/monitors/factory_test.go @@ -236,8 +236,8 @@ func TestDisabledMonitor(t *testing.T) { require.NoError(t, err) require.IsType(t, NoopRunner{}, runner) - require.Equal(t, 0, built.Load()) - require.Equal(t, 0, closed.Load()) + require.Equal(t, int64(0), built.Load()) + require.Equal(t, int64(0), closed.Load()) } } @@ -353,7 +353,7 @@ func TestDuplicateMonitorIDs(t *testing.T) { // Two are counted as built. The bad config is missing a stdfield so it // doesn't complete construction - require.Equal(t, 2, built.Load()) + require.Equal(t, int64(2), built.Load()) // Only 2 closes, because the bad config isn't closed - require.Equal(t, 2, closed.Load()) + require.Equal(t, int64(2), closed.Load()) } diff --git a/heartbeat/monitors/mocks.go b/heartbeat/monitors/mocks.go index c172d24464c8..2c4e5e9d0b51 100644 --- a/heartbeat/monitors/mocks.go +++ b/heartbeat/monitors/mocks.go @@ -21,6 +21,7 @@ import ( "fmt" "regexp" "sync" + "sync/atomic" "testing" "time" @@ -42,7 +43,6 @@ import ( "github.com/elastic/beats/v7/heartbeat/monitors/wrappers/monitorstate" "github.com/elastic/beats/v7/heartbeat/scheduler" "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/common/atomic" beatversion "github.com/elastic/beats/v7/libbeat/version" ) @@ -60,12 +60,8 @@ func makeMockFactory(pluginsReg *plugin.PluginsReg) (factory *RunnerFactory, sch EphemeralID: eid, FirstStart: time.Now(), StartTime: time.Now(), - Monitoring: struct { - DefaultUsername string - }{ - DefaultUsername: "test", - }, } + info.Monitoring.DefaultUsername = "test" sched = scheduler.Create( 1, @@ -216,17 +212,17 @@ func createMockJob() []jobs.Job { return []jobs.Job{j} } -func mockPluginBuilder() (plugin.PluginFactory, *atomic.Int, *atomic.Int) { +func mockPluginBuilder() (plugin.PluginFactory, *atomic.Int64, *atomic.Int64) { reg := monitoring.NewRegistry() - built := atomic.NewInt(0) - closed := atomic.NewInt(0) + built := &atomic.Int64{} + closed := &atomic.Int64{} return plugin.PluginFactory{ Name: "test", Aliases: []string{"testAlias"}, Make: func(s string, config *config.C) (plugin.Plugin, error) { - built.Inc() + built.Add(1) // Declare a real config block with a required attr so we can see what happens when it doesn't work unpacked := struct { URLs []string `config:"urls" validate:"required"` @@ -234,7 +230,7 @@ func mockPluginBuilder() (plugin.PluginFactory, *atomic.Int, *atomic.Int) { // track all closes, even on error closer := func() error { - closed.Inc() + closed.Add(1) return nil } @@ -246,12 +242,13 @@ func mockPluginBuilder() (plugin.PluginFactory, *atomic.Int, *atomic.Int) { return plugin.Plugin{Jobs: j, DoClose: closer, Endpoints: 1}, nil }, - Stats: plugin.NewPluginCountersRecorder("test", reg)}, + Stats: plugin.NewPluginCountersRecorder("test", reg), + }, built, closed } -func mockPluginsReg() (p *plugin.PluginsReg, built *atomic.Int, closed *atomic.Int) { +func mockPluginsReg() (p *plugin.PluginsReg, built *atomic.Int64, closed *atomic.Int64) { reg := plugin.NewPluginsReg() builder, built, closed := mockPluginBuilder() _ = reg.Add(builder) diff --git a/heartbeat/monitors/monitor_test.go b/heartbeat/monitors/monitor_test.go index 0890a1697bec..7bb3b5d3fae6 100644 --- a/heartbeat/monitors/monitor_test.go +++ b/heartbeat/monitors/monitor_test.go @@ -106,10 +106,10 @@ func testMonitorConfig(t *testing.T, conf *conf.C, eventValidator validator.Vali t.Fatalf("No publishes detected!") } - assert.Equal(t, 1, built.Load()) + assert.Equal(t, int64(1), built.Load()) mon.Stop() - assert.Equal(t, 1, closed.Load()) + assert.Equal(t, int64(1), closed.Load()) assert.Equal(t, true, pcClient.closed) } @@ -129,8 +129,8 @@ func TestCheckInvalidConfig(t *testing.T) { require.Nil(t, m, "For this test to work we need a nil value for the monitor.") // These counters are both zero since this fails at config parse time - require.Equal(t, 0, built.Load()) - require.Equal(t, 0, closed.Load()) + require.Equal(t, int64(0), built.Load()) + require.Equal(t, int64(0), closed.Load()) require.Error(t, checkMonitorConfig(serverMonConf, reg)) } diff --git a/heartbeat/scheduler/schedjob.go b/heartbeat/scheduler/schedjob.go index 2a8172b95641..50f94a895d0b 100644 --- a/heartbeat/scheduler/schedjob.go +++ b/heartbeat/scheduler/schedjob.go @@ -20,11 +20,11 @@ package scheduler import ( "context" "sync" + "sync/atomic" "time" "golang.org/x/sync/semaphore" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/elastic-agent-libs/logp" ) @@ -35,7 +35,7 @@ type schedJob struct { wg *sync.WaitGroup entrypoint TaskFunc jobLimitSem *semaphore.Weighted - activeTasks atomic.Int + activeTasks atomic.Int64 } // runRecursiveJob runs the entry point for a job, blocking until all subtasks are completed. @@ -48,7 +48,6 @@ func newSchedJob(ctx context.Context, s *Scheduler, id string, jobType string, t scheduler: s, jobLimitSem: s.jobLimitSem[jobType], entrypoint: task, - activeTasks: atomic.MakeInt(0), wg: &sync.WaitGroup{}, } } @@ -59,7 +58,7 @@ func newSchedJob(ctx context.Context, s *Scheduler, id string, jobType string, t // The wait group passed into this function expects to already have its count incremented by one. func (sj *schedJob) run() (startedAt time.Time) { sj.wg.Add(1) - sj.activeTasks.Inc() + sj.activeTasks.Add(1) if sj.jobLimitSem != nil { err := sj.jobLimitSem.Acquire(sj.ctx, 1) // Defer release only if acquired @@ -82,7 +81,7 @@ func (sj *schedJob) run() (startedAt time.Time) { // The wait group passed into this function expects to already have its count incremented by one. func (sj *schedJob) runTask(task TaskFunc) time.Time { defer sj.wg.Done() - defer sj.activeTasks.Dec() + defer sj.activeTasks.Add(-1) // The accounting for waiting/active tasks is done using atomics. // Absolute accuracy is not critical here so the gap between modifying waitingTasks and activeJobs is acceptable. @@ -113,7 +112,7 @@ func (sj *schedJob) runTask(task TaskFunc) time.Time { sj.scheduler.stats.activeTasks.Dec() sj.wg.Add(len(continuations)) - sj.activeTasks.Add(len(continuations)) + sj.activeTasks.Add(int64(len(continuations))) for _, cont := range continuations { // Run continuations in parallel, note that these each will acquire their own slots // We can discard the started at times for continuations as those are diff --git a/heartbeat/scheduler/schedjob_test.go b/heartbeat/scheduler/schedjob_test.go index 24e6178e1622..f989014f467c 100644 --- a/heartbeat/scheduler/schedjob_test.go +++ b/heartbeat/scheduler/schedjob_test.go @@ -20,13 +20,13 @@ package scheduler import ( "context" "sync" + "sync/atomic" "testing" "time" "github.com/stretchr/testify/require" "github.com/elastic/beats/v7/heartbeat/config" - batomic "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/elastic-agent-libs/monitoring" ) @@ -72,7 +72,7 @@ func TestSchedJobRun(t *testing.T) { wg := &sync.WaitGroup{} wg.Add(1) - executed := batomic.MakeBool(false) + executed := &atomic.Bool{} tf := func(ctx context.Context) []TaskFunc { executed.Store(true) @@ -102,14 +102,14 @@ func TestRecursiveForkingJob(t *testing.T) { s := Create(1000, monitoring.NewRegistry(), tarawaTime(), map[string]*config.JobLimit{ "atype": {Limit: 1}, }, false) - ran := batomic.NewInt(0) + var ran atomic.Int64 var terminalTf TaskFunc = func(ctx context.Context) []TaskFunc { - ran.Inc() + ran.Add(1) return nil } var forkingTf TaskFunc = func(ctx context.Context) []TaskFunc { - ran.Inc() + ran.Add(1) return []TaskFunc{ terminalTf, terminalTf, terminalTf, } @@ -118,6 +118,6 @@ func TestRecursiveForkingJob(t *testing.T) { sj := newSchedJob(context.Background(), s, "myid", "atype", forkingTf) sj.run() - require.Equal(t, 4, ran.Load()) + require.Equal(t, int64(4), ran.Load()) } diff --git a/libbeat/beat/info.go b/libbeat/beat/info.go index 314597abbb56..7c3b5c0d90f8 100644 --- a/libbeat/beat/info.go +++ b/libbeat/beat/info.go @@ -22,6 +22,8 @@ import ( "github.com/gofrs/uuid/v5" "go.opentelemetry.io/collector/consumer" + + "github.com/elastic/elastic-agent-libs/monitoring" ) // Info stores a beats instance meta data. @@ -41,9 +43,10 @@ type Info struct { // Monitoring-related fields Monitoring struct { - DefaultUsername string // The default username to be used to connect to Elasticsearch Monitoring + DefaultUsername string // The default username to be used to connect to Elasticsearch Monitoring + Namespace *monitoring.Namespace // a monitor namespace that is unique per beat instance } - LogConsumer consumer.Logs //otel log consumer + LogConsumer consumer.Logs // otel log consumer } diff --git a/libbeat/cmd/instance/beat.go b/libbeat/cmd/instance/beat.go index 6332ebac39b5..2d1eb3a20f02 100644 --- a/libbeat/cmd/instance/beat.go +++ b/libbeat/cmd/instance/beat.go @@ -337,6 +337,8 @@ func NewBeatReceiver(settings Settings, receiverConfig map[string]interface{}, c config.OverwriteConfigOpts(configOpts(store)) } + b.Beat.Info.Monitoring.Namespace = monitoring.GetNamespace(b.Info.Beat + "-" + b.Info.ID.String()) + instrumentation, err := instrumentation.New(cfg, b.Info.Beat, b.Info.Version) if err != nil { return nil, fmt.Errorf("error setting up instrumentation: %w", err) @@ -469,11 +471,6 @@ func NewBeatReceiver(settings Settings, receiverConfig map[string]interface{}, c return nil, fmt.Errorf("error creating processors: %w", err) } - reg := monitoring.Default.GetRegistry(b.Info.Name) - if reg == nil { - reg = monitoring.Default.NewRegistry(b.Info.Name) - } - // This should be replaced with static config for otel consumer // but need to figure out if we want the Queue settings from here. outputEnabled := b.Config.Output.IsSet() && b.Config.Output.Config().Enabled() @@ -485,12 +482,14 @@ func NewBeatReceiver(settings Settings, receiverConfig map[string]interface{}, c } } - tel := reg.GetRegistry("state") + uniq_reg := b.Beat.Info.Monitoring.Namespace.GetRegistry() + + tel := uniq_reg.GetRegistry("state") if tel == nil { - tel = reg.NewRegistry("state") + tel = uniq_reg.NewRegistry("state") } monitors := pipeline.Monitors{ - Metrics: reg, + Metrics: uniq_reg, Telemetry: tel, Logger: logp.L().Named("publisher"), Tracer: b.Instrumentation.Tracer(), @@ -510,7 +509,6 @@ func NewBeatReceiver(settings Settings, receiverConfig map[string]interface{}, c b.Publisher = publisher return b, nil - } // InitWithSettings does initialization of things common to all actions (read confs, flags) @@ -831,11 +829,27 @@ func (b *Beat) RegisterHostname(useFQDN bool) { hostname := b.Info.FQDNAwareHostname(useFQDN) // info.hostname - infoRegistry := monitoring.GetNamespace("info").GetRegistry() + var infoRegistry *monitoring.Registry + if b.Info.Monitoring.Namespace != nil { + infoRegistry = b.Info.Monitoring.Namespace.GetRegistry().GetRegistry("info") + if infoRegistry == nil { + infoRegistry = b.Info.Monitoring.Namespace.GetRegistry().NewRegistry("info") + } + } else { + infoRegistry = monitoring.GetNamespace("info").GetRegistry() + } monitoring.NewString(infoRegistry, "hostname").Set(hostname) // state.host - stateRegistry := monitoring.GetNamespace("state").GetRegistry() + var stateRegistry *monitoring.Registry + if b.Info.Monitoring.Namespace != nil { + stateRegistry = b.Info.Monitoring.Namespace.GetRegistry().GetRegistry("state") + if stateRegistry == nil { + stateRegistry = b.Info.Monitoring.Namespace.GetRegistry().NewRegistry("state") + } + } else { + stateRegistry = monitoring.GetNamespace("state").GetRegistry() + } monitoring.NewFunc(stateRegistry, "host", host.ReportInfo(hostname), monitoring.Report) } diff --git a/libbeat/cmd/platformcheck/platformcheck.go b/libbeat/cmd/platformcheck/platformcheck.go deleted file mode 100644 index c213a0a49a3c..000000000000 --- a/libbeat/cmd/platformcheck/platformcheck.go +++ /dev/null @@ -1,48 +0,0 @@ -// 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. - -//go:build linux || windows - -package platformcheck - -import ( - "fmt" - "math/bits" - "strings" - - "github.com/shirou/gopsutil/v3/host" -) - -func CheckNativePlatformCompat() error { - const compiledArchBits = bits.UintSize // 32 if the binary was compiled for 32 bit architecture. - - if compiledArchBits > 32 { - // We assume that 64bit binaries can only be run on 64bit systems - return nil - } - - arch, err := host.KernelArch() - if err != nil { - return err - } - - if strings.Contains(arch, "64") { - return fmt.Errorf("trying to run %vBit binary on 64Bit system", compiledArchBits) - } - - return nil -} diff --git a/libbeat/cmd/platformcheck/platformcheck_other.go b/libbeat/cmd/platformcheck/platformcheck_other.go deleted file mode 100644 index cab7157f7ee9..000000000000 --- a/libbeat/cmd/platformcheck/platformcheck_other.go +++ /dev/null @@ -1,24 +0,0 @@ -// 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. - -//go:build !linux && !windows - -package platformcheck - -func CheckNativePlatformCompat() error { - return nil -} diff --git a/libbeat/cmd/platformcheck/platformcheck_test.go b/libbeat/cmd/platformcheck/platformcheck_test.go deleted file mode 100644 index 9e8d71b4f969..000000000000 --- a/libbeat/cmd/platformcheck/platformcheck_test.go +++ /dev/null @@ -1,65 +0,0 @@ -// 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 platformcheck - -import ( - "os" - "os/exec" - "path/filepath" - "runtime" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestCheckPlatformCompat(t *testing.T) { - if !(runtime.GOARCH == "amd64" && (runtime.GOOS == "linux" || - runtime.GOOS == "windows")) { - t.Skip("Test not support on current platform") - } - - // compile test helper - tmp := t.TempDir() - helper := filepath.Join(tmp, "helper") - - cmd := exec.Command("go", "test", "-c", "-o", helper) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmd.Env = append(os.Environ(), "GOARCH=386") - require.NoError(t, cmd.Run(), "failed to compile test helper") - - // run test helper - cmd = exec.Command(helper, "-test.v", "-test.run", "TestHelper") - cmd.Env = []string{"GO_USE_HELPER=1"} - output, err := cmd.Output() - if err != nil { - t.Logf("32bit binary tester failed.\n Output: %s", output) - } -} - -func TestHelper(t *testing.T) { - if os.Getenv("GO_USE_HELPER") != "1" { - t.Log("ignore helper") - return - } - - err := CheckNativePlatformCompat() - if err.Error() != "trying to run 32Bit binary on 64Bit system" { - t.Error("expected the native platform check to fail") - } -} diff --git a/libbeat/cmd/root.go b/libbeat/cmd/root.go index cbe2f7f8f6e5..335b83560d78 100644 --- a/libbeat/cmd/root.go +++ b/libbeat/cmd/root.go @@ -20,14 +20,12 @@ package cmd import ( "flag" "fmt" - "os" "github.com/spf13/cobra" "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/beats/v7/libbeat/cfgfile" "github.com/elastic/beats/v7/libbeat/cmd/instance" - "github.com/elastic/beats/v7/libbeat/cmd/platformcheck" "github.com/elastic/beats/v7/libbeat/licenser" "github.com/elastic/beats/v7/libbeat/outputs/elasticsearch" ) @@ -53,11 +51,6 @@ func GenRootCmdWithSettings(beatCreator beat.Creator, settings instance.Settings // Check we are actually talking with Elasticsearch, to ensure that used features actually exist. _, _ = elasticsearch.RegisterGlobalCallback(licenser.FetchAndVerify) - if err := platformcheck.CheckNativePlatformCompat(); err != nil { - fmt.Fprintf(os.Stderr, "Failed to initialize: %v\n", err) - os.Exit(1) - } - if settings.IndexPrefix == "" { settings.IndexPrefix = settings.Name } diff --git a/libbeat/common/acker/acker.go b/libbeat/common/acker/acker.go index c75aec13564b..47c019a576f1 100644 --- a/libbeat/common/acker/acker.go +++ b/libbeat/common/acker/acker.go @@ -19,9 +19,9 @@ package acker import ( "sync" + "sync/atomic" "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/common/atomic" ) // Nil creates an ACKer that does nothing. @@ -98,7 +98,7 @@ type gapInfo struct { } func (a *trackingACKer) AddEvent(_ beat.Event, published bool) { - a.events.Inc() + a.events.Add(1) if published { a.addPublishedEvent() } else { @@ -148,7 +148,7 @@ func (a *trackingACKer) addDropEvent() { a.lst.Unlock() current.Unlock() - a.events.Dec() + a.events.Add(^uint32(0)) return } @@ -202,7 +202,7 @@ func (a *trackingACKer) ACKEvents(n int) { current.Unlock() } - a.events.Sub(uint32(total)) + a.events.Add(^uint32(total - 1)) a.fn(acked, total) } diff --git a/libbeat/common/atomic/atomic.go b/libbeat/common/atomic/atomic.go deleted file mode 100644 index 09e83614184f..000000000000 --- a/libbeat/common/atomic/atomic.go +++ /dev/null @@ -1,94 +0,0 @@ -// 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 atomic provides common primitive types with atomic accessors. -package atomic - -import a "sync/atomic" - -// Bool provides an atomic boolean type. -type Bool struct{ u Uint32 } - -// Int32 provides an atomic int32 type. -type Int32 struct{ value int32 } - -// Int64 provides an atomic int64 type. -type Int64 struct{ value int64 } - -// Uint32 provides an atomic uint32 type. -type Uint32 struct{ value uint32 } - -// Uint64 provides an atomic uint64 type. -type Uint64 struct{ value uint64 } - -func MakeBool(v bool) Bool { return Bool{MakeUint32(encBool(v))} } -func NewBool(v bool) *Bool { return &Bool{MakeUint32(encBool(v))} } -func (b *Bool) Load() bool { return b.u.Load() == 1 } -func (b *Bool) Store(v bool) { b.u.Store(encBool(v)) } -func (b *Bool) Swap(new bool) bool { return b.u.Swap(encBool(new)) == 1 } -func (b *Bool) CAS(old, new bool) bool { return b.u.CAS(encBool(old), encBool(new)) } - -func MakeInt32(v int32) Int32 { return Int32{v} } -func NewInt32(v int32) *Int32 { return &Int32{v} } -func (i *Int32) Load() int32 { return a.LoadInt32(&i.value) } -func (i *Int32) Store(v int32) { a.StoreInt32(&i.value, v) } -func (i *Int32) Swap(new int32) int32 { return a.SwapInt32(&i.value, new) } -func (i *Int32) Add(delta int32) int32 { return a.AddInt32(&i.value, delta) } -func (i *Int32) Sub(delta int32) int32 { return a.AddInt32(&i.value, -delta) } -func (i *Int32) Inc() int32 { return i.Add(1) } -func (i *Int32) Dec() int32 { return i.Add(-1) } -func (i *Int32) CAS(old, new int32) bool { return a.CompareAndSwapInt32(&i.value, old, new) } - -func MakeInt64(v int64) Int64 { return Int64{v} } -func NewInt64(v int64) *Int64 { return &Int64{v} } -func (i *Int64) Load() int64 { return a.LoadInt64(&i.value) } -func (i *Int64) Store(v int64) { a.StoreInt64(&i.value, v) } -func (i *Int64) Swap(new int64) int64 { return a.SwapInt64(&i.value, new) } -func (i *Int64) Add(delta int64) int64 { return a.AddInt64(&i.value, delta) } -func (i *Int64) Sub(delta int64) int64 { return a.AddInt64(&i.value, -delta) } -func (i *Int64) Inc() int64 { return i.Add(1) } -func (i *Int64) Dec() int64 { return i.Add(-1) } -func (i *Int64) CAS(old, new int64) bool { return a.CompareAndSwapInt64(&i.value, old, new) } - -func MakeUint32(v uint32) Uint32 { return Uint32{v} } -func NewUint32(v uint32) *Uint32 { return &Uint32{v} } -func (u *Uint32) Load() uint32 { return a.LoadUint32(&u.value) } -func (u *Uint32) Store(v uint32) { a.StoreUint32(&u.value, v) } -func (u *Uint32) Swap(new uint32) uint32 { return a.SwapUint32(&u.value, new) } -func (u *Uint32) Add(delta uint32) uint32 { return a.AddUint32(&u.value, delta) } -func (u *Uint32) Sub(delta uint32) uint32 { return a.AddUint32(&u.value, ^uint32(delta-1)) } -func (u *Uint32) Inc() uint32 { return u.Add(1) } -func (u *Uint32) Dec() uint32 { return u.Add(^uint32(0)) } -func (u *Uint32) CAS(old, new uint32) bool { return a.CompareAndSwapUint32(&u.value, old, new) } - -func MakeUint64(v uint64) Uint64 { return Uint64{v} } -func NewUint64(v uint64) *Uint64 { return &Uint64{v} } -func (u *Uint64) Load() uint64 { return a.LoadUint64(&u.value) } -func (u *Uint64) Store(v uint64) { a.StoreUint64(&u.value, v) } -func (u *Uint64) Swap(new uint64) uint64 { return a.SwapUint64(&u.value, new) } -func (u *Uint64) Add(delta uint64) uint64 { return a.AddUint64(&u.value, delta) } -func (u *Uint64) Sub(delta uint64) uint64 { return a.AddUint64(&u.value, ^uint64(delta-1)) } -func (u *Uint64) Inc() uint64 { return u.Add(1) } -func (u *Uint64) Dec() uint64 { return u.Add(^uint64(0)) } -func (u *Uint64) CAS(old, new uint64) bool { return a.CompareAndSwapUint64(&u.value, old, new) } - -func encBool(b bool) uint32 { - if b { - return 1 - } - return 0 -} diff --git a/libbeat/common/atomic/atomic32.go b/libbeat/common/atomic/atomic32.go deleted file mode 100644 index d811070a6cd7..000000000000 --- a/libbeat/common/atomic/atomic32.go +++ /dev/null @@ -1,50 +0,0 @@ -// 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. - -//go:build 386 || arm || mips || mipsle - -package atomic - -// atomic Uint/Int for 32bit systems - -// Uint provides an architecture specific atomic uint. -type Uint struct{ a Uint32 } - -// Int provides an architecture specific atomic uint. -type Int struct{ a Int32 } - -func MakeUint(v uint) Uint { return Uint{MakeUint32(uint32(v))} } -func NewUint(v uint) *Uint { return &Uint{MakeUint32(uint32(v))} } -func (u *Uint) Load() uint { return uint(u.a.Load()) } -func (u *Uint) Store(v uint) { u.a.Store(uint32(v)) } -func (u *Uint) Swap(new uint) uint { return uint(u.a.Swap(uint32(new))) } -func (u *Uint) Add(delta uint) uint { return uint(u.a.Add(uint32(delta))) } -func (u *Uint) Sub(delta uint) uint { return uint(u.a.Add(uint32(-delta))) } -func (u *Uint) Inc() uint { return uint(u.a.Inc()) } -func (u *Uint) Dec() uint { return uint(u.a.Dec()) } -func (u *Uint) CAS(old, new uint) bool { return u.a.CAS(uint32(old), uint32(new)) } - -func MakeInt(v int) Int { return Int{MakeInt32(int32(v))} } -func NewInt(v int) *Int { return &Int{MakeInt32(int32(v))} } -func (i *Int) Load() int { return int(i.a.Load()) } -func (i *Int) Store(v int) { i.a.Store(int32(v)) } -func (i *Int) Swap(new int) int { return int(i.a.Swap(int32(new))) } -func (i *Int) Add(delta int) int { return int(i.a.Add(int32(delta))) } -func (i *Int) Sub(delta int) int { return int(i.a.Add(int32(-delta))) } -func (i *Int) Inc() int { return int(i.a.Inc()) } -func (i *Int) Dec() int { return int(i.a.Dec()) } -func (i *Int) CAS(old, new int) bool { return i.a.CAS(int32(old), int32(new)) } diff --git a/libbeat/common/atomic/atomic64.go b/libbeat/common/atomic/atomic64.go deleted file mode 100644 index 3f3648e91ce1..000000000000 --- a/libbeat/common/atomic/atomic64.go +++ /dev/null @@ -1,50 +0,0 @@ -// 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. - -//go:build amd64 || arm64 || ppc64 || ppc64le || mips64 || mips64le || s390x - -package atomic - -// atomic Uint/Int for 64bit systems - -// Uint provides an architecture specific atomic uint. -type Uint struct{ a Uint64 } - -// Int provides an architecture specific atomic uint. -type Int struct{ a Int64 } - -func MakeUint(v uint) Uint { return Uint{MakeUint64(uint64(v))} } -func NewUint(v uint) *Uint { return &Uint{MakeUint64(uint64(v))} } -func (u *Uint) Load() uint { return uint(u.a.Load()) } -func (u *Uint) Store(v uint) { u.a.Store(uint64(v)) } -func (u *Uint) Swap(new uint) uint { return uint(u.a.Swap(uint64(new))) } -func (u *Uint) Add(delta uint) uint { return uint(u.a.Add(uint64(delta))) } -func (u *Uint) Sub(delta uint) uint { return uint(u.a.Add(uint64(-delta))) } -func (u *Uint) Inc() uint { return uint(u.a.Inc()) } -func (u *Uint) Dec() uint { return uint(u.a.Dec()) } -func (u *Uint) CAS(old, new uint) bool { return u.a.CAS(uint64(old), uint64(new)) } - -func MakeInt(v int) Int { return Int{MakeInt64(int64(v))} } -func NewInt(v int) *Int { return &Int{MakeInt64(int64(v))} } -func (i *Int) Load() int { return int(i.a.Load()) } -func (i *Int) Store(v int) { i.a.Store(int64(v)) } -func (i *Int) Swap(new int) int { return int(i.a.Swap(int64(new))) } -func (i *Int) Add(delta int) int { return int(i.a.Add(int64(delta))) } -func (i *Int) Sub(delta int) int { return int(i.a.Add(int64(-delta))) } -func (i *Int) Inc() int { return int(i.a.Inc()) } -func (i *Int) Dec() int { return int(i.a.Dec()) } -func (i *Int) CAS(old, new int) bool { return i.a.CAS(int64(old), int64(new)) } diff --git a/libbeat/common/atomic/atomic_test.go b/libbeat/common/atomic/atomic_test.go deleted file mode 100644 index f4df6fc4d89e..000000000000 --- a/libbeat/common/atomic/atomic_test.go +++ /dev/null @@ -1,273 +0,0 @@ -// 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 atomic - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestAtomicBool(t *testing.T) { - assert := assert.New(t) - - var b Bool - assert.False(b.Load(), "check zero value is false") - - b = MakeBool(true) - assert.True(b.Load(), "check value initializer with 'true' value") - - b.Store(false) - assert.False(b.Load(), "check store to false") - - old := b.Swap(true) - assert.False(old, "check old value of swap operation is 'false'") - assert.True(b.Load(), "check new value after swap is 'true'") - - old = b.Swap(false) - assert.True(old, "check old value of second swap operation is 'true'") - assert.False(b.Load(), "check new value after second swap is 'false'") - - ok := b.CAS(true, true) - assert.False(ok, "check CAS fails with wrong 'old' value") - assert.False(b.Load(), "check failed CAS did not change value 'false'") - - ok = b.CAS(false, true) - assert.True(ok, "check CAS succeeds with correct 'old' value") - assert.True(b.Load(), "check CAS did change value to 'true'") -} - -func TestAtomicInt32(t *testing.T) { - assert := assert.New(t) - check := func(expected, actual int32, msg string) { - assert.Equal(expected, actual, msg) - } - - var v Int32 - check(0, v.Load(), "check zero value") - - v = MakeInt32(23) - check(23, v.Load(), "check value initializer") - - v.Store(42) - check(42, v.Load(), "check store new value") - - new := v.Inc() - check(43, new, "check increment returns new value") - check(43, v.Load(), "check increment did store new value") - - new = v.Dec() - check(42, new, "check decrement returns new value") - check(42, v.Load(), "check decrement did store new value") - - new = v.Add(8) - check(50, new, "check add returns new value") - check(50, v.Load(), "check add did store new value") - - new = v.Sub(8) - check(42, new, "check sub returns new value") - check(42, v.Load(), "check sub did store new value") - - old := v.Swap(101) - check(42, old, "check swap returns old value") - check(101, v.Load(), "check swap stores new value") - - ok := v.CAS(0, 23) - assert.False(ok, "check CAS with wrong old value fails") - check(101, v.Load(), "check failed CAS did not change value") - - ok = v.CAS(101, 23) - assert.True(ok, "check CAS succeeds") - check(23, v.Load(), "check CAS did store new value") -} - -func TestAtomicInt64(t *testing.T) { - assert := assert.New(t) - check := func(expected, actual int64, msg string) { - assert.Equal(expected, actual, msg) - } - - var v Int64 - check(0, v.Load(), "check zero value") - - v = MakeInt64(23) - check(23, v.Load(), "check value initializer") - - v.Store(42) - check(42, v.Load(), "check store new value") - - new := v.Inc() - check(43, new, "check increment returns new value") - check(43, v.Load(), "check increment did store new value") - - new = v.Dec() - check(42, new, "check decrement returns new value") - check(42, v.Load(), "check decrement did store new value") - - new = v.Add(8) - check(50, new, "check add returns new value") - check(50, v.Load(), "check add did store new value") - - new = v.Sub(8) - check(42, new, "check sub returns new value") - check(42, v.Load(), "check sub did store new value") - - old := v.Swap(101) - check(42, old, "check swap returns old value") - check(101, v.Load(), "check swap stores new value") - - ok := v.CAS(0, 23) - assert.False(ok, "check CAS with wrong old value fails") - check(101, v.Load(), "check failed CAS did not change value") - - ok = v.CAS(101, 23) - assert.True(ok, "check CAS succeeds") - check(23, v.Load(), "check CAS did store new value") -} - -func TestAtomicUint32(t *testing.T) { - assert := assert.New(t) - check := func(expected, actual uint32, msg string) { - assert.Equal(expected, actual, msg) - } - - var v Uint32 - check(0, v.Load(), "check zero value") - - v = MakeUint32(23) - check(23, v.Load(), "check value initializer") - - v.Store(42) - check(42, v.Load(), "check store new value") - - new := v.Inc() - check(43, new, "check increment returns new value") - check(43, v.Load(), "check increment did store new value") - - new = v.Dec() - check(42, new, "check decrement returns new value") - check(42, v.Load(), "check decrement did store new value") - - new = v.Add(8) - check(50, new, "check add returns new value") - check(50, v.Load(), "check add did store new value") - - new = v.Sub(8) - check(42, new, "check sub returns new value") - check(42, v.Load(), "check sub did store new value") - - old := v.Swap(101) - check(42, old, "check swap returns old value") - check(101, v.Load(), "check swap stores new value") - - ok := v.CAS(0, 23) - assert.False(ok, "check CAS with wrong old value fails") - check(101, v.Load(), "check failed CAS did not change value") - - ok = v.CAS(101, 23) - assert.True(ok, "check CAS succeeds") - check(23, v.Load(), "check CAS did store new value") -} - -func TestAtomicUint64(t *testing.T) { - assert := assert.New(t) - check := func(expected, actual uint64, msg string) { - assert.Equal(expected, actual, msg) - } - - var v Uint64 - check(0, v.Load(), "check zero value") - - v = MakeUint64(23) - check(23, v.Load(), "check value initializer") - - v.Store(42) - check(42, v.Load(), "check store new value") - - new := v.Inc() - check(43, new, "check increment returns new value") - check(43, v.Load(), "check increment did store new value") - - new = v.Dec() - check(42, new, "check decrement returns new value") - check(42, v.Load(), "check decrement did store new value") - - new = v.Add(8) - check(50, new, "check add returns new value") - check(50, v.Load(), "check add did store new value") - - new = v.Sub(8) - check(42, new, "check sub returns new value") - check(42, v.Load(), "check sub did store new value") - - old := v.Swap(101) - check(42, old, "check swap returns old value") - check(101, v.Load(), "check swap stores new value") - - ok := v.CAS(0, 23) - assert.False(ok, "check CAS with wrong old value fails") - check(101, v.Load(), "check failed CAS did not change value") - - ok = v.CAS(101, 23) - assert.True(ok, "check CAS succeeds") - check(23, v.Load(), "check CAS did store new value") -} - -func TestAtomicUint(t *testing.T) { - assert := assert.New(t) - check := func(expected, actual uint, msg string) { - assert.Equal(expected, actual, msg) - } - - var v Uint - check(0, v.Load(), "check zero value") - - v = MakeUint(23) - check(23, v.Load(), "check value initializer") - - v.Store(42) - check(42, v.Load(), "check store new value") - - new := v.Inc() - check(43, new, "check increment returns new value") - check(43, v.Load(), "check increment did store new value") - - new = v.Dec() - check(42, new, "check decrement returns new value") - check(42, v.Load(), "check decrement did store new value") - - new = v.Add(8) - check(50, new, "check add returns new value") - check(50, v.Load(), "check add did store new value") - - new = v.Sub(8) - check(42, new, "check sub returns new value") - check(42, v.Load(), "check sub did store new value") - - old := v.Swap(101) - check(42, old, "check swap returns old value") - check(101, v.Load(), "check swap stores new value") - - ok := v.CAS(0, 23) - assert.False(ok, "check CAS with wrong old value fails") - check(101, v.Load(), "check failed CAS did not change value") - - ok = v.CAS(101, 23) - assert.True(ok, "check CAS succeeds") - check(23, v.Load(), "check CAS did store new value") -} diff --git a/libbeat/common/kafka/sasl.go b/libbeat/common/kafka/sasl.go index 9a6b3314b8b2..ca9df078ebcd 100644 --- a/libbeat/common/kafka/sasl.go +++ b/libbeat/common/kafka/sasl.go @@ -21,7 +21,7 @@ import ( "fmt" "strings" - "github.com/Shopify/sarama" + "github.com/elastic/sarama" ) type SaslConfig struct { diff --git a/libbeat/common/kafka/version.go b/libbeat/common/kafka/version.go index 3df44b86216a..c8f0cca99fba 100644 --- a/libbeat/common/kafka/version.go +++ b/libbeat/common/kafka/version.go @@ -20,7 +20,7 @@ package kafka import ( "fmt" - "github.com/Shopify/sarama" + "github.com/elastic/sarama" ) // Version is a kafka version @@ -31,6 +31,8 @@ var ( // We also allow versions to be specified as a prefix, e.g. "1", // understood as referencing the most recent version starting with "1". // truncatedKafkaVersions stores a lookup of the abbreviations we accept. + + //Ref for version mapping - https://kafka.apache.org/downloads truncatedKafkaVersions = map[string]sarama.KafkaVersion{ "0.8.2": sarama.V0_8_2_2, "0.8": sarama.V0_8_2_2, @@ -57,7 +59,16 @@ var ( "2.4": sarama.V2_4_0_0, "2.5": sarama.V2_5_0_0, "2.6": sarama.V2_6_0_0, + "2.7": sarama.V2_7_0_0, + "2.8": sarama.V2_8_0_0, "2": sarama.V2_6_0_0, + + "3": sarama.V3_1_1_0, + "3.2": sarama.V3_2_0_0, + "3.3": sarama.V3_3_1_0, + "3.4": sarama.V3_4_0_0, + "3.5": sarama.V3_5_1_0, + "3.6": sarama.V3_6_0_0, } ) diff --git a/libbeat/common/kafka/version_test.go b/libbeat/common/kafka/version_test.go index 19d5b04ad233..ae0f0a385e05 100644 --- a/libbeat/common/kafka/version_test.go +++ b/libbeat/common/kafka/version_test.go @@ -20,7 +20,7 @@ package kafka import ( "testing" - "github.com/Shopify/sarama" + "github.com/elastic/sarama" ) func TestVersionGet(t *testing.T) { @@ -62,7 +62,7 @@ func TestSaramaUpdate(t *testing.T) { // If any of these versions are considered valid by our parsing code, // it means someone updated sarama without updating the parsing code // for the new version. Gently remind them. - flagVersions := []Version{"2.8.1", "2.9.0"} + flagVersions := []Version{"3.7.0", "3.8.0"} for _, v := range flagVersions { if _, ok := v.Get(); ok { t.Fatalf( @@ -71,7 +71,7 @@ func TestSaramaUpdate(t *testing.T) { "- Update truncatedKafkaVersions in libbeat/common/kafka/version.go\n"+ "- Update the documentation to list the latest version:\n"+ " * libbeat/outputs/kafka/docs/kafka.asciidoc\n"+ - " * filebeat/docs/inputs/inputs-kafka.asciidoc\n"+ + " * filebeat/docs/inputs/input-kafka.asciidoc\n"+ "- Update TestSaramaUpdate in libbeat/common/kafka/version_test.go\n", v) diff --git a/libbeat/common/transport/kerberos/client.go b/libbeat/common/transport/kerberos/client.go index 1cbfb0a43386..3561f235bd06 100644 --- a/libbeat/common/transport/kerberos/client.go +++ b/libbeat/common/transport/kerberos/client.go @@ -21,10 +21,10 @@ import ( "fmt" "net/http" - krbclient "gopkg.in/jcmturner/gokrb5.v7/client" - krbconfig "gopkg.in/jcmturner/gokrb5.v7/config" - "gopkg.in/jcmturner/gokrb5.v7/keytab" - "gopkg.in/jcmturner/gokrb5.v7/spnego" + krbclient "github.com/jcmturner/gokrb5/v8/client" + krbconfig "github.com/jcmturner/gokrb5/v8/config" + "github.com/jcmturner/gokrb5/v8/keytab" + "github.com/jcmturner/gokrb5/v8/spnego" ) type Client struct { @@ -35,18 +35,18 @@ func NewClient(config *Config, httpClient *http.Client, esurl string) (*Client, var krbClient *krbclient.Client krbConf, err := krbconfig.Load(config.ConfigPath) if err != nil { - return nil, fmt.Errorf("error creating Kerberos client: %+v", err) + return nil, fmt.Errorf("error creating Kerberos client: %w", err) } switch config.AuthType { case authKeytab: kTab, err := keytab.Load(config.KeyTabPath) if err != nil { - return nil, fmt.Errorf("cannot load keytab file %s: %+v", config.KeyTabPath, err) + return nil, fmt.Errorf("cannot load keytab file %s: %w", config.KeyTabPath, err) } - krbClient = krbclient.NewClientWithKeytab(config.Username, config.Realm, kTab, krbConf) + krbClient = krbclient.NewWithKeytab(config.Username, config.Realm, kTab, krbConf) case authPassword: - krbClient = krbclient.NewClientWithPassword(config.Username, config.Realm, config.Password, krbConf) + krbClient = krbclient.NewWithPassword(config.Username, config.Realm, config.Password, krbConf) default: return nil, InvalidAuthType } diff --git a/libbeat/conditions/conditions_test.go b/libbeat/conditions/conditions_test.go index be74f0a7caa9..8abbb0694e73 100644 --- a/libbeat/conditions/conditions_test.go +++ b/libbeat/conditions/conditions_test.go @@ -105,6 +105,29 @@ var httpResponseTestEvent = &beat.Event{ }, } +var httpResponseEventIPList = &beat.Event{ + Timestamp: time.Now(), + Fields: mapstr.M{ + "@timestamp": "2024-12-05T09:51:23.642Z", + "ecs": mapstr.M{ + "version": "8.11.0", + }, + "host": mapstr.M{ + "hostname": "testhost", + "os": mapstr.M{ + "type": "linux", + "family": "debian", + "version": "11 (bullseye)", + "platform": "debian", + }, + "ip": []string{ + "10.1.0.55", + "fe80::4001:aff:fe9a:55", + }, + }, + }, +} + func testConfig(t *testing.T, expected bool, event *beat.Event, config *Config) { t.Helper() logp.TestingSetup() diff --git a/libbeat/conditions/network.go b/libbeat/conditions/network.go index 76ab2d08423c..25c5fb86e701 100644 --- a/libbeat/conditions/network.go +++ b/libbeat/conditions/network.go @@ -20,6 +20,7 @@ package conditions import ( "fmt" "net" + "slices" "strings" "github.com/elastic/elastic-agent-libs/logp" @@ -94,6 +95,24 @@ func (m multiNetworkMatcher) String() string { return strings.Join(names, " OR ") } +func makeMatcher(network string) (networkMatcher, error) { + m := singleNetworkMatcher{name: network, netContainsFunc: namedNetworks[network]} + if m.netContainsFunc == nil { + subnet, err := parseCIDR(network) + if err != nil { + return nil, err + } + m.netContainsFunc = subnet.Contains + } + return m, nil +} + +func invalidTypeError(field string, value interface{}) error { + return fmt.Errorf("network condition attempted to set "+ + "'%v' -> '%v' and encountered unexpected type '%T', only "+ + "strings or []strings are allowed", field, value, value) +} + // NewNetworkCondition builds a new Network using the given configuration. func NewNetworkCondition(fields map[string]interface{}) (*Network, error) { cond := &Network{ @@ -101,24 +120,6 @@ func NewNetworkCondition(fields map[string]interface{}) (*Network, error) { log: logp.NewLogger(logName), } - makeMatcher := func(network string) (networkMatcher, error) { - m := singleNetworkMatcher{name: network, netContainsFunc: namedNetworks[network]} - if m.netContainsFunc == nil { - subnet, err := parseCIDR(network) - if err != nil { - return nil, err - } - m.netContainsFunc = subnet.Contains - } - return m, nil - } - - invalidTypeError := func(field string, value interface{}) error { - return fmt.Errorf("network condition attempted to set "+ - "'%v' -> '%v' and encountered unexpected type '%T', only "+ - "strings or []strings are allowed", field, value, value) - } - for field, value := range mapstr.M(fields).Flatten() { switch v := value.(type) { case string: @@ -157,15 +158,17 @@ func (c *Network) Check(event ValuesMap) bool { return false } - ip := extractIP(value) - if ip == nil { + ipList := extractIP(value) + if len(ipList) == 0 { c.log.Debugf("Invalid IP address in field=%v for network condition", field) return false } - - if !network.Contains(ip) { + // match on an "any" basis when we find multiple IPs in the event; + // if the network matcher returns true for any seen IP, consider it a match + if !slices.ContainsFunc(ipList, network.Contains) { return false } + } return true @@ -202,12 +205,20 @@ func parseCIDR(value string) (*net.IPNet, error) { // extractIP return an IP address if unk is an IP address string or a net.IP. // Otherwise it returns nil. -func extractIP(unk interface{}) net.IP { +func extractIP(unk interface{}) []net.IP { switch v := unk.(type) { case string: - return net.ParseIP(v) - case net.IP: + return []net.IP{net.ParseIP(v)} + case []net.IP: return v + case net.IP: + return []net.IP{v} + case []string: + parsed := make([]net.IP, len(v)) + for i, rawIP := range v { + parsed[i] = net.ParseIP(rawIP) + } + return parsed default: return nil } diff --git a/libbeat/conditions/network_test.go b/libbeat/conditions/network_test.go index b79568098e42..71ab0918e675 100644 --- a/libbeat/conditions/network_test.go +++ b/libbeat/conditions/network_test.go @@ -79,6 +79,26 @@ network: testYAMLConfig(t, true, evt, yaml) }) + + t.Run("IP list", func(t *testing.T) { + const yaml = ` +network: + ip: + client: [loopback] + server: [loopback] + host: 10.10.0.0/8 +` + + evt := &beat.Event{Fields: mapstr.M{ + "ip": mapstr.M{ + "client": "127.0.0.1", + "server": "127.0.0.1", + "host": []string{"10.10.0.83", "fe80::4001:aff:fe9a:53"}, + }, + }} + + testYAMLConfig(t, true, evt, yaml) + }) } func TestNetworkCreate(t *testing.T) { @@ -166,6 +186,22 @@ func TestNetworkCheck(t *testing.T) { }) }) + t.Run("multiple IPs field single match", func(t *testing.T) { + testConfig(t, true, httpResponseEventIPList, &Config{ + Network: map[string]interface{}{ + "host.ip": "10.1.0.0/24", + }, + }) + }) + + t.Run("multiple IPs field negative match", func(t *testing.T) { + testConfig(t, false, httpResponseEventIPList, &Config{ + Network: map[string]interface{}{ + "host.ip": "127.0.0.0/24", + }, + }) + }) + // Multiple conditions are treated as an implicit AND. t.Run("multiple fields negative match", func(t *testing.T) { testConfig(t, false, httpResponseTestEvent, &Config{ @@ -191,6 +227,22 @@ func TestNetworkCheck(t *testing.T) { }, }) }) + + t.Run("multiple values multiple IPs match", func(t *testing.T) { + testConfig(t, true, httpResponseEventIPList, &Config{ + Network: map[string]interface{}{ + "host.ip": []interface{}{"10.1.0.0/24", "127.0.0.0/24"}, + }, + }) + }) + + t.Run("multiple values multiple IPs no match", func(t *testing.T) { + testConfig(t, false, httpResponseEventIPList, &Config{ + Network: map[string]interface{}{ + "host.ip": []interface{}{"12.1.0.0/24", "127.0.0.0/24"}, + }, + }) + }) } func TestNetworkPrivate(t *testing.T) { diff --git a/libbeat/docs/command-reference.asciidoc b/libbeat/docs/command-reference.asciidoc index 91daaf097be6..4766152f39fd 100644 --- a/libbeat/docs/command-reference.asciidoc +++ b/libbeat/docs/command-reference.asciidoc @@ -103,9 +103,6 @@ more information, see https://www.elastic.co/subscriptions and [options="header"] |======================= |Commands | -ifeval::["{beatname_lc}"=="functionbeat"] -|<> | {deploy-command-short-desc}. -endif::[] ifdef::apm-server[] |<> |{apikey-command-short-desc}. endif::[] @@ -114,10 +111,6 @@ endif::[] ifndef::serverless[] |<> |{keystore-command-short-desc}. endif::[] -ifeval::["{beatname_lc}"=="functionbeat"] -|<> |{package-command-short-desc}. -|<> |{remove-command-short-desc}. -endif::[] ifdef::has_modules_command[] |<> |{modules-command-short-desc}. endif::[] @@ -126,9 +119,6 @@ ifndef::serverless[] endif::[] |<> |{setup-command-short-desc}. |<> |{test-command-short-desc}. -ifeval::["{beatname_lc}"=="functionbeat"] -|<> |{update-command-short-desc}. -endif::[] |<> |{version-command-short-desc}. |======================= @@ -232,39 +222,6 @@ For more information, see <>. endif::[] -ifeval::["{beatname_lc}"=="functionbeat"] -[[deploy-command]] -==== `deploy` command - -{deploy-command-short-desc}. Before deploying functions, make sure the user has -the credentials required by your cloud service provider. - -*SYNOPSIS* - -["source","sh",subs="attributes"] ----- -{beatname_lc} deploy FUNCTION_NAME [FLAGS] ----- - -*`FUNCTION_NAME`*:: -Specifies the name of the function to deploy. - -*FLAGS* - -*`-h, --help`*:: -Shows help for the `deploy` command. - -{global-flags} - -*EXAMPLES* - -["source","sh",subs="attributes"] ------ -{beatname_lc} deploy cloudwatch -{beatname_lc} deploy sqs ------ -endif::[] - [[export-command]] ==== `export` command @@ -521,68 +478,6 @@ See <> for more examples. endif::[] -ifeval::["{beatname_lc}"=="functionbeat"] -[[package-command]] -==== `package` command - -{package-command-short-desc}. - -*SYNOPSIS* - -["source","sh",subs="attributes"] ----- -{beatname_lc} package [FLAGS] ----- - -*FLAGS* - -*`-h, --help`*:: -Shows help for the `package` command. - -*`-o, --output`*:: -Specifies the full path pattern to use when creating the packages. - -{global-flags} - -*EXAMPLES* - -["source","sh",subs="attributes"] ------ -{beatname_lc} package --output /path/to/folder/package-{{.Provider}}.zip ------ - -[[remove-command]] -==== `remove` command - -{remove-command-short-desc}. Before removing functions, make sure the user has -the credentials required by your cloud service provider. - -*SYNOPSIS* - -["source","sh",subs="attributes"] ----- -{beatname_lc} remove FUNCTION_NAME [FLAGS] ----- - -*`FUNCTION_NAME`*:: -Specifies the name of the function to remove. - -*FLAGS* - -*`-h, --help`*:: -Shows help for the `remove` command. - -{global-flags} - -*EXAMPLES* - -["source","sh",subs="attributes"] ------ -{beatname_lc} remove cloudwatch -{beatname_lc} remove sqs ------ -endif::[] - ifdef::has_modules_command[] [[modules-command]] ==== `modules` command @@ -748,7 +643,7 @@ endif::[] *`--system.hostfs MOUNT_POINT`*:: -Specifies the mount point of the host's filesystem for use in monitoring a host. +Specifies the mount point of the host's filesystem for use in monitoring a host. This flag is depricated, and an alternate hostfs should be specified via the `hostfs` module config value. @@ -961,39 +856,6 @@ ifeval::["{beatname_lc}"=="metricbeat"] ----- endif::[] -ifeval::["{beatname_lc}"=="functionbeat"] -[[update-command]] -==== `update` command - -{update-command-short-desc}. Before updating functions, make sure the user has -the credentials required by your cloud service provider. - -*SYNOPSIS* - -["source","sh",subs="attributes"] ----- -{beatname_lc} update FUNCTION_NAME [FLAGS] ----- - -*`FUNCTION_NAME`*:: -Specifies the name of the function to update. - -*FLAGS* - -*`-h, --help`*:: -Shows help for the `update` command. - -{global-flags} - -*EXAMPLES* - -["source","sh",subs="attributes"] ------ -{beatname_lc} update cloudwatch -{beatname_lc} update sqs ------ -endif::[] - [[version-command]] ==== `version` command diff --git a/libbeat/docs/overview.asciidoc b/libbeat/docs/overview.asciidoc index c76aa8558e54..d42f3e904eb3 100644 --- a/libbeat/docs/overview.asciidoc +++ b/libbeat/docs/overview.asciidoc @@ -9,7 +9,6 @@ for capturing: [horizontal] Audit data:: https://www.elastic.co/products/beats/auditbeat[Auditbeat] Log files and journals:: https://www.elastic.co/products/beats/filebeat[Filebeat] -Cloud data:: https://www.elastic.co/products/beats/functionbeat[Functionbeat] Availability:: https://www.elastic.co/products/beats/heartbeat[Heartbeat] Metrics:: https://www.elastic.co/products/beats/metricbeat[Metricbeat] Network traffic:: https://www.elastic.co/products/beats/packetbeat[Packetbeat] diff --git a/libbeat/docs/processors-using.asciidoc b/libbeat/docs/processors-using.asciidoc index dd91ea8d5db6..a029f5f2ea8b 100644 --- a/libbeat/docs/processors-using.asciidoc +++ b/libbeat/docs/processors-using.asciidoc @@ -311,10 +311,15 @@ range: [[condition-network]] ===== `network` -The `network` condition checks if the field is in a certain IP network range. -Both IPv4 and IPv6 addresses are supported. The network range may be specified -using CIDR notation, like "192.0.2.0/24" or "2001:db8::/32", or by using one of -these named ranges: +The `network` condition checks whether a field's value falls within a specified +IP network range. If multiple fields are provided, each field value must match +its corresponding network range. You can specify multiple network ranges for a +single field, and a match occurs if any one of the ranges matches. If the field +value is an array of IPs, it will match if any of the IPs fall within any of the +given ranges. Both IPv4 and IPv6 addresses are supported. + +The network range may be specified using CIDR notation, like "192.0.2.0/24" or +"2001:db8::/32", or by using one of these named ranges: - `loopback` - Matches loopback addresses in the range of `127.0.0.0/8` or `::1/128`. diff --git a/libbeat/docs/release.asciidoc b/libbeat/docs/release.asciidoc index f9b46d9120ca..eb2d9495b5ad 100644 --- a/libbeat/docs/release.asciidoc +++ b/libbeat/docs/release.asciidoc @@ -8,6 +8,9 @@ This section summarizes the changes in each release. Also read <> for more detail about changes that affect upgrade. +* <> +* <> +* <> * <> * <> * <> diff --git a/libbeat/esleg/eslegclient/enc.go b/libbeat/esleg/eslegclient/enc.go index 27e409f9172e..79e6c430a383 100644 --- a/libbeat/esleg/eslegclient/enc.go +++ b/libbeat/esleg/eslegclient/enc.go @@ -19,11 +19,13 @@ package eslegclient import ( "bytes" - "compress/gzip" + "io" "net/http" "time" + "github.com/klauspost/compress/gzip" + "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/beats/v7/libbeat/outputs/codec" "github.com/elastic/elastic-agent-libs/mapstr" diff --git a/libbeat/idxmgmt/index_support.go b/libbeat/idxmgmt/index_support.go index 4526d916c359..57816b3625c5 100644 --- a/libbeat/idxmgmt/index_support.go +++ b/libbeat/idxmgmt/index_support.go @@ -21,10 +21,10 @@ import ( "errors" "fmt" "strings" + "sync/atomic" "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/beats/v7/libbeat/beat/events" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/libbeat/idxmgmt/lifecycle" "github.com/elastic/beats/v7/libbeat/outputs" "github.com/elastic/beats/v7/libbeat/outputs/outil" @@ -314,7 +314,7 @@ func (m *indexManager) setupWithILM() (bool, error) { } if withILM { // mark ILM as enabled in indexState - m.support.st.withILM.CAS(false, true) + m.support.st.withILM.CompareAndSwap(false, true) } } return withILM, nil diff --git a/libbeat/internal/testutil/util.go b/libbeat/internal/testutil/util.go index 51a811587e58..a44becb70081 100644 --- a/libbeat/internal/testutil/util.go +++ b/libbeat/internal/testutil/util.go @@ -21,9 +21,13 @@ package testutil import ( "flag" + "fmt" "math/rand" "testing" "time" + + "github.com/elastic/beats/v7/libbeat/beat" + "github.com/elastic/elastic-agent-libs/mapstr" ) var ( @@ -37,5 +41,32 @@ func SeedPRNG(t *testing.T) { } t.Logf("reproduce test with `go test ... -seed %v`", seed) - rand.Seed(seed) + rand.New(rand.NewSource(seed)) +} + +func GenerateEvents(numEvents, fieldsPerLevel, depth int) []beat.Event { + events := make([]beat.Event, numEvents) + for i := 0; i < numEvents; i++ { + event := &beat.Event{Fields: mapstr.M{}} + generateFields(event, fieldsPerLevel, depth) + events[i] = *event + } + return events +} + +func generateFields(event *beat.Event, fieldsPerLevel, depth int) { + if depth == 0 { + return + } + + for j := 1; j <= fieldsPerLevel; j++ { + var key string + for d := 1; d <= depth; d++ { + key += fmt.Sprintf("level%dfield%d", d, j) + key += "." + } + event.Fields.Put(key, "value") + key = "" + } + } diff --git a/libbeat/management/agent.go b/libbeat/management/agent.go index 84f5a1e9f6b1..cd14f8cb9690 100644 --- a/libbeat/management/agent.go +++ b/libbeat/management/agent.go @@ -17,17 +17,15 @@ package management -import ( - "github.com/elastic/beats/v7/libbeat/common/atomic" -) +import "sync/atomic" var ( // underAgent is set to true with this beat is being ran under the elastic-agent - underAgent = atomic.MakeBool(false) + underAgent atomic.Bool // underAgentTrace is set to true when the elastic-agent has placed this beat into // trace mode (which enables logging of published events) - underAgentTrace = atomic.MakeBool(false) + underAgentTrace atomic.Bool ) // SetUnderAgent sets that the processing pipeline is being ran under the elastic-agent. diff --git a/libbeat/outputs/elasticsearch/client_proxy_test.go b/libbeat/outputs/elasticsearch/client_proxy_test.go index bd6739c3bf02..b0cef2824870 100644 --- a/libbeat/outputs/elasticsearch/client_proxy_test.go +++ b/libbeat/outputs/elasticsearch/client_proxy_test.go @@ -29,12 +29,12 @@ import ( "net/url" "os" "os/exec" + "sync/atomic" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/libbeat/esleg/eslegclient" "github.com/elastic/beats/v7/libbeat/outputs/outil" "github.com/elastic/elastic-agent-libs/transport/httpcommon" @@ -224,17 +224,17 @@ type serverState struct { serverURL string proxyURL string - _serverRequestCount atomic.Int // Requests directly to the server - _proxyRequestCount atomic.Int // Requests via the proxy + _serverRequestCount atomic.Int64 // Requests directly to the server + _proxyRequestCount atomic.Int64 // Requests via the proxy } // Convenience functions to unwrap the atomic primitives -func (s serverState) serverRequestCount() int { - return s._serverRequestCount.Load() +func (s *serverState) serverRequestCount() int { + return int(s._serverRequestCount.Load()) } -func (s serverState) proxyRequestCount() int { - return s._proxyRequestCount.Load() +func (s *serverState) proxyRequestCount() int { + return int(s._proxyRequestCount.Load()) } // startServers starts endpoints representing a backend server and a proxy, @@ -246,13 +246,13 @@ func startServers(t *testing.T) (*serverState, func()) { http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, headerTestValue, r.Header.Get(headerTestField)) fmt.Fprintln(w, "Hello, client") - state._serverRequestCount.Inc() + state._serverRequestCount.Add(1) })) proxy := httptest.NewServer( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, headerTestValue, r.Header.Get(headerTestField)) fmt.Fprintln(w, "Hello, client") - state._proxyRequestCount.Inc() + state._proxyRequestCount.Add(1) })) state.serverURL = server.URL state.proxyURL = proxy.URL diff --git a/libbeat/outputs/elasticsearch/client_test.go b/libbeat/outputs/elasticsearch/client_test.go index abda06a02ee1..f6322383cb5a 100644 --- a/libbeat/outputs/elasticsearch/client_test.go +++ b/libbeat/outputs/elasticsearch/client_test.go @@ -40,6 +40,7 @@ import ( "github.com/elastic/beats/v7/libbeat/common" "github.com/elastic/beats/v7/libbeat/esleg/eslegclient" "github.com/elastic/beats/v7/libbeat/idxmgmt" + "github.com/elastic/beats/v7/libbeat/internal/testutil" "github.com/elastic/beats/v7/libbeat/outputs" "github.com/elastic/beats/v7/libbeat/outputs/outest" "github.com/elastic/beats/v7/libbeat/outputs/outil" @@ -713,6 +714,83 @@ func BenchmarkCollectPublishFailAll(b *testing.B) { } } +func BenchmarkPublish(b *testing.B) { + tests := []struct { + Name string + Events []beat.Event + }{ + { + Name: "5 events", + Events: testutil.GenerateEvents(50, 5, 3), + }, + { + Name: "50 events", + Events: testutil.GenerateEvents(500, 5, 3), + }, + { + Name: "500 events", + Events: testutil.GenerateEvents(500, 5, 3), + }, + } + + levels := []int{1, 4, 7, 9} + + requestCount := 0 + + // start a mock HTTP server + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(b, "testing value", r.Header.Get("X-Test")) + // from the documentation: https://golang.org/pkg/net/http/ + // For incoming requests, the Host header is promoted to the + // Request.Host field and removed from the Header map. + assert.Equal(b, "myhost.local", r.Host) + + var response string + if r.URL.Path == "/" { + response = `{ "version": { "number": "7.6.0" } }` + } else { + response = `{"items":[{"index":{}},{"index":{}},{"index":{}}]}` + + } + fmt.Fprintln(w, response) + requestCount++ + })) + defer ts.Close() + + // Indexing to _bulk api + for _, test := range tests { + for _, l := range levels { + b.Run(fmt.Sprintf("%s with compression level %d", test.Name, l), func(b *testing.B) { + client, err := NewClient( + clientSettings{ + connection: eslegclient.ConnectionSettings{ + URL: ts.URL, + Headers: map[string]string{ + "host": "myhost.local", + "X-Test": "testing value", + }, + CompressionLevel: l, + }, + }, + + nil, + ) + assert.NoError(b, err) + batch := encodeBatch(client, outest.NewBatch(test.Events...)) + + // It uses gzip encoder internally for encoding data + b.ResetTimer() + for i := 0; i < b.N; i++ { + err := client.Publish(context.Background(), batch) + assert.NoError(b, err) + } + }) + + } + } + +} + func TestClientWithHeaders(t *testing.T) { requestCount := 0 // start a mock HTTP server diff --git a/libbeat/outputs/kafka/client.go b/libbeat/outputs/kafka/client.go index 1780f1392b31..76d5f9b8a78c 100644 --- a/libbeat/outputs/kafka/client.go +++ b/libbeat/outputs/kafka/client.go @@ -26,9 +26,10 @@ import ( "sync/atomic" "time" - "github.com/Shopify/sarama" "github.com/eapache/go-resiliency/breaker" + "github.com/elastic/sarama" + "github.com/elastic/beats/v7/libbeat/common/fmtstr" "github.com/elastic/beats/v7/libbeat/outputs" "github.com/elastic/beats/v7/libbeat/outputs/codec" @@ -113,7 +114,7 @@ func newKafkaClient( return c, nil } -func (c *client) Connect() error { +func (c *client) Connect(_ context.Context) error { c.mux.Lock() defer c.mux.Unlock() @@ -257,7 +258,11 @@ func (c *client) successWorker(ch <-chan *sarama.ProducerMessage) { defer c.log.Debug("Stop kafka ack worker") for libMsg := range ch { - msg := libMsg.Metadata.(*message) + msg, ok := libMsg.Metadata.(*message) + if !ok { + c.log.Debug("Failed to assert libMsg.Metadata to *message") + return + } msg.ref.done() } } @@ -268,7 +273,11 @@ func (c *client) errorWorker(ch <-chan *sarama.ProducerError) { defer c.log.Debug("Stop kafka error handler") for errMsg := range ch { - msg := errMsg.Msg.Metadata.(*message) + msg, ok := errMsg.Msg.Metadata.(*message) + if !ok { + c.log.Debug("Failed to assert libMsg.Metadata to *message") + return + } msg.ref.fail(msg, errMsg.Err) if errors.Is(errMsg.Err, breaker.ErrBreakerOpen) { diff --git a/libbeat/outputs/kafka/config.go b/libbeat/outputs/kafka/config.go index c7dc74ee9934..9300e385aa15 100644 --- a/libbeat/outputs/kafka/config.go +++ b/libbeat/outputs/kafka/config.go @@ -25,8 +25,6 @@ import ( "strings" "time" - "github.com/Shopify/sarama" - "github.com/elastic/beats/v7/libbeat/common/cfgwarn" "github.com/elastic/beats/v7/libbeat/common/fmtstr" "github.com/elastic/beats/v7/libbeat/common/kafka" @@ -38,6 +36,7 @@ import ( "github.com/elastic/elastic-agent-libs/monitoring" "github.com/elastic/elastic-agent-libs/monitoring/adapter" "github.com/elastic/elastic-agent-libs/transport/tlscommon" + "github.com/elastic/sarama" ) type backoffConfig struct { @@ -136,7 +135,7 @@ func defaultConfig() kafkaConfig { BrokerTimeout: 10 * time.Second, Compression: "gzip", CompressionLevel: 4, - Version: kafka.Version("1.0.0"), + Version: kafka.Version("2.1.0"), MaxRetries: 3, Headers: nil, Backoff: backoffConfig{ diff --git a/libbeat/outputs/kafka/docs/kafka.asciidoc b/libbeat/outputs/kafka/docs/kafka.asciidoc index 9907cad61c29..383b724d4042 100644 --- a/libbeat/outputs/kafka/docs/kafka.asciidoc +++ b/libbeat/outputs/kafka/docs/kafka.asciidoc @@ -44,7 +44,7 @@ endif::[] ==== Compatibility This output can connect to Kafka version 0.8.2.0 and later. Older versions -might work as well, but are not supported. +might work as well, but are not supported. When using Kafka 4.0 and newer, the version must be set to at least `"2.1.0"` ==== Configuration options @@ -69,7 +69,7 @@ The cluster metadata contain the actual Kafka brokers events are published to. ===== `version` -Kafka protocol version that {beatname_uc} will request when connecting. Defaults to 1.0.0. +Kafka protocol version that {beatname_uc} will request when connecting. Defaults to 2.1.0. When using Kafka 4.0 and newer, the version must be set to at least `"2.1.0"` Valid values are all kafka releases in between `0.8.2.0` and `2.6.0`. diff --git a/libbeat/outputs/kafka/kafka.go b/libbeat/outputs/kafka/kafka.go index e8c0d75aa4d6..02dadafd9723 100644 --- a/libbeat/outputs/kafka/kafka.go +++ b/libbeat/outputs/kafka/kafka.go @@ -20,14 +20,13 @@ package kafka import ( "fmt" - "github.com/Shopify/sarama" - "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/beats/v7/libbeat/outputs" "github.com/elastic/beats/v7/libbeat/outputs/codec" "github.com/elastic/beats/v7/libbeat/outputs/outil" "github.com/elastic/elastic-agent-libs/config" "github.com/elastic/elastic-agent-libs/logp" + "github.com/elastic/sarama" ) const ( diff --git a/libbeat/outputs/kafka/kafka_integration_test.go b/libbeat/outputs/kafka/kafka_integration_test.go index e9abc559774d..e0f42e2667aa 100644 --- a/libbeat/outputs/kafka/kafka_integration_test.go +++ b/libbeat/outputs/kafka/kafka_integration_test.go @@ -30,9 +30,10 @@ import ( "testing" "time" - "github.com/Shopify/sarama" "github.com/stretchr/testify/assert" + "github.com/elastic/sarama" + "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/beats/v7/libbeat/common/fmtstr" "github.com/elastic/beats/v7/libbeat/outputs" @@ -280,7 +281,7 @@ func TestKafkaPublish(t *testing.T) { output, ok := grp.Clients[0].(*client) assert.True(t, ok, "grp.Clients[0] didn't contain a ptr to client") - if err := output.Connect(); err != nil { + if err := output.Connect(context.Background()); err != nil { t.Fatal(err) } assert.Equal(t, output.index, "testbeat") diff --git a/libbeat/outputs/kafka/log.go b/libbeat/outputs/kafka/log.go index 2f7bfa948483..1745bf2000fa 100644 --- a/libbeat/outputs/kafka/log.go +++ b/libbeat/outputs/kafka/log.go @@ -18,9 +18,8 @@ package kafka import ( - "github.com/Shopify/sarama" - "github.com/elastic/elastic-agent-libs/logp" + "github.com/elastic/sarama" ) type kafkaLogger struct { diff --git a/libbeat/outputs/kafka/message.go b/libbeat/outputs/kafka/message.go index bf77f32ac25d..af034736b666 100644 --- a/libbeat/outputs/kafka/message.go +++ b/libbeat/outputs/kafka/message.go @@ -20,9 +20,8 @@ package kafka import ( "time" - "github.com/Shopify/sarama" - "github.com/elastic/beats/v7/libbeat/publisher" + "github.com/elastic/sarama" ) type message struct { @@ -40,8 +39,6 @@ type message struct { data publisher.Event } -var kafkaMessageKey interface{} = int(0) - func (m *message) initProducerMessage() { m.msg = sarama.ProducerMessage{ Metadata: m, diff --git a/libbeat/outputs/kafka/partition.go b/libbeat/outputs/kafka/partition.go index 8f56fde53e41..d2bf311132fd 100644 --- a/libbeat/outputs/kafka/partition.go +++ b/libbeat/outputs/kafka/partition.go @@ -26,11 +26,10 @@ import ( "math/rand" "strconv" - "github.com/Shopify/sarama" - "github.com/elastic/elastic-agent-libs/config" "github.com/elastic/elastic-agent-libs/logp" "github.com/elastic/elastic-agent-libs/mapstr" + "github.com/elastic/sarama" ) type partitionBuilder func(*logp.Logger, *config.C) (func() partitioner, error) @@ -117,7 +116,11 @@ func (p *messagePartitioner) Partition( libMsg *sarama.ProducerMessage, numPartitions int32, ) (int32, error) { - msg := libMsg.Metadata.(*message) + msg, ok := libMsg.Metadata.(*message) + if !ok { + return 0, fmt.Errorf("failed to assert libMsg.Metadata to *message") + } + if numPartitions == p.partitions { // if reachable is false, this is always true if 0 <= msg.partition && msg.partition < numPartitions { return msg.partition, nil @@ -126,13 +129,13 @@ func (p *messagePartitioner) Partition( partition, err := p.p(msg, numPartitions) if err != nil { - return 0, nil + return 0, nil //nolint:nilerr //ignoring this error } msg.partition = partition if _, err := msg.data.Cache.Put("partition", partition); err != nil { - return 0, fmt.Errorf("setting kafka partition in publisher event failed: %v", err) + return 0, fmt.Errorf("setting kafka partition in publisher event failed: %w", err) } p.partitions = numPartitions diff --git a/libbeat/outputs/kafka/partition_test.go b/libbeat/outputs/kafka/partition_test.go index bebc03f4a446..0a35c2bfdf0e 100644 --- a/libbeat/outputs/kafka/partition_test.go +++ b/libbeat/outputs/kafka/partition_test.go @@ -25,9 +25,10 @@ import ( "testing" "time" - "github.com/Shopify/sarama" "github.com/stretchr/testify/assert" + "github.com/elastic/sarama" + "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/beats/v7/libbeat/common" "github.com/elastic/beats/v7/libbeat/publisher" diff --git a/libbeat/outputs/logstash/async.go b/libbeat/outputs/logstash/async.go index a980d1cef32c..f0da5e45943d 100644 --- a/libbeat/outputs/logstash/async.go +++ b/libbeat/outputs/logstash/async.go @@ -22,10 +22,10 @@ import ( "errors" "net" "sync" + "sync/atomic" "time" "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/libbeat/outputs" "github.com/elastic/beats/v7/libbeat/publisher" "github.com/elastic/elastic-agent-libs/logp" @@ -147,13 +147,13 @@ func (c *asyncClient) Publish(_ context.Context, batch publisher.Batch) error { ref := &msgRef{ client: c, - count: atomic.MakeUint32(1), batch: batch, slice: events, batchSize: len(events), win: c.win, err: nil, } + ref.count.Store(1) defer ref.dec() for len(events) > 0 { @@ -218,7 +218,7 @@ func (c *asyncClient) sendEvents(ref *msgRef, events []publisher.Event) error { for i := range events { window[i] = &events[i].Content } - ref.count.Inc() + ref.count.Add(1) return client.Send(ref.callback, window) } @@ -261,7 +261,7 @@ func (r *msgRef) fail(n uint32, err error) { } func (r *msgRef) dec() { - i := r.count.Dec() + i := r.count.Add(^uint32(0)) if i > 0 { return } diff --git a/libbeat/outputs/otelconsumer/otelconsumer.go b/libbeat/outputs/otelconsumer/otelconsumer.go index ca5da5308e59..7b2f6fe93e5f 100644 --- a/libbeat/outputs/otelconsumer/otelconsumer.go +++ b/libbeat/outputs/otelconsumer/otelconsumer.go @@ -20,7 +20,6 @@ package otelconsumer import ( "context" "fmt" - "strings" "time" "github.com/elastic/beats/v7/libbeat/beat" @@ -103,30 +102,6 @@ func (out *otelConsumer) logsPublish(ctx context.Context, batch publisher.Batch) err := out.logsConsumer.ConsumeLogs(ctx, pLogs) if err != nil { - // If the batch is too large, the elasticsearchexporter will - // return a 413 error. - // - // At the moment, the exporter does not support batch splitting - // on error so we do it here. - // - // See https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/36163. - if strings.Contains(err.Error(), "Request Entity Too Large") { - // Try and split the batch into smaller batches and retry - if batch.SplitRetry() { - st.BatchSplit() - st.RetryableErrors(len(events)) - } else { - // If the batch could not be split, there is no option left but - // to drop it and log the error state. - batch.Drop() - st.PermanentErrors(len(events)) - out.log.Errorf("the batch is too large to be sent: %v", err) - } - - // Don't propagate the error, the batch was split and retried. - return nil - } - // Permanent errors shouldn't be retried. This tipically means // the data cannot be serialized by the exporter that is attached // to the pipeline or when the destination refuses the data because diff --git a/libbeat/outputs/otelconsumer/otelconsumer_test.go b/libbeat/outputs/otelconsumer/otelconsumer_test.go index 2751ce7f7214..6a197d806c13 100644 --- a/libbeat/outputs/otelconsumer/otelconsumer_test.go +++ b/libbeat/outputs/otelconsumer/otelconsumer_test.go @@ -90,33 +90,6 @@ func TestPublish(t *testing.T) { assert.Equal(t, outest.BatchRetry, batch.Signals[0].Tag) }) - t.Run("split batch on entity too large error", func(t *testing.T) { - batch := outest.NewBatch(event1, event2, event3) - - otelConsumer := makeOtelConsumer(t, func(ctx context.Context, ld plog.Logs) error { - return errors.New("Request Entity Too Large") - }) - - err := otelConsumer.Publish(ctx, batch) - assert.NoError(t, err) - assert.Len(t, batch.Signals, 1) - assert.Equal(t, outest.BatchSplitRetry, batch.Signals[0].Tag) - }) - - t.Run("drop batch if can't split on entity too large error", func(t *testing.T) { - batch := outest.NewBatch(event1) - - otelConsumer := makeOtelConsumer(t, func(ctx context.Context, ld plog.Logs) error { - return errors.New("Request Entity Too Large") - }) - - err := otelConsumer.Publish(ctx, batch) - assert.NoError(t, err) - assert.Len(t, batch.Signals, 2) - assert.Equal(t, outest.BatchSplitRetry, batch.Signals[0].Tag) - assert.Equal(t, outest.BatchDrop, batch.Signals[1].Tag) - }) - t.Run("drop batch on permanent consumer error", func(t *testing.T) { batch := outest.NewBatch(event1, event2, event3) diff --git a/libbeat/outputs/redis/backoff.go b/libbeat/outputs/redis/backoff.go index 2abc1f846f0a..42f9db1c2854 100644 --- a/libbeat/outputs/redis/backoff.go +++ b/libbeat/outputs/redis/backoff.go @@ -19,6 +19,7 @@ package redis import ( "context" + "errors" "time" "github.com/gomodule/redigo/redis" @@ -61,7 +62,7 @@ func newBackoffClient(client *client, init, max time.Duration) *backoffClient { } func (b *backoffClient) Connect(ctx context.Context) error { - err := b.client.Connect() + err := b.client.Connect(ctx) if err != nil { // give the client a chance to promote an internal error to a network error. b.updateFailReason(err) @@ -102,7 +103,8 @@ func (b *backoffClient) updateFailReason(err error) { return } - if _, ok := err.(redis.Error); ok { + var redisErr *redis.Error + if errors.As(err, &redisErr) { b.reason = failRedis } else { b.reason = failOther diff --git a/libbeat/outputs/redis/client.go b/libbeat/outputs/redis/client.go index 9f5c9812dd10..db3ec5a3b433 100644 --- a/libbeat/outputs/redis/client.go +++ b/libbeat/outputs/redis/client.go @@ -90,7 +90,7 @@ func newClient( } } -func (c *client) Connect() error { +func (c *client) Connect(_ context.Context) error { c.log.Debug("connect") err := c.Client.Connect() if err != nil { diff --git a/libbeat/processors/actions/lowercase_test.go b/libbeat/processors/actions/lowercase_test.go index 855112094fe1..4c11bd0f75d3 100644 --- a/libbeat/processors/actions/lowercase_test.go +++ b/libbeat/processors/actions/lowercase_test.go @@ -18,13 +18,13 @@ package actions import ( - "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/elastic/beats/v7/libbeat/beat" + "github.com/elastic/beats/v7/libbeat/internal/testutil" conf "github.com/elastic/elastic-agent-libs/config" "github.com/elastic/elastic-agent-libs/mapstr" ) @@ -337,21 +337,14 @@ func BenchmarkLowerCaseProcessorRun(b *testing.B) { Events []beat.Event }{ { - Name: "5000 events with 5 fields on each level with 3 level depth without collisions", - Events: GenerateEvents(5000, 5, 3, false), + Name: "5000 events with 5 fields on each level with 3 level depth", + Events: testutil.GenerateEvents(5000, 5, 3), }, { - Name: "5000 events with 5 fields on each level with 3 level depth with collisions", - Events: GenerateEvents(5000, 5, 3, true), - }, - { - Name: "500 events with 50 fields on each level with 5 level depth without collisions", - Events: GenerateEvents(500, 50, 3, false), - }, - { - Name: "500 events with 50 fields on each level with 5 level depth with collisions", - Events: GenerateEvents(500, 50, 3, true), + Name: "500 events with 50 fields on each level with 5 level depth", + Events: testutil.GenerateEvents(500, 50, 3), }, + // Add more test cases as needed for benchmarking } @@ -376,35 +369,3 @@ func BenchmarkLowerCaseProcessorRun(b *testing.B) { }) } } - -func GenerateEvents(numEvents, fieldsPerLevel, depth int, withCollisions bool) []beat.Event { - events := make([]beat.Event, numEvents) - for i := 0; i < numEvents; i++ { - event := &beat.Event{Fields: mapstr.M{}} - generateFields(event, fieldsPerLevel, depth, withCollisions) - events[i] = *event - } - return events -} - -func generateFields(event *beat.Event, fieldsPerLevel, depth int, withCollisions bool) { - if depth == 0 { - return - } - - for j := 1; j <= fieldsPerLevel; j++ { - var key string - for d := 1; d < depth; d++ { - key += fmt.Sprintf("level%dfield%d", d, j) - key += "." - } - if withCollisions { - key += fmt.Sprintf("Level%dField%d", depth, j) // Creating a collision (Level is capitalized) - } else { - key += fmt.Sprintf("level%dfield%d", depth, j) - } - event.Fields.Put(key, "value") - key = "" - } - -} diff --git a/libbeat/processors/add_cloud_metadata/docs/add_cloud_metadata.asciidoc b/libbeat/processors/add_cloud_metadata/docs/add_cloud_metadata.asciidoc index 1e05e1d2c24a..852b3b187d1e 100644 --- a/libbeat/processors/add_cloud_metadata/docs/add_cloud_metadata.asciidoc +++ b/libbeat/processors/add_cloud_metadata/docs/add_cloud_metadata.asciidoc @@ -21,7 +21,10 @@ The following cloud providers are supported: - Openstack Nova - Hetzner Cloud -NOTE: `huawei` is an alias for `openstack`. Huawei cloud runs on OpenStack platform, and when +[float] +==== Special notes + +`huawei` is an alias for `openstack`. Huawei cloud runs on OpenStack platform, and when viewed from a metadata API standpoint, it is impossible to differentiate it from OpenStack. If you know that your deployments run on Huawei Cloud exclusively, and you wish to have `cloud.provider` value as `huawei`, you can achieve this by overwriting the value using an `add_fields` processor. @@ -30,6 +33,16 @@ The Alibaba Cloud and Tencent cloud providers are disabled by default, because they require to access a remote host. The `providers` setting allows users to select a list of default providers to query. +Cloud providers tend to maintain metadata services compliant with other cloud providers. +For example, Openstack supports https://docs.openstack.org/nova/latest/user/metadata.html#ec2-compatible-metadata[EC2 compliant metadat service]. +This makes it impossible to differentiate cloud provider (`cloud.provider` property) with auto discovery (when `providers` configuration is omitted). +The processor implementation incorporates a priority mechanism where priority is given to some providers over others when there are multiple successful metadata results. +Currently, `aws/ec2` and `azure` have priority over any other provider as their metadata retrival rely on SDKs. +The expectation here is that SDK methods should fail if run in an environment not configured accordingly (ex:- missing configurations or credentials). + +[float] +==== Configurations + The simple configuration below enables the processor. [source,yaml] @@ -71,6 +84,16 @@ List of names the `providers` setting supports: - "tencent", or "qcloud" for Tencent Cloud (disabled by default). - "hetzner" for Hetzner Cloud (enabled by default). +For example, configuration below only utilize `aws` metadata retrival mechanism, + +[source,yaml] +------------------------------------------------------------------------------- +processors: + - add_cloud_metadata: + providers: + aws +------------------------------------------------------------------------------- + The third optional configuration setting is `overwrite`. When `overwrite` is `true`, `add_cloud_metadata` overwrites existing `cloud.*` fields (`false` by default). @@ -78,6 +101,9 @@ default). The `add_cloud_metadata` processor supports SSL options to configure the http client used to query cloud metadata. See <> for more information. +[float] +==== Provided metadata + The metadata that is added to events varies by hosting provider. Below are examples for each of the supported providers. diff --git a/libbeat/processors/add_cloud_metadata/provider_alibaba_cloud.go b/libbeat/processors/add_cloud_metadata/provider_alibaba_cloud.go index 9bdce314ba8e..754cf82007f8 100644 --- a/libbeat/processors/add_cloud_metadata/provider_alibaba_cloud.go +++ b/libbeat/processors/add_cloud_metadata/provider_alibaba_cloud.go @@ -27,7 +27,7 @@ import ( var alibabaCloudMetadataFetcher = provider{ Name: "alibaba-ecs", - Local: false, + DefaultEnabled: false, Create: func(_ string, c *conf.C) (metadataFetcher, error) { ecsMetadataHost := "100.100.100.200" diff --git a/libbeat/processors/add_cloud_metadata/provider_aws_ec2.go b/libbeat/processors/add_cloud_metadata/provider_aws_ec2.go index ae7dfbf9865d..1c364f8e6a9a 100644 --- a/libbeat/processors/add_cloud_metadata/provider_aws_ec2.go +++ b/libbeat/processors/add_cloud_metadata/provider_aws_ec2.go @@ -65,7 +65,7 @@ var NewEC2Client func(cfg awssdk.Config) EC2Client = func(cfg awssdk.Config) EC2 var ec2MetadataFetcher = provider{ Name: "aws-ec2", - Local: true, + DefaultEnabled: true, Create: func(_ string, config *conf.C) (metadataFetcher, error) { ec2Schema := func(m map[string]interface{}) mapstr.M { diff --git a/libbeat/processors/add_cloud_metadata/provider_azure_vm.go b/libbeat/processors/add_cloud_metadata/provider_azure_vm.go index 788519352a86..e39b97b7031d 100644 --- a/libbeat/processors/add_cloud_metadata/provider_azure_vm.go +++ b/libbeat/processors/add_cloud_metadata/provider_azure_vm.go @@ -62,7 +62,7 @@ var NewClusterClient func(clientFactory *armcontainerservice.ClientFactory) *arm var azureVMMetadataFetcher = provider{ Name: "azure-compute", - Local: true, + DefaultEnabled: true, Create: func(_ string, config *conf.C) (metadataFetcher, error) { azMetadataURI := "/metadata/instance/compute?api-version=2021-02-01" diff --git a/libbeat/processors/add_cloud_metadata/provider_digital_ocean.go b/libbeat/processors/add_cloud_metadata/provider_digital_ocean.go index bfe282f70744..afc8cd3020dc 100644 --- a/libbeat/processors/add_cloud_metadata/provider_digital_ocean.go +++ b/libbeat/processors/add_cloud_metadata/provider_digital_ocean.go @@ -28,7 +28,7 @@ import ( var doMetadataFetcher = provider{ Name: "digitalocean", - Local: true, + DefaultEnabled: true, Create: func(provider string, config *conf.C) (metadataFetcher, error) { doSchema := func(m map[string]interface{}) mapstr.M { diff --git a/libbeat/processors/add_cloud_metadata/provider_google_gce.go b/libbeat/processors/add_cloud_metadata/provider_google_gce.go index 1eb8525b2f3e..cebfb747bfe5 100644 --- a/libbeat/processors/add_cloud_metadata/provider_google_gce.go +++ b/libbeat/processors/add_cloud_metadata/provider_google_gce.go @@ -45,7 +45,7 @@ type Server struct { var gceMetadataFetcher = provider{ Name: "google-gce", - Local: true, + DefaultEnabled: true, Create: func(provider string, config *conf.C) (metadataFetcher, error) { gceMetadataURI := "/computeMetadata/v1/?recursive=true&alt=json" diff --git a/libbeat/processors/add_cloud_metadata/provider_hetzner_cloud.go b/libbeat/processors/add_cloud_metadata/provider_hetzner_cloud.go index 4c231174c001..3bfea2c119a8 100644 --- a/libbeat/processors/add_cloud_metadata/provider_hetzner_cloud.go +++ b/libbeat/processors/add_cloud_metadata/provider_hetzner_cloud.go @@ -32,8 +32,8 @@ const ( // Hetzner Cloud Metadata Service // Document https://docs.hetzner.cloud/#server-metadata var hetznerMetadataFetcher = provider{ - Name: "hetzner-cloud", - Local: true, + Name: "hetzner-cloud", + DefaultEnabled: true, Create: func(_ string, c *conf.C) (metadataFetcher, error) { hetznerSchema := func(m map[string]interface{}) mapstr.M { m["service"] = mapstr.M{ diff --git a/libbeat/processors/add_cloud_metadata/provider_openstack_nova.go b/libbeat/processors/add_cloud_metadata/provider_openstack_nova.go index 824d2651c3a4..40f91be43231 100644 --- a/libbeat/processors/add_cloud_metadata/provider_openstack_nova.go +++ b/libbeat/processors/add_cloud_metadata/provider_openstack_nova.go @@ -33,15 +33,15 @@ const ( // OpenStack Nova Metadata Service // Document https://docs.openstack.org/nova/latest/user/metadata-service.html var openstackNovaMetadataFetcher = provider{ - Name: "openstack-nova", - Local: true, - Create: buildOpenstackNovaCreate("http"), + Name: "openstack-nova", + DefaultEnabled: true, + Create: buildOpenstackNovaCreate("http"), } var openstackNovaSSLMetadataFetcher = provider{ - Name: "openstack-nova-ssl", - Local: true, - Create: buildOpenstackNovaCreate("https"), + Name: "openstack-nova-ssl", + DefaultEnabled: true, + Create: buildOpenstackNovaCreate("https"), } func buildOpenstackNovaCreate(scheme string) func(provider string, c *conf.C) (metadataFetcher, error) { diff --git a/libbeat/processors/add_cloud_metadata/provider_tencent_cloud.go b/libbeat/processors/add_cloud_metadata/provider_tencent_cloud.go index e805ff1bf95c..ca4733edc60d 100644 --- a/libbeat/processors/add_cloud_metadata/provider_tencent_cloud.go +++ b/libbeat/processors/add_cloud_metadata/provider_tencent_cloud.go @@ -27,7 +27,7 @@ import ( var qcloudMetadataFetcher = provider{ Name: "tencent-qcloud", - Local: false, + DefaultEnabled: false, Create: func(_ string, c *conf.C) (metadataFetcher, error) { qcloudMetadataHost := "metadata.tencentyun.com" diff --git a/libbeat/processors/add_cloud_metadata/providers.go b/libbeat/processors/add_cloud_metadata/providers.go index ea56a5e669b3..5d6d64047c44 100644 --- a/libbeat/processors/add_cloud_metadata/providers.go +++ b/libbeat/processors/add_cloud_metadata/providers.go @@ -23,10 +23,12 @@ import ( "net" "net/http" "os" + "slices" "strings" "time" conf "github.com/elastic/elastic-agent-libs/config" + "github.com/elastic/elastic-agent-libs/logp" "github.com/elastic/elastic-agent-libs/mapstr" ) @@ -34,8 +36,9 @@ type provider struct { // Name contains a long name of provider and service metadata is fetched from. Name string - // Local Set to true if local IP is accessed only - Local bool + // DefaultEnabled allows to control whether metadata provider should be enabled by default + // Set to true if metadata access is enabled by default for the provider + DefaultEnabled bool // Create returns an actual metadataFetcher Create func(string, *conf.C) (metadataFetcher, error) @@ -70,6 +73,14 @@ var cloudMetaProviders = map[string]provider{ "hetzner": hetznerMetadataFetcher, } +// priorityProviders contains providers which has priority over others. +// Metadata of these are derived using cloud provider SDKs, making them valid over metadata derived over well-known IP +// or other common endpoints. For example, Openstack supports EC2 compliant metadata endpoint. Thus adding possibility to +// conflict metadata between EC2/AWS and Openstack. +var priorityProviders = []string{ + "aws", "ec2", "azure", +} + func selectProviders(configList providerList, providers map[string]provider) map[string]provider { return filterMetaProviders(providersFilter(configList, providers), providers) } @@ -93,7 +104,7 @@ func providersFilter(configList providerList, allProviders map[string]provider) if len(configList) == 0 { return func(name string) bool { ff, ok := allProviders[name] - return ok && ff.Local + return ok && ff.DefaultEnabled } } return func(name string) (ok bool) { @@ -178,22 +189,54 @@ func (p *addCloudMetadata) fetchMetadata() *result { }() } - for i := 0; i < len(p.initData.fetchers); i++ { + var responses []result + + for ctx.Err() == nil { select { case result := <-results: p.logger.Debugf("add_cloud_metadata: received disposition for %v after %v. %v", result.provider, time.Since(start), result) - // Bail out on first success. + if result.err == nil && result.metadata != nil { - return &result - } else if result.err != nil { - p.logger.Errorf("add_cloud_metadata: received error for provider %s: %v", result.provider, result.err) + responses = append(responses, result) + } + + if result.err != nil { + p.logger.Debugf("add_cloud_metadata: received error for provider %s: %v", result.provider, result.err) } case <-ctx.Done(): - p.logger.Debugf("add_cloud_metadata: timed-out waiting for all responses") - return nil + p.logger.Debugf("add_cloud_metadata: timed-out waiting for responses") } } - return nil + return priorityResult(responses, p.logger) +} + +// priorityResult is a helper to extract correct result (if multiple exist) based on priorityProviders +func priorityResult(responses []result, logger *logp.Logger) *result { + if len(responses) == 0 { + return nil + } + + if len(responses) == 1 { + return &responses[0] + } + + logger.Debugf("add_cloud_metadata: multiple responses were received, filtering based on priority") + var prioritizedResponses []result + for _, r := range responses { + if slices.Contains(priorityProviders, r.provider) { + prioritizedResponses = append(prioritizedResponses, r) + } + } + + // simply send the first entry of prioritized response + if len(prioritizedResponses) != 0 { + pr := prioritizedResponses[0] + logger.Debugf("add_cloud_metadata: using provider %s metadata based on priority", pr.provider) + return &pr + } + + // else send the first from bulk of response + return &responses[0] } diff --git a/libbeat/processors/add_cloud_metadata/providers_test.go b/libbeat/processors/add_cloud_metadata/providers_test.go index 85336a4c2b3f..0f39dcf56769 100644 --- a/libbeat/processors/add_cloud_metadata/providers_test.go +++ b/libbeat/processors/add_cloud_metadata/providers_test.go @@ -25,6 +25,7 @@ import ( "github.com/stretchr/testify/assert" conf "github.com/elastic/elastic-agent-libs/config" + "github.com/elastic/elastic-agent-libs/logp" ) func init() { @@ -34,7 +35,7 @@ func init() { func TestProvidersFilter(t *testing.T) { var allLocal []string for name, ff := range cloudMetaProviders { - if ff.Local { + if ff.DefaultEnabled { allLocal = append(allLocal, name) } } @@ -119,3 +120,59 @@ func TestProvidersFilter(t *testing.T) { }) } } + +func Test_priorityResult(t *testing.T) { + tLogger := logp.NewLogger("add_cloud_metadata testing") + awsRsp := result{ + provider: "aws", + metadata: map[string]interface{}{ + "id": "a-1", + }, + } + + openStackRsp := result{ + provider: "openstack", + metadata: map[string]interface{}{ + "id": "o-1", + }, + } + + digitaloceanRsp := result{ + provider: "digitalocean", + metadata: map[string]interface{}{ + "id": "d-1", + }, + } + + tests := []struct { + name string + collected []result + want *result + }{ + { + name: "Empty results returns nil", + collected: []result{}, + want: nil, + }, + { + name: "Single result returns the same", + collected: []result{awsRsp}, + want: &awsRsp, + }, + { + name: "Priority result wins", + collected: []result{openStackRsp, awsRsp}, + want: &awsRsp, + }, + { + name: "For non-priority result, response order wins", + collected: []result{openStackRsp, digitaloceanRsp}, + want: &openStackRsp, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, priorityResult(tt.collected, tLogger)) + }) + } +} diff --git a/libbeat/processors/add_process_metadata/add_process_metadata.go b/libbeat/processors/add_process_metadata/add_process_metadata.go index 2385e5f99def..78e67f8e4d70 100644 --- a/libbeat/processors/add_process_metadata/add_process_metadata.go +++ b/libbeat/processors/add_process_metadata/add_process_metadata.go @@ -22,11 +22,11 @@ import ( "fmt" "reflect" "strconv" + "sync/atomic" "time" "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/beats/v7/libbeat/common" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/libbeat/processors" jsprocessor "github.com/elastic/beats/v7/libbeat/processors/script/javascript/module/processor" conf "github.com/elastic/elastic-agent-libs/config" @@ -131,7 +131,7 @@ func NewWithConfig(opts ...ConfigOption) (beat.Processor, error) { func newProcessMetadataProcessorWithProvider(config config, provider processMetadataProvider, withCache bool) (proc beat.Processor, err error) { // Logging (each processor instance has a unique ID). var ( - id = int(instanceID.Inc()) + id = int(instanceID.Add(1)) log = logp.NewLogger(processorName).With("instance_id", id) ) diff --git a/libbeat/processors/cache/cache.go b/libbeat/processors/cache/cache.go index a7ce4876f505..45c1e41872ef 100644 --- a/libbeat/processors/cache/cache.go +++ b/libbeat/processors/cache/cache.go @@ -22,10 +22,10 @@ import ( "errors" "fmt" "os" + "sync/atomic" "time" "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/libbeat/processors" conf "github.com/elastic/elastic-agent-libs/config" "github.com/elastic/elastic-agent-libs/logp" @@ -67,7 +67,7 @@ func New(cfg *conf.C) (beat.Processor, error) { return nil, fmt.Errorf("failed to unpack the %s configuration: %w", name, err) } // Logging (each processor instance has a unique ID). - id := int(instanceID.Inc()) + id := int(instanceID.Add(1)) log := logp.NewLogger(name).With("instance_id", id) src, cancel, err := getStoreFor(config, log) diff --git a/libbeat/processors/decode_xml_wineventlog/config.go b/libbeat/processors/decode_xml_wineventlog/config.go index 061a4d0a52fb..28373651c213 100644 --- a/libbeat/processors/decode_xml_wineventlog/config.go +++ b/libbeat/processors/decode_xml_wineventlog/config.go @@ -24,6 +24,7 @@ type config struct { MapECSFields bool `config:"map_ecs_fields"` IgnoreMissing bool `config:"ignore_missing"` IgnoreFailure bool `config:"ignore_failure"` + Language uint32 `config:"language"` } func defaultConfig() config { diff --git a/libbeat/processors/decode_xml_wineventlog/decoder.go b/libbeat/processors/decode_xml_wineventlog/decoder.go index 7f0d298c815c..3849a06af455 100644 --- a/libbeat/processors/decode_xml_wineventlog/decoder.go +++ b/libbeat/processors/decode_xml_wineventlog/decoder.go @@ -26,7 +26,7 @@ import ( type nonWinDecoder struct{} -func newDecoder() decoder { +func newDecoder(uint32) decoder { return nonWinDecoder{} } diff --git a/libbeat/processors/decode_xml_wineventlog/decoder_windows.go b/libbeat/processors/decode_xml_wineventlog/decoder_windows.go index ba27cf51ddc3..7989b36459b5 100644 --- a/libbeat/processors/decode_xml_wineventlog/decoder_windows.go +++ b/libbeat/processors/decode_xml_wineventlog/decoder_windows.go @@ -29,11 +29,13 @@ import ( ) type winDecoder struct { - cache *metadataCache + locale uint32 + cache *metadataCache } -func newDecoder() decoder { +func newDecoder(locale uint32) decoder { return &winDecoder{ + locale: locale, cache: &metadataCache{ store: map[string]*winevent.WinMeta{}, log: logp.NewLogger(logName), @@ -46,7 +48,7 @@ func (dec *winDecoder) decode(data []byte) (mapstr.M, mapstr.M, error) { if err != nil { return nil, nil, err } - md := dec.cache.getPublisherMetadata(evt.Provider.Name) + md := dec.cache.getPublisherMetadata(evt.Provider.Name, dec.locale) winevent.EnrichRawValuesWithNames(md, &evt) win, ecs := fields(evt) return win, ecs, nil @@ -59,7 +61,7 @@ type metadataCache struct { log *logp.Logger } -func (c *metadataCache) getPublisherMetadata(publisher string) *winevent.WinMeta { +func (c *metadataCache) getPublisherMetadata(publisher string, locale uint32) *winevent.WinMeta { // NOTE: This code uses double-check locking to elevate to a write-lock // when a cache value needs initialized. c.mutex.RLock() @@ -79,7 +81,7 @@ func (c *metadataCache) getPublisherMetadata(publisher string) *winevent.WinMeta } // Load metadata from the publisher. - md, err := wineventlog.NewPublisherMetadataStore(wineventlog.NilHandle, publisher, c.log) + md, err := wineventlog.NewPublisherMetadataStore(wineventlog.NilHandle, publisher, locale, c.log) if err != nil { // Return an empty store on error (can happen in cases where the // log was forwarded and the provider doesn't exist on collector). diff --git a/libbeat/processors/decode_xml_wineventlog/docs/decode_xml_wineventlog.asciidoc b/libbeat/processors/decode_xml_wineventlog/docs/decode_xml_wineventlog.asciidoc index 1e30d57f6983..c86bb06e440c 100644 --- a/libbeat/processors/decode_xml_wineventlog/docs/decode_xml_wineventlog.asciidoc +++ b/libbeat/processors/decode_xml_wineventlog/docs/decode_xml_wineventlog.asciidoc @@ -35,6 +35,11 @@ when a specified field does not exist. Defaults to `false`. `ignore_failure`:: (Optional) Ignore all errors produced by the processor. Defaults to `false`. +`language`:: (Optional) The language ID the events will be rendered in. The language will be forced regardless +of the system language. Forwarded events will ignore this setting. A complete list of language IDs can be found +https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c[here]. +It defaults to `0`, which indicates to use the system language. + Example: [source,yaml] diff --git a/libbeat/processors/decode_xml_wineventlog/processor.go b/libbeat/processors/decode_xml_wineventlog/processor.go index c6eacdf94671..85a514d6d440 100644 --- a/libbeat/processors/decode_xml_wineventlog/processor.go +++ b/libbeat/processors/decode_xml_wineventlog/processor.go @@ -83,7 +83,7 @@ func newProcessor(config config) (beat.Processor, error) { return &processor{ config: config, - decoder: newDecoder(), + decoder: newDecoder(config.Language), log: logp.NewLogger(logName), }, nil } diff --git a/libbeat/processors/dns/dns.go b/libbeat/processors/dns/dns.go index d4f3d2ba57b9..48b08ab671c9 100644 --- a/libbeat/processors/dns/dns.go +++ b/libbeat/processors/dns/dns.go @@ -22,9 +22,9 @@ import ( "strconv" "strings" "sync" + "sync/atomic" "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/libbeat/processors" jsprocessor "github.com/elastic/beats/v7/libbeat/processors/script/javascript/module/processor" conf "github.com/elastic/elastic-agent-libs/config" @@ -36,7 +36,7 @@ import ( const logName = "processor.dns" // instanceID is used to assign each instance a unique monitoring namespace. -var instanceID = atomic.MakeUint32(0) +var instanceID atomic.Uint32 func init() { processors.RegisterPlugin("dns", New) @@ -58,7 +58,7 @@ func New(cfg *conf.C) (beat.Processor, error) { // Logging and metrics (each processor instance has a unique ID). var ( - id = int(instanceID.Inc()) + id = int(instanceID.Add(1)) log = logp.NewLogger(logName).With("instance_id", id) metrics = monitoring.Default.NewRegistry(logName+"."+strconv.Itoa(id), monitoring.DoNotReport) ) diff --git a/libbeat/processors/namespace.go b/libbeat/processors/namespace.go index 0ccf1deda458..5d015b16bcf1 100644 --- a/libbeat/processors/namespace.go +++ b/libbeat/processors/namespace.go @@ -38,6 +38,11 @@ type pluginer interface { Plugin() Constructor } +var ( + ErrExistsAlready error = errors.New("exists already") + ErrPluginAlreadyRegistered error = errors.New("non-namespace plugin already registered") +) + func NewNamespace() *Namespace { return &Namespace{ reg: map[string]pluginer{}, @@ -47,7 +52,7 @@ func NewNamespace() *Namespace { func (ns *Namespace) Register(name string, factory Constructor) error { p := plugin{NewConditional(factory)} names := strings.Split(name, ".") - if err := ns.add(names, p); err != nil { + if err := ns.add(names, p); err != nil && !errors.Is(err, ErrExistsAlready) && !errors.Is(err, ErrPluginAlreadyRegistered) { return fmt.Errorf("plugin %s registration fail %w", name, err) } return nil @@ -59,7 +64,7 @@ func (ns *Namespace) add(names []string, p pluginer) error { // register plugin if intermediate node in path being processed if len(names) == 1 { if _, found := ns.reg[name]; found { - return fmt.Errorf("%v exists already", name) + return fmt.Errorf("%s %w", name, ErrExistsAlready) } ns.reg[name] = p @@ -71,7 +76,7 @@ func (ns *Namespace) add(names []string, p pluginer) error { if found { ns, ok := tmp.(*Namespace) if !ok { - return errors.New("non-namespace plugin already registered") + return ErrPluginAlreadyRegistered } return ns.add(names[1:], p) } diff --git a/libbeat/processors/namespace_test.go b/libbeat/processors/namespace_test.go index 07c62328c2c1..221cee9b2e37 100644 --- a/libbeat/processors/namespace_test.go +++ b/libbeat/processors/namespace_test.go @@ -65,7 +65,7 @@ func TestNamespaceRegisterFail(t *testing.T) { fatalError(t, err) err = ns.Register("test", newTestFilterRule) - assert.Error(t, err) + assert.NoError(t, err) } func TestNamespaceError(t *testing.T) { diff --git a/libbeat/processors/ratelimit/rate_limit.go b/libbeat/processors/ratelimit/rate_limit.go index f558b076e2ba..92d9b4c37a0b 100644 --- a/libbeat/processors/ratelimit/rate_limit.go +++ b/libbeat/processors/ratelimit/rate_limit.go @@ -22,12 +22,12 @@ import ( "fmt" "sort" "strconv" + "sync/atomic" "github.com/jonboulle/clockwork" "github.com/mitchellh/hashstructure" "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/libbeat/processors" c "github.com/elastic/elastic-agent-libs/config" "github.com/elastic/elastic-agent-libs/logp" @@ -36,7 +36,7 @@ import ( ) // instanceID is used to assign each instance a unique monitoring namespace. -var instanceID = atomic.MakeUint32(0) +var instanceID atomic.Uint32 const processorName = "rate_limit" const logName = "processor." + processorName @@ -79,7 +79,7 @@ func new(cfg *c.C) (beat.Processor, error) { // Logging and metrics (each processor instance has a unique ID). var ( - id = int(instanceID.Inc()) + id = int(instanceID.Add(1)) log = logp.NewLogger(logName).With("instance_id", id) reg = monitoring.Default.NewRegistry(logName+"."+strconv.Itoa(id), monitoring.DoNotReport) ) diff --git a/libbeat/processors/ratelimit/token_bucket.go b/libbeat/processors/ratelimit/token_bucket.go index 1f1381fd8dfe..1e84f799b986 100644 --- a/libbeat/processors/ratelimit/token_bucket.go +++ b/libbeat/processors/ratelimit/token_bucket.go @@ -20,13 +20,13 @@ package ratelimit import ( "fmt" "sync" + "sync/atomic" "time" "github.com/jonboulle/clockwork" "github.com/elastic/go-concert/unison" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/elastic-agent-libs/logp" ) @@ -50,7 +50,7 @@ type tokenBucket struct { gc struct { thresholds tokenBucketGCConfig metrics struct { - numCalls atomic.Uint + numCalls atomic.Uint64 } } @@ -93,7 +93,7 @@ func newTokenBucket(config algoConfig) (algorithm, error) { gc: struct { thresholds tokenBucketGCConfig metrics struct { - numCalls atomic.Uint + numCalls atomic.Uint64 } }{ thresholds: tokenBucketGCConfig{ @@ -112,7 +112,7 @@ func (t *tokenBucket) IsAllowed(key uint64) bool { b := t.getBucket(key) allowed := b.withdraw() - t.gc.metrics.numCalls.Inc() + t.gc.metrics.numCalls.Add(1) return allowed } @@ -126,6 +126,7 @@ func (t *tokenBucket) getBucket(key uint64) *bucket { tokens: t.depth, lastReplenish: t.clock.Now(), }) + //nolint:errcheck // ignore b := v.(*bucket) if exists { @@ -154,7 +155,7 @@ func (b *bucket) replenish(rate rate, clock clockwork.Clock) { func (t *tokenBucket) runGC() { // Don't run GC if thresholds haven't been crossed. - if t.gc.metrics.numCalls.Load() < t.gc.thresholds.NumCalls { + if t.gc.metrics.numCalls.Load() < uint64(t.gc.thresholds.NumCalls) { return } @@ -171,7 +172,9 @@ func (t *tokenBucket) runGC() { toDelete := make([]uint64, 0) numBucketsBefore := 0 t.buckets.Range(func(k, v interface{}) bool { + //nolint:errcheck // ignore key := k.(uint64) + //nolint:errcheck // ignore b := v.(*bucket) b.replenish(t.limit, t.clock) @@ -190,9 +193,9 @@ func (t *tokenBucket) runGC() { } // Reset GC metrics - t.gc.metrics.numCalls = atomic.MakeUint(0) + t.gc.metrics.numCalls = atomic.Uint64{} - gcDuration := time.Now().Sub(gcStartTime) + gcDuration := time.Since(gcStartTime) numBucketsDeleted := len(toDelete) numBucketsAfter := numBucketsBefore - numBucketsDeleted t.logger.Debugf("gc duration: %v, buckets: (before: %v, deleted: %v, after: %v)", diff --git a/libbeat/processors/syslog/syslog.go b/libbeat/processors/syslog/syslog.go index 96c21d3d7738..9a6e71fcca3f 100644 --- a/libbeat/processors/syslog/syslog.go +++ b/libbeat/processors/syslog/syslog.go @@ -22,9 +22,9 @@ import ( "errors" "fmt" "strconv" + "sync/atomic" "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/libbeat/common/cfgtype" "github.com/elastic/beats/v7/libbeat/common/jsontransform" "github.com/elastic/beats/v7/libbeat/processors" @@ -43,7 +43,7 @@ const ( ) // instanceID is used to assign each instance a unique monitoring namespace. -var instanceID = atomic.MakeUint32(0) +var instanceID atomic.Uint32 // config defines the configuration for this processor. type config struct { @@ -114,7 +114,7 @@ func New(c *conf.C) (beat.Processor, error) { return nil, fmt.Errorf("fail to unpack the "+procName+" processor configuration: %w", err) } - id := int(instanceID.Inc()) + id := int(instanceID.Add(1)) log := logp.NewLogger(logName).With("instance_id", id) registryName := logName + "." + strconv.Itoa(id) diff --git a/libbeat/publisher/pipeline/client.go b/libbeat/publisher/pipeline/client.go index af756213a632..3048ec4a0017 100644 --- a/libbeat/publisher/pipeline/client.go +++ b/libbeat/publisher/pipeline/client.go @@ -19,10 +19,10 @@ package pipeline import ( "sync" + "sync/atomic" "time" "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/libbeat/processors" "github.com/elastic/beats/v7/libbeat/publisher" "github.com/elastic/beats/v7/libbeat/publisher/queue" @@ -41,8 +41,7 @@ type client struct { canDrop bool // Open state, signaling, and sync primitives for coordinating client Close. - isOpen atomic.Bool // set to false during shutdown, such that no new events will be accepted anymore. - closeOnce sync.Once // closeOnce ensure that the client shutdown sequence is only executed once + isOpen atomic.Bool // set to false during shutdown, such that no new events will be accepted anymore. observer observer eventListener beat.EventListener @@ -204,12 +203,12 @@ func newClientCloseWaiter(timeout time.Duration) *clientCloseWaiter { func (w *clientCloseWaiter) AddEvent(_ beat.Event, published bool) { if published { - w.events.Inc() + w.events.Add(1) } } func (w *clientCloseWaiter) ACKEvents(n int) { - value := w.events.Sub(uint32(n)) + value := w.events.Add(^uint32(n - 1)) if value != 0 { return } diff --git a/libbeat/publisher/pipeline/client_worker_test.go b/libbeat/publisher/pipeline/client_worker_test.go index 97692b2aada8..ed97cd11ac83 100644 --- a/libbeat/publisher/pipeline/client_worker_test.go +++ b/libbeat/publisher/pipeline/client_worker_test.go @@ -22,6 +22,7 @@ import ( "math" "strings" "sync" + "sync/atomic" "testing" "testing/quick" "time" @@ -30,7 +31,6 @@ import ( "github.com/stretchr/testify/require" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/libbeat/internal/testutil" "github.com/elastic/beats/v7/libbeat/outputs" "github.com/elastic/beats/v7/libbeat/publisher" @@ -48,7 +48,7 @@ func TestMakeClientWorker(t *testing.T) { err := quick.Check(func(i uint) bool { numBatches := 300 + (i % 100) // between 300 and 399 - var numEvents uint + var numEvents uint64 logger := makeBufLogger(t) @@ -56,9 +56,9 @@ func TestMakeClientWorker(t *testing.T) { retryer := newStandaloneRetryer(workQueue) defer retryer.close() - var published atomic.Uint + var published atomic.Uint64 publishFn := func(batch publisher.Batch) error { - published.Add(uint(len(batch.Events()))) + published.Add(uint64(len(batch.Events()))) return nil } @@ -69,7 +69,7 @@ func TestMakeClientWorker(t *testing.T) { for i := uint(0); i < numBatches; i++ { batch := randomBatch(50, 150).withRetryer(retryer) - numEvents += uint(len(batch.Events())) + numEvents += uint64(len(batch.Events())) workQueue <- batch } @@ -82,7 +82,7 @@ func TestMakeClientWorker(t *testing.T) { }) if !success { logger.Flush() - t.Logf("numBatches = %v, numEvents = %v, published = %v", numBatches, numEvents, published) + t.Logf("numBatches = %v, numEvents = %v, published = %v", numBatches, numEvents, published.Load()) } return success }, nil) @@ -140,9 +140,9 @@ func TestReplaceClientWorker(t *testing.T) { }() // Publish at least 1 batch worth of events but no more than 20% events - publishLimit := uint(math.Max(minEventsInBatch, float64(numEvents)*0.2)) + publishLimit := uint64(math.Max(minEventsInBatch, float64(numEvents)*0.2)) - var publishedFirst atomic.Uint + var publishedFirst atomic.Uint64 blockCtrl := make(chan struct{}) blockingPublishFn := func(batch publisher.Batch) error { // Emulate blocking. Upon unblocking the in-flight batch that was @@ -152,7 +152,7 @@ func TestReplaceClientWorker(t *testing.T) { } count := len(batch.Events()) - publishedFirst.Add(uint(count)) + publishedFirst.Add(uint64(count)) t.Logf("#1 processed batch: %v (%v)", batch.(*mockBatch).events[0].Content.Private, count) return nil } @@ -176,10 +176,10 @@ func TestReplaceClientWorker(t *testing.T) { close(blockCtrl) // Start new worker to drain work queue - var publishedLater atomic.Uint + var publishedLater atomic.Uint64 countingPublishFn := func(batch publisher.Batch) error { count := len(batch.Events()) - publishedLater.Add(uint(count)) + publishedLater.Add(uint64(count)) t.Logf("#2 processed batch: %v (%v)", batch.(*mockBatch).events[0].Content.Private, count) return nil } @@ -212,7 +212,7 @@ func TestMakeClientTracer(t *testing.T) { testutil.SeedPRNG(t) numBatches := 10 - var numEvents uint + var numEvents uint64 logger := makeBufLogger(t) @@ -220,9 +220,9 @@ func TestMakeClientTracer(t *testing.T) { retryer := newStandaloneRetryer(workQueue) defer retryer.close() - var published atomic.Uint + var published atomic.Uint64 publishFn := func(batch publisher.Batch) error { - published.Add(uint(len(batch.Events()))) + published.Add(uint64(len(batch.Events()))) return nil } @@ -236,7 +236,7 @@ func TestMakeClientTracer(t *testing.T) { for i := 0; i < numBatches; i++ { batch := randomBatch(10, 15).withRetryer(retryer) - numEvents += uint(len(batch.Events())) + numEvents += uint64(len(batch.Events())) workQueue <- batch } @@ -248,7 +248,7 @@ func TestMakeClientTracer(t *testing.T) { return numEvents == published.Load() }) if !matches { - t.Errorf("expected %d events, got %d", numEvents, published) + t.Errorf("expected %d events, got %d", numEvents, published.Load()) } recorder.Flush(nil) diff --git a/libbeat/publisher/pipeline/controller_test.go b/libbeat/publisher/pipeline/controller_test.go index 706c159e3d4a..5e48fbb79b8f 100644 --- a/libbeat/publisher/pipeline/controller_test.go +++ b/libbeat/publisher/pipeline/controller_test.go @@ -20,12 +20,12 @@ package pipeline import ( "fmt" "sync" + "sync/atomic" "testing" "testing/quick" "time" "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/libbeat/internal/testutil" "github.com/elastic/beats/v7/libbeat/outputs" "github.com/elastic/beats/v7/libbeat/publisher" @@ -64,9 +64,9 @@ func TestOutputReload(t *testing.T) { fmt.Sprintf("mem.events: %v", numEventsToPublish)) _ = queueConfig.Unpack(conf) - var publishedCount atomic.Uint + var publishedCount atomic.Uint64 countingPublishFn := func(batch publisher.Batch) error { - publishedCount.Add(uint(len(batch.Events()))) + publishedCount.Add(uint64(len(batch.Events()))) return nil } @@ -108,7 +108,7 @@ func TestOutputReload(t *testing.T) { timeout := 20 * time.Second return waitUntilTrue(timeout, func() bool { - return numEventsToPublish == publishedCount.Load() + return uint64(numEventsToPublish) == publishedCount.Load() }) }, &quick.Config{MaxCount: 25}) @@ -222,18 +222,19 @@ func TestQueueProducerBlocksUntilOutputIsSet(t *testing.T) { // block, because there is no queue, but they should become unblocked // once we set a nonempty output. const producerCount = 10 - remaining := atomic.MakeInt(producerCount) + var remaining atomic.Int64 + remaining.Store(producerCount) for i := 0; i < producerCount; i++ { go func() { controller.queueProducer(queue.ProducerConfig{}) - remaining.Dec() + remaining.Add(-1) }() } allStarted := waitUntilTrue(time.Second, func() bool { return len(controller.pendingRequests) == producerCount }) assert.True(t, allStarted, "All queueProducer requests should be saved as pending requests by outputController") - assert.Equal(t, producerCount, remaining.Load(), "No queueProducer request should return before an output is set") + assert.Equal(t, int64(producerCount), remaining.Load(), "No queueProducer request should return before an output is set") // Set the output, then ensure that it unblocks all the waiting goroutines. controller.Set(outputs.Group{ diff --git a/libbeat/publisher/pipeline/pipeline.go b/libbeat/publisher/pipeline/pipeline.go index a5a13a0584ea..6297f7b7ee64 100644 --- a/libbeat/publisher/pipeline/pipeline.go +++ b/libbeat/publisher/pipeline/pipeline.go @@ -26,7 +26,6 @@ import ( "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/beats/v7/libbeat/common/acker" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/libbeat/common/reload" "github.com/elastic/beats/v7/libbeat/outputs" "github.com/elastic/beats/v7/libbeat/publisher" @@ -211,13 +210,13 @@ func (p *Pipeline) ConnectWith(cfg beat.ClientConfig) (beat.Client, error) { client := &client{ logger: p.monitors.Logger, - isOpen: atomic.MakeBool(true), clientListener: cfg.ClientListener, processors: processors, eventFlags: eventFlags, canDrop: canDrop, observer: p.observer, } + client.isOpen.Store(true) ackHandler := cfg.EventListener diff --git a/libbeat/publisher/pipeline/pipeline_test.go b/libbeat/publisher/pipeline/pipeline_test.go index a8cf34b895aa..bd374c3c87bd 100644 --- a/libbeat/publisher/pipeline/pipeline_test.go +++ b/libbeat/publisher/pipeline/pipeline_test.go @@ -20,10 +20,10 @@ package pipeline import ( "runtime" "sync" + "sync/atomic" "testing" "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/libbeat/publisher/queue" "github.com/elastic/beats/v7/libbeat/tests/resources" "github.com/elastic/elastic-agent-libs/mapstr" @@ -79,7 +79,7 @@ func TestPipelineAcceptsAnyNumberOfClients(t *testing.T) { // close method is called, this ID is returned func makeDiscardQueue() queue.Queue { var wg sync.WaitGroup - producerID := atomic.NewInt(0) + var producerID atomic.Int64 return &testQueue{ close: func() error { @@ -92,7 +92,7 @@ func makeDiscardQueue() queue.Queue { }, producer: func(cfg queue.ProducerConfig) queue.Producer { - producerID.Inc() + producerID.Add(1) // count is a counter that increments on every published event // it's also the returned Event ID @@ -231,11 +231,11 @@ func makeTestQueue() queue.Queue { func blockingProducer(_ queue.ProducerConfig) queue.Producer { sig := make(chan struct{}) - waiting := atomic.MakeInt(0) + var waiting atomic.Int64 return &testProducer{ publish: func(_ bool, _ queue.Entry) (queue.EntryID, bool) { - waiting.Inc() + waiting.Add(1) <-sig return 0, false }, diff --git a/libbeat/publisher/pipeline/stress/gen.go b/libbeat/publisher/pipeline/stress/gen.go index 2a4d8c72ef0a..7fdf17bd27b0 100644 --- a/libbeat/publisher/pipeline/stress/gen.go +++ b/libbeat/publisher/pipeline/stress/gen.go @@ -22,6 +22,7 @@ import ( "fmt" "runtime/pprof" "sync" + "sync/atomic" "time" "github.com/elastic/elastic-agent-libs/logp" @@ -29,7 +30,6 @@ import ( "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/beats/v7/libbeat/common/acker" - "github.com/elastic/beats/v7/libbeat/common/atomic" ) type generateConfig struct { @@ -97,7 +97,7 @@ func generate( done := make(chan struct{}) defer close(done) - count := atomic.MakeUint64(0) + var count atomic.Uint64 var wg sync.WaitGroup defer wg.Wait() @@ -148,7 +148,7 @@ func generate( Fields: mapstr.M{ "id": id, "hello": "world", - "count": count, + "count": count.Load(), // TODO: more custom event generation? }, @@ -156,7 +156,7 @@ func generate( client.Publish(event) - total := count.Inc() + total := count.Add(1) if config.MaxEvents > 0 && total == config.MaxEvents { break } diff --git a/libbeat/publisher/pipeline/stress/sig.go b/libbeat/publisher/pipeline/stress/sig.go index 537fc9c633bb..d6d03f0c3d13 100644 --- a/libbeat/publisher/pipeline/stress/sig.go +++ b/libbeat/publisher/pipeline/stress/sig.go @@ -17,7 +17,7 @@ package stress -import "github.com/elastic/beats/v7/libbeat/common/atomic" +import "sync/atomic" type closeSignaler struct { active atomic.Bool @@ -25,14 +25,15 @@ type closeSignaler struct { } func newCloseSignaler() *closeSignaler { - return &closeSignaler{ - active: atomic.MakeBool(true), - done: make(chan struct{}), + cs := &closeSignaler{ + done: make(chan struct{}), } + cs.active.Store(true) + return cs } func (s *closeSignaler) Close() { - if act := s.active.Swap(false); act { + if s.active.Swap(false) { close(s.done) } } diff --git a/libbeat/publisher/pipeline/sync_client.go b/libbeat/publisher/pipeline/sync_client.go deleted file mode 100644 index 9dcf69ff1550..000000000000 --- a/libbeat/publisher/pipeline/sync_client.go +++ /dev/null @@ -1,106 +0,0 @@ -// 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 pipeline - -import ( - "sync" - - "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/common/acker" - "github.com/elastic/beats/v7/libbeat/publisher/pipetool" - "github.com/elastic/elastic-agent-libs/logp" -) - -// Client implements the interface used by all the functionbeat function, we only implement a synchronous -// client. This interface superseed the core beat.Client interface and can return errors on publish. -type ISyncClient interface { - // Publish accepts a unique events and will publish it to the pipeline. - Publish(beat.Event) error - - // PublishAll accepts a list of multiple events and will publish them to the pipeline. - PublishAll([]beat.Event) error - - // Close closes the current client, no events will be accepted, this method can block if we still - // need to ACK on events. - Close() error - - // Wait blocks until the publisher pipeline send the ACKS for all the events. - Wait() -} - -// SyncClient wraps an existing beat.Client and provide a sync interface. -type SyncClient struct { - client beat.Client - wg sync.WaitGroup - log *logp.Logger -} - -// NewSyncClient creates a new sync clients from the provided configuration, existing ACKs handlers -// defined in the configuration will be proxied by this object. -func NewSyncClient(log *logp.Logger, pipeline beat.Pipeline, cfg beat.ClientConfig) (*SyncClient, error) { - if log == nil { - log = logp.NewLogger("") - } - s := &SyncClient{log: log.Named("sync client")} - - pipeline = pipetool.WithACKer(pipeline, acker.TrackingCounter(func(_, total int) { - log.Debugf("ack callback receives with events count of %d", total) - s.onACK(total) - })) - - c, err := pipeline.ConnectWith(cfg) - if err != nil { - return nil, err - } - - s.client = c - - return s, nil -} - -// Publish publishes one event to the pipeline and return. -func (s *SyncClient) Publish(event beat.Event) error { - s.log.Debug("Publish 1 event") - s.wg.Add(1) - s.client.Publish(event) - return nil -} - -// PublishAll publish a slice of events to the pipeline and return. -func (s *SyncClient) PublishAll(events []beat.Event) error { - s.log.Debugf("Publish %d events", len(events)) - s.wg.Add(len(events)) - s.client.PublishAll(events) - return nil -} - -// Close closes the wrapped beat.Client. -func (s *SyncClient) Close() error { - s.wg.Wait() - return s.client.Close() -} - -// Wait waits until we received a ACK for every events that were sent, this is useful in the -// context of serverless, because when the handler return the execution of the process is suspended. -func (s *SyncClient) Wait() { - s.wg.Wait() -} - -func (s *SyncClient) onACK(n int) { - s.wg.Add(-1 * n) -} diff --git a/libbeat/publisher/pipeline/sync_client_test.go b/libbeat/publisher/pipeline/sync_client_test.go deleted file mode 100644 index 09eac919bd52..000000000000 --- a/libbeat/publisher/pipeline/sync_client_test.go +++ /dev/null @@ -1,132 +0,0 @@ -// 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 pipeline - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/elastic/beats/v7/libbeat/beat" -) - -type dummyClient struct { - Received chan int -} - -func newDummyClient() *dummyClient { - return &dummyClient{Received: make(chan int)} -} - -func (c *dummyClient) Publish(event beat.Event) { - c.Received <- 1 -} - -func (c *dummyClient) PublishAll(events []beat.Event) { - c.Received <- len(events) -} - -func (c *dummyClient) Close() error { - close(c.Received) - return nil -} - -type dummyPipeline struct { - client beat.Client -} - -func newDummyPipeline(client beat.Client) *dummyPipeline { - return &dummyPipeline{client: client} -} - -func (d *dummyPipeline) Connect() (beat.Client, error) { - return d.client, nil -} - -func (d *dummyPipeline) ConnectWith(cfg beat.ClientConfig) (beat.Client, error) { - return d.client, nil -} - -func TestSyncClient(t *testing.T) { - receiver := func(c *dummyClient, sc *SyncClient) { - i := <-c.Received - sc.onACK(i) - } - - t.Run("Publish", func(t *testing.T) { - c := newDummyClient() - - pipeline := newDummyPipeline(c) - sc, err := NewSyncClient(nil, pipeline, beat.ClientConfig{}) - if !assert.NoError(t, err) { - return - } - defer sc.Close() - - go receiver(c, sc) - - err = sc.Publish(beat.Event{}) - if !assert.NoError(t, err) { - return - } - sc.Wait() - }) - - t.Run("PublishAll single ACK", func(t *testing.T) { - c := newDummyClient() - - pipeline := newDummyPipeline(c) - sc, err := NewSyncClient(nil, pipeline, beat.ClientConfig{}) - if !assert.NoError(t, err) { - return - } - defer sc.Close() - - go receiver(c, sc) - - err = sc.PublishAll(make([]beat.Event, 10)) - if !assert.NoError(t, err) { - return - } - sc.Wait() - }) - - t.Run("PublishAll multiple independent ACKs", func(t *testing.T) { - c := newDummyClient() - - pipeline := newDummyPipeline(c) - sc, err := NewSyncClient(nil, pipeline, beat.ClientConfig{}) - if !assert.NoError(t, err) { - return - } - defer sc.Close() - - go func(c *dummyClient, sc *SyncClient) { - <-c.Received - // simulate multiple acks - sc.onACK(5) - sc.onACK(5) - }(c, sc) - - err = sc.PublishAll(make([]beat.Event, 10)) - if !assert.NoError(t, err) { - return - } - sc.Wait() - }) -} diff --git a/libbeat/publisher/testing/connector.go b/libbeat/publisher/testing/connector.go index ddf48cc126f9..967f86ebe28a 100644 --- a/libbeat/publisher/testing/connector.go +++ b/libbeat/publisher/testing/connector.go @@ -18,15 +18,16 @@ package testing import ( + "sync/atomic" + "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/common/atomic" ) // ClientCounter can be used to create a beat.PipelineConnector that count // pipeline connects and disconnects. type ClientCounter struct { - total atomic.Int - active atomic.Int + total atomic.Int64 + active atomic.Int64 } // FakeConnector implements the beat.PipelineConnector interface. @@ -111,21 +112,21 @@ func ChClient(ch chan beat.Event) beat.Client { } // Active returns the number of currently active connections. -func (c *ClientCounter) Active() int { return c.active.Load() } +func (c *ClientCounter) Active() int { return int(c.active.Load()) } // Total returns the total number of calls to Connect. -func (c *ClientCounter) Total() int { return c.total.Load() } +func (c *ClientCounter) Total() int { return int(c.total.Load()) } // BuildConnector create a pipeline that updates the active and tocal // connection counters on Connect and Close calls. func (c *ClientCounter) BuildConnector() beat.PipelineConnector { return FakeConnector{ ConnectFunc: func(_ beat.ClientConfig) (beat.Client, error) { - c.total.Inc() - c.active.Inc() + c.total.Add(1) + c.active.Add(1) return &FakeClient{ CloseFunc: func() error { - c.active.Dec() + c.active.Add(-1) return nil }, }, nil diff --git a/libbeat/tests/integration/framework.go b/libbeat/tests/integration/framework.go index 904fc1e302a9..aa05d6ff0e6b 100644 --- a/libbeat/tests/integration/framework.go +++ b/libbeat/tests/integration/framework.go @@ -37,13 +37,12 @@ import ( "strconv" "strings" "sync" + "sync/atomic" "testing" "time" "github.com/gofrs/uuid/v5" "github.com/stretchr/testify/require" - - "github.com/elastic/beats/v7/libbeat/common/atomic" ) type BeatProc struct { @@ -189,7 +188,7 @@ func (b *BeatProc) Start(args ...string) { b.fullPath = fullPath b.Args = append(b.baseArgs, args...) - done := atomic.MakeBool(false) + var done atomic.Bool wg := sync.WaitGroup{} if b.RestartOnBeatOnExit { wg.Add(1) diff --git a/libbeat/tests/integration/kafka_test.go b/libbeat/tests/integration/kafka_test.go new file mode 100644 index 000000000000..ceaf75b01121 --- /dev/null +++ b/libbeat/tests/integration/kafka_test.go @@ -0,0 +1,89 @@ +// 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. + +//go:build integration + +package integration + +import ( + "fmt" + "testing" + "time" + + "github.com/elastic/sarama" +) + +var ( + // https://github.com/elastic/sarama/blob/c7eabfcee7e5bcd7d0071f0ece4d6bec8c33928a/config_test.go#L14-L17 + // The version of MockBroker used when this test was written only supports the lowest protocol version by default. + // Version incompatibilities will result in message decoding errors between the mock and the beat. + kafkaVersion = sarama.MinVersion + kafkaTopic = "test_topic" + kafkaCfg = ` +mockbeat: +logging: + level: debug + selectors: + - publisher_pipeline_output + - kafka +queue.mem: + events: 4096 + flush.timeout: 0s +output.kafka: + topic: %s + version: %s + hosts: + - %s + backoff: + init: 0.1s + max: 0.2s +` +) + +// TestKafkaOutputCanConnectAndPublish ensures the beat Kafka output can successfully produce messages to Kafka. +// Regression test for https://github.com/elastic/beats/issues/41823 where the Kafka output would +// panic on the first Publish because it's Connect method was no longer called. +func TestKafkaOutputCanConnectAndPublish(t *testing.T) { + // Create a Mock Kafka broker that will listen on localhost on a random unallocated port. + // The reference configuration was taken from https://github.com/elastic/sarama/blob/c7eabfcee7e5bcd7d0071f0ece4d6bec8c33928a/async_producer_test.go#L141. + leader := sarama.NewMockBroker(t, 1) + defer leader.Close() + + // The mock broker must respond to a single metadata request. + metadataResponse := new(sarama.MetadataResponse) + metadataResponse.AddBroker(leader.Addr(), leader.BrokerID()) + metadataResponse.AddTopicPartition(kafkaTopic, 0, leader.BrokerID(), nil, nil, nil, sarama.ErrNoError) + leader.Returns(metadataResponse) + + // The mock broker must return a single produce response. If no produce request is received, the test will fail. + // This guarantees that mockbeat successfully produced a message to Kafka and connectivity is established. + prodSuccess := new(sarama.ProduceResponse) + prodSuccess.AddTopicPartition(kafkaTopic, 0, sarama.ErrNoError) + leader.Returns(prodSuccess) + + // Start mockbeat with the appropriate configuration. + mockbeat := NewBeat(t, "mockbeat", "../../libbeat.test") + mockbeat.WriteConfigFile(fmt.Sprintf(kafkaCfg, kafkaTopic, kafkaVersion, leader.Addr())) + mockbeat.Start() + + // Wait for mockbeat to log that it successfully published a batch to Kafka. + // This ensures that mockbeat received the expected produce response configured above. + mockbeat.WaitForLogs( + `finished kafka batch`, + 10*time.Second, + "did not find finished batch log") +} diff --git a/metricbeat/autodiscover/appender/kubernetes/token/token_test.go b/metricbeat/autodiscover/appender/kubernetes/token/token_test.go index aacf10b6bd0b..1fd500667992 100644 --- a/metricbeat/autodiscover/appender/kubernetes/token/token_test.go +++ b/metricbeat/autodiscover/appender/kubernetes/token/token_test.go @@ -31,6 +31,8 @@ import ( func TestMain(m *testing.M) { InitializeModule() + + os.Exit(m.Run()) } func TestTokenAppender(t *testing.T) { diff --git a/metricbeat/autodiscover/builder/hints/metrics_test.go b/metricbeat/autodiscover/builder/hints/metrics_test.go index fb0980450bd8..4cede2536eba 100644 --- a/metricbeat/autodiscover/builder/hints/metrics_test.go +++ b/metricbeat/autodiscover/builder/hints/metrics_test.go @@ -34,6 +34,8 @@ import ( func TestMain(m *testing.M) { InitializeModule() + + os.Exit(m.Run()) } func TestGenerateHints(t *testing.T) { diff --git a/metricbeat/cmd/root.go b/metricbeat/cmd/root.go index 497b71bed8ad..872f05b8b356 100644 --- a/metricbeat/cmd/root.go +++ b/metricbeat/cmd/root.go @@ -43,9 +43,6 @@ const ( Name = "metricbeat" ) -// RootCmd to handle beats cli -var RootCmd *cmd.BeatsRootCmd - // withECSVersion is a modifier that adds ecs.version to events. var withECSVersion = processing.WithFields(mapstr.M{ "ecs": mapstr.M{ @@ -60,7 +57,7 @@ func MetricbeatSettings(moduleNameSpace string) instance.Settings { if moduleNameSpace == "" { moduleNameSpace = "module" } - var runFlags = pflag.NewFlagSet(Name, pflag.ExitOnError) + runFlags := pflag.NewFlagSet(Name, pflag.ExitOnError) runFlags.AddGoFlag(flag.CommandLine.Lookup("system.hostfs")) cfgfile.AddAllowedBackwardsCompatibleFlag("system.hostfs") return instance.Settings{ @@ -82,7 +79,3 @@ func Initialize(settings instance.Settings) *cmd.BeatsRootCmd { rootCmd.TestCmd.AddCommand(test.GenTestModulesCmd(Name, "", beater.DefaultTestModulesCreator())) return rootCmd } - -func init() { - RootCmd = Initialize(MetricbeatSettings("")) -} diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index eaef6fe9d014..f750552fb80a 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -23,6 +23,7 @@ grouped in the following categories: * <> * <> * <> +* <> * <> * <> * <> @@ -67,6 +68,7 @@ grouped in the following categories: * <> * <> * <> +* <> * <> * <> * <> @@ -10473,6 +10475,36 @@ type: long -- +[[exported-fields-benchmark]] +== Benchmark fields + +benchmark module + + + +[float] +=== benchmark + + + + +[float] +=== info + +info + + + +*`benchmark.info.counter`*:: ++ +-- +The nth info metric emitted by the benchmark module + + +type: keyword + +-- + [[exported-fields-ceph]] == Ceph fields @@ -32131,6 +32163,27 @@ type: keyword -- +*`elasticsearch.index.tier_preference`*:: ++ +-- +type: keyword + +-- + +*`elasticsearch.index.creation_date`*:: ++ +-- +type: date + +-- + +*`elasticsearch.index.version`*:: ++ +-- +type: keyword + +-- + *`elasticsearch.index.name`*:: + -- @@ -56655,6 +56708,372 @@ type: long -- +[[exported-fields-openai]] +== openai fields + +openai module + + + +[float] +=== openai + + + + +[float] +=== usage + +OpenAI API usage metrics and statistics + + + +*`openai.usage.organization_id`*:: ++ +-- +Organization identifier + +type: keyword + +-- + +*`openai.usage.organization_name`*:: ++ +-- +Organization name + +type: keyword + +-- + +*`openai.usage.api_key_id`*:: ++ +-- +API key identifier + +type: keyword + +-- + +*`openai.usage.api_key_name`*:: ++ +-- +API key name + +type: keyword + +-- + +*`openai.usage.api_key_redacted`*:: ++ +-- +Redacted API key + +type: keyword + +-- + +*`openai.usage.api_key_type`*:: ++ +-- +Type of API key + +type: keyword + +-- + +*`openai.usage.project_id`*:: ++ +-- +Project identifier + +type: keyword + +-- + +*`openai.usage.project_name`*:: ++ +-- +Project name + +type: keyword + +-- + +[float] +=== data + +General usage data metrics + + + +*`openai.usage.data.requests_total`*:: ++ +-- +Number of requests made + +type: long + +-- + +*`openai.usage.data.operation`*:: ++ +-- +Operation type + +type: keyword + +-- + +*`openai.usage.data.snapshot_id`*:: ++ +-- +Snapshot identifier + +type: keyword + +-- + +*`openai.usage.data.context_tokens_total`*:: ++ +-- +Total number of context tokens used + +type: long + +-- + +*`openai.usage.data.generated_tokens_total`*:: ++ +-- +Total number of generated tokens + +type: long + +-- + +*`openai.usage.data.cached_context_tokens_total`*:: ++ +-- +Total number of cached context tokens + +type: long + +-- + +*`openai.usage.data.email`*:: ++ +-- +User email + +type: keyword + +-- + +*`openai.usage.data.request_type`*:: ++ +-- +Type of request + +type: keyword + +-- + +[float] +=== dalle + +DALL-E API usage metrics + + + +*`openai.usage.dalle.num_images`*:: ++ +-- +Number of images generated + +type: long + +-- + +*`openai.usage.dalle.requests_total`*:: ++ +-- +Number of requests + +type: long + +-- + +*`openai.usage.dalle.image_size`*:: ++ +-- +Size of generated images + +type: keyword + +-- + +*`openai.usage.dalle.operation`*:: ++ +-- +Operation type + +type: keyword + +-- + +*`openai.usage.dalle.user_id`*:: ++ +-- +User identifier + +type: keyword + +-- + +*`openai.usage.dalle.model_id`*:: ++ +-- +Model identifier + +type: keyword + +-- + +[float] +=== whisper + +Whisper API usage metrics + + + +*`openai.usage.whisper.model_id`*:: ++ +-- +Model identifier + +type: keyword + +-- + +*`openai.usage.whisper.num_seconds`*:: ++ +-- +Number of seconds processed + +type: long + +-- + +*`openai.usage.whisper.requests_total`*:: ++ +-- +Number of requests + +type: long + +-- + +*`openai.usage.whisper.user_id`*:: ++ +-- +User identifier + +type: keyword + +-- + +[float] +=== tts + +Text-to-Speech API usage metrics + + + +*`openai.usage.tts.model_id`*:: ++ +-- +Model identifier + +type: keyword + +-- + +*`openai.usage.tts.num_characters`*:: ++ +-- +Number of characters processed + +type: long + +-- + +*`openai.usage.tts.requests_total`*:: ++ +-- +Number of requests + +type: long + +-- + +*`openai.usage.tts.user_id`*:: ++ +-- +User identifier + +type: keyword + +-- + +[float] +=== ft_data + +Fine-tuning data metrics + + + +*`openai.usage.ft_data.original`*:: ++ +-- +Raw fine-tuning data + +type: object + +-- + +[float] +=== assistant_code_interpreter + +Assistant Code Interpreter usage metrics + + + +*`openai.usage.assistant_code_interpreter.original`*:: ++ +-- +Raw assistant code interpreter data + +type: object + +-- + +[float] +=== retrieval_storage + +Retrieval storage usage metrics + + + +*`openai.usage.retrieval_storage.original`*:: ++ +-- +Raw retrieval storage data + +type: object + +-- + [[exported-fields-openmetrics]] == Openmetrics fields diff --git a/metricbeat/docs/modules/benchmark.asciidoc b/metricbeat/docs/modules/benchmark.asciidoc new file mode 100644 index 000000000000..01c950c84d41 --- /dev/null +++ b/metricbeat/docs/modules/benchmark.asciidoc @@ -0,0 +1,76 @@ +//// +This file is generated! See scripts/mage/docs_collector.go +//// + +:modulename: benchmark +:edit_url: https://github.com/elastic/beats/edit/main/x-pack/metricbeat/module/benchmark/_meta/docs.asciidoc + + +[[metricbeat-module-benchmark]] +[role="xpack"] +== Benchmark module + +beta[] + +include::{libbeat-dir}/shared/integration-link.asciidoc[] + +:modulename!: + +The `benchmark` module is used to generate synthetic metrics at a predictable rate. This can be useful when you want to test output settings or test system sizing without using real data. + +The `benchmark` module metricset is `info`. + +[source,yaml] +---- +- module: benchmark + metricsets: + - info + enabled: true + period: 10s +---- + +[float] +== Metricsets + +[float] +=== `info` +A metric that includes a `counter` field which is used to keep the metric unique. + +[float] +=== Module-specific configuration notes + +`count`:: number, the number of metrics to emit per fetch. + + + + + +:edit_url: + +[float] +=== Example configuration + +The Benchmark module supports the standard configuration options that are described +in <>. Here is an example configuration: + +[source,yaml] +---- +metricbeat.modules: +- module: benchmark + metricsets: + - info + enabled: false + period: 10s + +---- + +[float] +=== Metricsets + +The following metricsets are available: + +* <> + +include::benchmark/info.asciidoc[] + +:edit_url!: diff --git a/metricbeat/docs/modules/benchmark/info.asciidoc b/metricbeat/docs/modules/benchmark/info.asciidoc new file mode 100644 index 000000000000..4f6cee9874ff --- /dev/null +++ b/metricbeat/docs/modules/benchmark/info.asciidoc @@ -0,0 +1,29 @@ +//// +This file is generated! See scripts/mage/docs_collector.go +//// +:edit_url: https://github.com/elastic/beats/edit/main/x-pack/metricbeat/module/benchmark/info/_meta/docs.asciidoc + + +[[metricbeat-metricset-benchmark-info]] +[role="xpack"] +=== Benchmark info metricset + +beta[] + +include::../../../../x-pack/metricbeat/module/benchmark/info/_meta/docs.asciidoc[] + + +:edit_url: + +==== Fields + +For a description of each field in the metricset, see the +<> section. + +Here is an example document generated by this metricset: + +[source,json] +---- +include::../../../../x-pack/metricbeat/module/benchmark/info/_meta/data.json[] +---- +:edit_url!: \ No newline at end of file diff --git a/metricbeat/docs/modules/docker.asciidoc b/metricbeat/docs/modules/docker.asciidoc index cd5e2a207a83..a8ae9cbf4882 100644 --- a/metricbeat/docs/modules/docker.asciidoc +++ b/metricbeat/docs/modules/docker.asciidoc @@ -22,6 +22,9 @@ The Docker module is currently tested on Linux and Mac with the community edition engine, versions 1.11 and 17.09.0-ce. It is not tested on Windows, but it should also work there. +The Docker module supports collection of metrics from Podman's Docker-compatible API. +It has been tested on Linux and Mac with Podman Rest API v2.0.0 and above. + [float] === Module-specific configuration notes @@ -30,6 +33,9 @@ It is strongly recommended that you run Docker metricsets with a Docker API already takes up to 2 seconds. Specifying less than 3 seconds will result in requests that timeout, and no data will be reported for those requests. +In the case of Podman, the configuration parameter `podman` should be set to `true`. +This enables streaming of container stats output, which allows for more accurate +CPU percentage calculations when using Podman. :edit_url: @@ -62,6 +68,9 @@ metricbeat.modules: # If set to true, replace dots in labels with `_`. #labels.dedot: false + # Docker module supports metrics collection from podman's docker compatible API. In case of podman set to true. + # podman: false + # Skip metrics for certain device major numbers in docker/diskio. # Necessary on systems with software RAID, device mappers, # or other configurations where virtual disks will sum metrics from other disks. diff --git a/metricbeat/docs/modules/gcp.asciidoc b/metricbeat/docs/modules/gcp.asciidoc index 00c1536e5c04..11f3b14eaff0 100644 --- a/metricbeat/docs/modules/gcp.asciidoc +++ b/metricbeat/docs/modules/gcp.asciidoc @@ -346,6 +346,7 @@ metricbeat.modules: credentials_file_path: "your JSON credentials file path" exclude_labels: false period: 1m + location_label: "resource.labels.zone" metrics: - aligner: ALIGN_NONE service: compute diff --git a/metricbeat/docs/modules/openai.asciidoc b/metricbeat/docs/modules/openai.asciidoc new file mode 100644 index 000000000000..ce5fd3e0ccc5 --- /dev/null +++ b/metricbeat/docs/modules/openai.asciidoc @@ -0,0 +1,75 @@ +//// +This file is generated! See scripts/mage/docs_collector.go +//// + +:modulename: openai +:edit_url: https://github.com/elastic/beats/edit/main/x-pack/metricbeat/module/openai/_meta/docs.asciidoc + + +[[metricbeat-module-openai]] +[role="xpack"] +== openai module + +beta[] + +This is the openai module. + + + +:edit_url: + +[float] +=== Example configuration + +The openai module supports the standard configuration options that are described +in <>. Here is an example configuration: + +[source,yaml] +---- +metricbeat.modules: +- module: openai + metricsets: ["usage"] + enabled: false + period: 1h + + # # Project API Keys - Multiple API keys can be specified for different projects + # api_keys: + # - key: "api_key1" + # - key: "api_key2" + + # # API Configuration + # ## Base URL for the OpenAI usage API endpoint + # api_url: "https://api.openai.com/v1/usage" + # ## Custom headers to be included in API requests + # headers: + # - "k1: v1" + # - "k2: v2" + ## Rate Limiting Configuration + # rate_limit: + # limit: 12 # seconds between requests + # burst: 1 # max concurrent requests + # ## Request Timeout Duration + # timeout: 30s + + # # Data Collection Configuration + # collection: + # ## Number of days to look back when collecting usage data + # lookback_days: 30 + # ## Whether to collect usage data in realtime. Defaults to false as how + # # OpenAI usage data is collected will end up adding duplicate data to ES + # # and also making it harder to do analytics. Best approach is to avoid + # # realtime collection and collect only upto last day (in UTC). So, there's + # # at most 24h delay. + # realtime: false +---- + +[float] +=== Metricsets + +The following metricsets are available: + +* <> + +include::openai/usage.asciidoc[] + +:edit_url!: diff --git a/metricbeat/docs/modules/openai/usage.asciidoc b/metricbeat/docs/modules/openai/usage.asciidoc new file mode 100644 index 000000000000..69d0ba313d9c --- /dev/null +++ b/metricbeat/docs/modules/openai/usage.asciidoc @@ -0,0 +1,29 @@ +//// +This file is generated! See scripts/mage/docs_collector.go +//// +:edit_url: https://github.com/elastic/beats/edit/main/x-pack/metricbeat/module/openai/usage/_meta/docs.asciidoc + + +[[metricbeat-metricset-openai-usage]] +[role="xpack"] +=== openai usage metricset + +beta[] + +include::../../../../x-pack/metricbeat/module/openai/usage/_meta/docs.asciidoc[] + + +:edit_url: + +==== Fields + +For a description of each field in the metricset, see the +<> section. + +Here is an example document generated by this metricset: + +[source,json] +---- +include::../../../../x-pack/metricbeat/module/openai/usage/_meta/data.json[] +---- +:edit_url!: \ No newline at end of file diff --git a/metricbeat/docs/modules/system.asciidoc b/metricbeat/docs/modules/system.asciidoc index 2fc3930d8444..164abe5c91e3 100644 --- a/metricbeat/docs/modules/system.asciidoc +++ b/metricbeat/docs/modules/system.asciidoc @@ -265,6 +265,11 @@ metricbeat.modules: # Filter systemd services based on a name pattern #service.pattern_filter: ["ssh*", "nfs*"] + + # This option enables the use of performance counters to collect data for cpu/core metricset. + # Only effective for Windows. + # You should use this option if running beats on machins with more than 64 cores. + #use_performance_counters: true ---- [float] diff --git a/metricbeat/docs/modules_list.asciidoc b/metricbeat/docs/modules_list.asciidoc index c3048e4b6a51..0d30fc98ae4a 100644 --- a/metricbeat/docs/modules_list.asciidoc +++ b/metricbeat/docs/modules_list.asciidoc @@ -51,6 +51,8 @@ This file is generated! See scripts/mage/docs_collector.go |<> |image:./images/icon-no.png[No prebuilt dashboards] | .2+| .2+| |<> |<> +|<> beta[] |image:./images/icon-no.png[No prebuilt dashboards] | +.1+| .1+| |<> beta[] |<> |image:./images/icon-yes.png[Prebuilt dashboards are available] | .13+| .13+| |<> |<> @@ -240,6 +242,8 @@ This file is generated! See scripts/mage/docs_collector.go |<> |<> |image:./images/icon-yes.png[Prebuilt dashboards are available] | .1+| .1+| |<> +|<> beta[] |image:./images/icon-no.png[No prebuilt dashboards] | +.1+| .1+| |<> beta[] |<> beta[] |image:./images/icon-no.png[No prebuilt dashboards] | .1+| .1+| |<> beta[] |<> |image:./images/icon-yes.png[Prebuilt dashboards are available] | @@ -349,6 +353,7 @@ include::modules/aws.asciidoc[] include::modules/awsfargate.asciidoc[] include::modules/azure.asciidoc[] include::modules/beat.asciidoc[] +include::modules/benchmark.asciidoc[] include::modules/ceph.asciidoc[] include::modules/cloudfoundry.asciidoc[] include::modules/cockroachdb.asciidoc[] @@ -386,6 +391,7 @@ include::modules/munin.asciidoc[] include::modules/mysql.asciidoc[] include::modules/nats.asciidoc[] include::modules/nginx.asciidoc[] +include::modules/openai.asciidoc[] include::modules/openmetrics.asciidoc[] include::modules/oracle.asciidoc[] include::modules/panw.asciidoc[] diff --git a/metricbeat/helper/sql/sql.go b/metricbeat/helper/sql/sql.go index a0d4ebbd36be..d06fd766f92c 100644 --- a/metricbeat/helper/sql/sql.go +++ b/metricbeat/helper/sql/sql.go @@ -21,11 +21,11 @@ import ( "context" "database/sql" "fmt" - "strconv" - "strings" "time" + "strings" + "github.com/elastic/elastic-agent-libs/logp" "github.com/elastic/elastic-agent-libs/mapstr" ) @@ -114,7 +114,7 @@ func (d *DbClient) fetchTableMode(rows sqlRow) ([]mapstr.M, error) { return rr, nil } -// fetchTableMode scan the rows and publishes the event for querys that return the response in a table format. +// FetchVariableMode executes the provided SQL query and returns the results in a key/value format. func (d *DbClient) FetchVariableMode(ctx context.Context, q string) (mapstr.M, error) { rows, err := d.QueryContext(ctx, q) if err != nil { @@ -123,7 +123,7 @@ func (d *DbClient) FetchVariableMode(ctx context.Context, q string) (mapstr.M, e return d.fetchVariableMode(rows) } -// fetchVariableMode scan the rows and publishes the event for querys that return the response in a key/value format. +// fetchVariableMode scans the provided SQL rows and returns the results in a key/value format. func (d *DbClient) fetchVariableMode(rows sqlRow) (mapstr.M, error) { data := mapstr.M{} @@ -167,24 +167,25 @@ func ReplaceUnderscores(ms mapstr.M) mapstr.M { } func getValue(pval *interface{}) interface{} { + if pval == nil { + return nil + } + switch v := (*pval).(type) { - case nil, bool: + case nil, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, string, []interface{}: return v case []byte: - s := string(v) - num, err := strconv.ParseFloat(s, 64) - if err == nil { - return num - } - return s + return string(v) case time.Time: return v.Format(time.RFC3339Nano) - case []interface{}: - return v default: + // For any other types, convert to string and try to parse as number s := fmt.Sprint(v) - num, err := strconv.ParseFloat(s, 64) - if err == nil { + if len(s) > 1 && s[0] == '0' && s[1] != '.' { + // Preserve string with leading zeros i.e., 00100 stays 00100 + return s + } + if num, err := strconv.ParseFloat(s, 64); err == nil { return num } return s diff --git a/metricbeat/helper/sql/sql_test.go b/metricbeat/helper/sql/sql_test.go index 783fff993a2c..b94a04526578 100644 --- a/metricbeat/helper/sql/sql_test.go +++ b/metricbeat/helper/sql/sql_test.go @@ -22,7 +22,7 @@ import ( "database/sql" "database/sql/driver" "fmt" - "math" + "strconv" "testing" "time" @@ -43,10 +43,10 @@ type mockVariableMode struct { } func (m *mockVariableMode) Scan(dest ...interface{}) error { - d1 := dest[0].(*string) + d1 := dest[0].(*string) //nolint:errcheck // false positive *d1 = m.results[m.index].k - d2 := dest[1].(*interface{}) + d2 := dest[1].(*interface{}) //nolint:errcheck // false positive *d2 = m.results[m.index].v m.index++ @@ -73,7 +73,7 @@ type mockTableMode struct { func (m *mockTableMode) Scan(dest ...interface{}) error { for i, d := range dest { - d1 := d.(*interface{}) + d1 := d.(*interface{}) //nolint:errcheck // false positive *d1 = m.results[i].v } @@ -87,7 +87,11 @@ func (m *mockTableMode) Next() bool { } func (m *mockTableMode) Columns() ([]string, error) { - return []string{"hello", "integer", "signed_integer", "unsigned_integer", "float64", "float32", "null", "boolean", "array", "byte_array", "time"}, nil + cols := make([]string, len(m.results)) + for i, r := range m.results { + cols[i] = r.k + } + return cols, nil } func (m mockTableMode) Err() error { @@ -95,6 +99,8 @@ func (m mockTableMode) Err() error { } var results = []kv{ + {k: "string", v: "000400"}, + {k: "varchar", v: "00100"}, {k: "hello", v: "world"}, {k: "integer", v: int(10)}, {k: "signed_integer", v: int(-10)}, @@ -137,54 +143,65 @@ func TestFetchTableMode(t *testing.T) { } func checkValue(t *testing.T, res kv, ms mapstr.M) { + t.Helper() + + actual := ms[res.k] switch v := res.v.(type) { - case string, bool: - if ms[res.k] != v { - t.Fail() + case string, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64: + if actual != v { + t.Errorf("key %q: expected %v (%T), got %v (%T)", res.k, v, v, actual, actual) } case nil: - if ms[res.k] != nil { - t.Fail() - } - case int: - if ms[res.k] != float64(v) { - t.Fail() - } - case uint: - if ms[res.k] != float64(v) { - t.Fail() - } - case float32: - if math.Abs(float64(ms[res.k].(float64)-float64(v))) > 1 { - t.Fail() - } - case float64: - if ms[res.k] != v { - t.Fail() + if actual != nil { + t.Errorf("key %q: expected nil, got %v (%T)", res.k, actual, actual) } case []interface{}: + actualSlice := actual.([]interface{}) + if len(v) != len(actualSlice) { + t.Errorf("key %q: slice length mismatch: expected %d, got %d", res.k, len(v), len(actualSlice)) + return + } for i, val := range v { - if ms[res.k].([]interface{})[i] != val { - t.Fail() + if actualSlice[i] != val { + t.Errorf("key %q: slice mismatch at index %d: expected %v, got %v", res.k, i, val, actualSlice[i]) } } case []byte: - ar := ms[res.k].(string) - if ar != string(v) { - t.Fail() + actualStr := actual.(string) + if actualStr != string(v) { + t.Errorf("key %q: expected %q (string), got %q", res.k, string(v), actualStr) } case time.Time: - ar := ms[res.k].(string) - if v.Format(time.RFC3339Nano) != ar { - t.Fail() + actualStr := actual.(string) + expectedStr := v.Format(time.RFC3339Nano) + if expectedStr != actualStr { + t.Errorf("key %q: expected time %q, got %q", res.k, expectedStr, actualStr) + } + case CustomType: + // Handle custom types that should be converted to string + expectedStr := fmt.Sprint(v) + if num, err := strconv.ParseFloat(expectedStr, 64); err == nil { + if actual != num { + t.Errorf("key %q: expected %v (float64), got %v (%T)", res.k, num, actual, actual) + } + } else { + actualStr := actual.(string) + if actualStr != expectedStr { + t.Errorf("key %q: expected %q (string), got %q", res.k, expectedStr, actualStr) + } } default: - if ms[res.k] != res.v { - t.Fail() + if actual != res.v { + t.Errorf("key %q: expected %v (%T), got %v (%T)", res.k, res.v, res.v, actual, actual) } } } +// CustomType for testing custom type handling +type CustomType struct { + value string //nolint:unused // unused checker is buggy +} + func TestToDotKeys(t *testing.T) { ms := mapstr.M{"key_value": "value"} ms = ReplaceUnderscores(ms) diff --git a/metricbeat/main.go b/metricbeat/main.go index 5dcea740b21f..8515bca79d80 100644 --- a/metricbeat/main.go +++ b/metricbeat/main.go @@ -32,7 +32,7 @@ import ( ) func main() { - if err := cmd.RootCmd.Execute(); err != nil { + if err := cmd.Initialize(cmd.MetricbeatSettings("")).Execute(); err != nil { os.Exit(1) } } diff --git a/metricbeat/main_test.go b/metricbeat/main_test.go index 495ce5787e04..be50210575e7 100644 --- a/metricbeat/main_test.go +++ b/metricbeat/main_test.go @@ -21,21 +21,27 @@ package main import ( "flag" + "os" "testing" "github.com/elastic/beats/v7/libbeat/cfgfile" + cmd "github.com/elastic/beats/v7/libbeat/cmd" "github.com/elastic/beats/v7/libbeat/tests/system/template" - "github.com/elastic/beats/v7/metricbeat/cmd" + mbcmd "github.com/elastic/beats/v7/metricbeat/cmd" ) -var systemTest *bool +var ( + systemTest *bool + mbCommand *cmd.BeatsRootCmd +) func init() { testing.Init() systemTest = flag.Bool("systemTest", false, "Set to true when running system tests") - cmd.RootCmd.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("systemTest")) + mbCommand = mbcmd.Initialize(mbcmd.MetricbeatSettings("")) + mbCommand.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("systemTest")) cfgfile.AddAllowedBackwardsCompatibleFlag("systemTest") - cmd.RootCmd.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("test.coverprofile")) + mbCommand.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("test.coverprofile")) cfgfile.AddAllowedBackwardsCompatibleFlag("test.coverprofile") } @@ -43,10 +49,12 @@ func init() { func TestSystem(t *testing.T) { cfgfile.ConvertFlagsForBackwardsCompatibility() if *systemTest { - main() + if err := mbCommand.Execute(); err != nil { + os.Exit(1) + } } } func TestTemplate(t *testing.T) { - template.TestTemplate(t, cmd.Name, false) + template.TestTemplate(t, mbCommand.Name(), false) } diff --git a/metricbeat/mb/module/runner_group_test.go b/metricbeat/mb/module/runner_group_test.go index 1d462359968e..2cd6e6cc8b5c 100644 --- a/metricbeat/mb/module/runner_group_test.go +++ b/metricbeat/mb/module/runner_group_test.go @@ -19,13 +19,13 @@ package module import ( "fmt" + "sync/atomic" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/elastic/beats/v7/libbeat/cfgfile" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/libbeat/common/diagnostics" ) @@ -55,19 +55,19 @@ func (fr *fakeRunnerDiag) Diagnostics() []diagnostics.DiagnosticSetup { type fakeRunner struct { id int - startCounter *atomic.Int - stopCounter *atomic.Int + startCounter *atomic.Int64 + stopCounter *atomic.Int64 } func (fr *fakeRunner) Start() { if fr.startCounter != nil { - fr.startCounter.Inc() + fr.startCounter.Add(1) } } func (fr *fakeRunner) Stop() { if fr.stopCounter != nil { - fr.stopCounter.Inc() + fr.stopCounter.Add(1) } } @@ -76,15 +76,14 @@ func (fr *fakeRunner) String() string { } func TestStartStop(t *testing.T) { - startCounter := atomic.NewInt(0) - stopCounter := atomic.NewInt(0) + var startCounter, stopCounter atomic.Int64 runners := make([]cfgfile.Runner, 0, fakeRunnersNum) for i := 0; i < fakeRunnersNum; i++ { runners = append(runners, &fakeRunner{ id: i, - startCounter: startCounter, - stopCounter: stopCounter, + startCounter: &startCounter, + stopCounter: &stopCounter, }) } @@ -93,8 +92,8 @@ func TestStartStop(t *testing.T) { runnerGroup.Stop() - assert.Equal(t, fakeRunnersNum, startCounter.Load()) - assert.Equal(t, fakeRunnersNum, stopCounter.Load()) + assert.Equal(t, int64(fakeRunnersNum), startCounter.Load()) + assert.Equal(t, int64(fakeRunnersNum), stopCounter.Load()) } func TestDiagnosticsUnsupported(t *testing.T) { @@ -102,8 +101,8 @@ func TestDiagnosticsUnsupported(t *testing.T) { for i := 0; i < fakeRunnersNum; i++ { runners = append(runners, &fakeRunner{ id: i, - startCounter: atomic.NewInt(0), - stopCounter: atomic.NewInt(0), + startCounter: &atomic.Int64{}, + stopCounter: &atomic.Int64{}, }) } diff --git a/metricbeat/mb/module/wrapper.go b/metricbeat/mb/module/wrapper.go index 95185817f5fb..4681976f2e14 100644 --- a/metricbeat/mb/module/wrapper.go +++ b/metricbeat/mb/module/wrapper.go @@ -36,11 +36,15 @@ import ( "github.com/elastic/elastic-agent-libs/testing" ) -// Expvar metric names. const ( - successesKey = "success" - failuresKey = "failures" - eventsKey = "events" + // Expvar metric names. + successesKey = "success" + failuresKey = "failures" + eventsKey = "events" + consecutiveFailuresKey = "consecutive_failures" + + // Failure threshold config key + failureThresholdKey = "failure_threshold" ) var ( @@ -70,16 +74,18 @@ type metricSetWrapper struct { module *Wrapper // Parent Module. stats *stats // stats for this MetricSet. - periodic bool // Set to true if this metricset is a periodic fetcher + periodic bool // Set to true if this metricset is a periodic fetcher + failureThreshold uint // threshold of consecutive errors needed to set the stream as degraded } // stats bundles common metricset stats. type stats struct { - key string // full stats key - ref uint32 // number of modules/metricsets reusing stats instance - success *monitoring.Int // Total success events. - failures *monitoring.Int // Total error events. - events *monitoring.Int // Total events published. + key string // full stats key + ref uint32 // number of modules/metricsets reusing stats instance + success *monitoring.Int // Total success events. + failures *monitoring.Int // Total error events. + events *monitoring.Int // Total events published. + consecutiveFailures *monitoring.Uint // Consecutive failures fetching this metricset } // NewWrapper creates a new module and its associated metricsets based on the given configuration. @@ -106,11 +112,28 @@ func createWrapper(module mb.Module, metricSets []mb.MetricSet, options ...Optio applyOption(wrapper) } + failureThreshold := uint(1) + + var streamHealthSettings struct { + FailureThreshold *uint `config:"failure_threshold"` + } + + err := module.UnpackConfig(&streamHealthSettings) + + if err != nil { + return nil, fmt.Errorf("unpacking raw config: %w", err) + } + + if streamHealthSettings.FailureThreshold != nil { + failureThreshold = *streamHealthSettings.FailureThreshold + } + for i, metricSet := range metricSets { wrapper.metricSets[i] = &metricSetWrapper{ - MetricSet: metricSet, - module: wrapper, - stats: getMetricSetStats(wrapper.Name(), metricSet.Name()), + MetricSet: metricSet, + module: wrapper, + stats: getMetricSetStats(wrapper.Name(), metricSet.Name()), + failureThreshold: failureThreshold, } } return wrapper, nil @@ -254,35 +277,11 @@ func (msw *metricSetWrapper) fetch(ctx context.Context, reporter reporter) { case mb.ReportingMetricSetV2Error: reporter.StartFetchTimer() err := fetcher.Fetch(reporter.V2()) - if err != nil { - reporter.V2().Error(err) - if errors.As(err, &mb.PartialMetricsError{}) { - // mark module as running if metrics are partially available and display the error message - msw.module.UpdateStatus(status.Running, fmt.Sprintf("Error fetching data for metricset %s.%s: %v", msw.module.Name(), msw.MetricSet.Name(), err)) - } else { - // mark it as degraded for any other issue encountered - msw.module.UpdateStatus(status.Degraded, fmt.Sprintf("Error fetching data for metricset %s.%s: %v", msw.module.Name(), msw.MetricSet.Name(), err)) - } - logp.Err("Error fetching data for metricset %s.%s: %s", msw.module.Name(), msw.Name(), err) - } else { - msw.module.UpdateStatus(status.Running, "") - } + msw.handleFetchError(err, reporter.V2()) case mb.ReportingMetricSetV2WithContext: reporter.StartFetchTimer() err := fetcher.Fetch(ctx, reporter.V2()) - if err != nil { - reporter.V2().Error(err) - if errors.As(err, &mb.PartialMetricsError{}) { - // mark module as running if metrics are partially available and display the error message - msw.module.UpdateStatus(status.Running, fmt.Sprintf("Error fetching data for metricset %s.%s: %v", msw.module.Name(), msw.MetricSet.Name(), err)) - } else { - // mark it as degraded for any other issue encountered - msw.module.UpdateStatus(status.Degraded, fmt.Sprintf("Error fetching data for metricset %s.%s: %v", msw.module.Name(), msw.MetricSet.Name(), err)) - } - logp.Err("Error fetching data for metricset %s.%s: %s", msw.module.Name(), msw.Name(), err) - } else { - msw.module.UpdateStatus(status.Running, "") - } + msw.handleFetchError(err, reporter.V2()) default: panic(fmt.Sprintf("unexpected fetcher type for %v", msw)) } @@ -311,6 +310,31 @@ func (msw *metricSetWrapper) Test(d testing.Driver) { }) } +func (msw *metricSetWrapper) handleFetchError(err error, reporter mb.PushReporterV2) { + switch { + case err == nil: + msw.stats.consecutiveFailures.Set(0) + msw.module.UpdateStatus(status.Running, "") + + case errors.As(err, &mb.PartialMetricsError{}): + reporter.Error(err) + msw.stats.consecutiveFailures.Set(0) + // mark module as running if metrics are partially available and display the error message + msw.module.UpdateStatus(status.Running, fmt.Sprintf("Error fetching data for metricset %s.%s: %v", msw.module.Name(), msw.MetricSet.Name(), err)) + logp.Err("Error fetching data for metricset %s.%s: %s", msw.module.Name(), msw.Name(), err) + + default: + reporter.Error(err) + msw.stats.consecutiveFailures.Inc() + if msw.failureThreshold > 0 && msw.stats.consecutiveFailures != nil && uint(msw.stats.consecutiveFailures.Get()) >= msw.failureThreshold { + // mark it as degraded for any other issue encountered + msw.module.UpdateStatus(status.Degraded, fmt.Sprintf("Error fetching data for metricset %s.%s: %v", msw.module.Name(), msw.MetricSet.Name(), err)) + } + logp.Err("Error fetching data for metricset %s.%s: %s", msw.module.Name(), msw.Name(), err) + + } +} + type reporter interface { StartFetchTimer() V1() mb.PushReporter //nolint:staticcheck // PushReporter is deprecated but not removed @@ -437,11 +461,12 @@ func getMetricSetStats(module, name string) *stats { reg := monitoring.Default.NewRegistry(key) s := &stats{ - key: key, - ref: 1, - success: monitoring.NewInt(reg, successesKey), - failures: monitoring.NewInt(reg, failuresKey), - events: monitoring.NewInt(reg, eventsKey), + key: key, + ref: 1, + success: monitoring.NewInt(reg, successesKey), + failures: monitoring.NewInt(reg, failuresKey), + events: monitoring.NewInt(reg, eventsKey), + consecutiveFailures: monitoring.NewUint(reg, consecutiveFailuresKey), } fetches[key] = s diff --git a/metricbeat/mb/module/wrapper_internal_test.go b/metricbeat/mb/module/wrapper_internal_test.go new file mode 100644 index 000000000000..a9b242e55e26 --- /dev/null +++ b/metricbeat/mb/module/wrapper_internal_test.go @@ -0,0 +1,567 @@ +// 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 module + +import ( + "context" + "errors" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + "github.com/elastic/beats/v7/libbeat/management/status" + "github.com/elastic/beats/v7/metricbeat/mb" + conf "github.com/elastic/elastic-agent-libs/config" +) + +const mockModuleName = "MockModule" +const mockMetricSetName = "MockMetricSet" + +// mockReportingFetcher +type mockReportingFetcher struct { + mb.BaseMetricSet + mock.Mock +} + +func (mrf *mockReportingFetcher) Fetch(r mb.ReporterV2) error { + args := mrf.Called(r) + return args.Error(0) +} + +// mockReportingFetcherWithContext +type mockReportingFetcherWithContext struct { + mb.BaseMetricSet + mock.Mock +} + +func (mrf *mockReportingFetcherWithContext) Fetch(ctx context.Context, r mb.ReporterV2) error { + args := mrf.Called(ctx, r) + return args.Error(0) +} + +// mockReporter +type mockReporter struct { + mock.Mock +} + +func (mr *mockReporter) StartFetchTimer() { + mr.Called() +} + +func (mr *mockReporter) V1() mb.PushReporter { //nolint:staticcheck // PushReporter is deprecated but not removed + args := mr.Called() + return args.Get(0).(mb.PushReporter) //nolint:staticcheck // PushReporter is deprecated but not removed +} + +func (mr *mockReporter) V2() mb.PushReporterV2 { + args := mr.Called() + return args.Get(0).(mb.PushReporterV2) +} + +// mockPushReporterV2 +type mockPushReporterV2 struct { + mock.Mock +} + +func (mpr *mockPushReporterV2) Event(event mb.Event) bool { + args := mpr.Called(event) + return args.Bool(0) +} + +func (mpr *mockPushReporterV2) Error(err error) bool { + args := mpr.Called(err) + return args.Bool(0) +} + +func (mpr *mockPushReporterV2) Done() <-chan struct{} { + args := mpr.Called() + return args.Get(0).(<-chan struct{}) +} + +// mockStatusReporterV2 +type mockStatusReporter struct { + mock.Mock +} + +func (m *mockStatusReporter) UpdateStatus(status status.Status, msg string) { + m.Called(status, msg) +} + +func TestWrapperHandleFetchErrorSync(t *testing.T) { + + fetchError := errors.New("fetch has gone all wrong") + + t.Run("ReportingMetricSetV2Error", func(t *testing.T) { + type setupFunc func(t *testing.T, fetcher *mockReportingFetcher, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) + type postIterationAssertFunc func(t *testing.T, i int, msWrapper *metricSetWrapper, fetcher *mockReportingFetcher, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) + + testcases := []struct { + name string + config *conf.C + setup setupFunc + iterations int + assertIteration postIterationAssertFunc + }{ + { + name: "no failure_threshold: status DEGRADED after first error", + config: newConfig(t, map[string]interface{}{ + "module": mockModuleName, + "metricsets": []string{mockMetricSetName}, + "period": "100ms", + "hosts": []string{"testhost"}, + }), + setup: func(t *testing.T, fetcher *mockReportingFetcher, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) { + // fetcher will immediately error out + fetcher.On("Fetch", pushReporter).Return(fetchError).Once() + + // expect the error to be propagated via the pushReporter + pushReporter.On("Error", fetchError).Return(true).Once() + // expect the status degraded to be set + statusReporter.On("UpdateStatus", status.Degraded, mock.AnythingOfType("string")).Once() + }, + iterations: 1, + assertIteration: nil, + }, + { + name: "no failure_threshold: status DEGRADED after first error, reset to Running after first successful fetch", + config: newConfig(t, map[string]interface{}{ + "module": mockModuleName, + "metricsets": []string{mockMetricSetName}, + "period": "100ms", + "hosts": []string{"testhost"}, + }), + setup: func(t *testing.T, fetcher *mockReportingFetcher, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) { + // fetcher will immediately error out 3 times + fetcher.On("Fetch", pushReporter).Return(fetchError).Times(3) + // fetcher will never error again afterwards + fetcher.On("Fetch", pushReporter).Return(nil) + // expect the error to be propagated via the pushReporter + pushReporter.On("Error", fetchError).Return(true).Times(3) + // expect the status degraded to be set 3 times + statusReporter.On("UpdateStatus", status.Degraded, mock.AnythingOfType("string")).Times(3) + // expect the status Running to be set once fetch recovers + statusReporter.On("UpdateStatus", status.Running, mock.AnythingOfType("string")).Twice() + }, + iterations: 5, + assertIteration: func(t *testing.T, i int, msWrapper *metricSetWrapper, fetcher *mockReportingFetcher, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) { + t.Logf("Assertion after iteration %d", i) + switch { + case i < 3: + assert.Truef(t, statusReporter.AssertCalled(t, "UpdateStatus", status.Degraded, mock.AnythingOfType("string")), "stream degraded at iteration %d", i) + case i >= 3: + assert.Truef(t, statusReporter.AssertCalled(t, "UpdateStatus", status.Running, mock.AnythingOfType("string")), "stream set to running at iteration %d", i) + } + }, + }, + { + name: "failure_threshold = 3: status DEGRADED at the 3rd error", + config: newConfig(t, map[string]interface{}{ + "module": mockModuleName, + "metricsets": []string{mockMetricSetName}, + "period": "100ms", + "hosts": []string{"testhost"}, + failureThresholdKey: 3, + }), + setup: func(t *testing.T, fetcher *mockReportingFetcher, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) { + // fetcher will immediately error out 3 times in a row + fetcher.On("Fetch", pushReporter).Return(fetchError).Times(3) + // expect the error to be propagated via the pushReporter at every iteration + pushReporter.On("Error", fetchError).Return(true).Times(3) + // expect the status degraded to be set + statusReporter.On("UpdateStatus", status.Degraded, mock.AnythingOfType("string")).Once() + }, + iterations: 3, + assertIteration: func(t *testing.T, i int, msWrapper *metricSetWrapper, fetcher *mockReportingFetcher, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) { + t.Logf("Assertion after iteration %d", i) + switch { + case i < 2: + assert.Truef(t, statusReporter.AssertNotCalled(t, "UpdateStatus", status.Degraded, mock.AnythingOfType("string")), "stream degraded at iteration %d", i) + case i == 2: + assert.Truef(t, statusReporter.AssertCalled(t, "UpdateStatus", status.Degraded, mock.AnythingOfType("string")), "stream not yet degraded at iteration %d", i) + } + }, + }, + { + name: "failure_threshold = 3: status HEALTHY after 2 errors, 1 success and 2 more errors, DEGRADED at the 3rd consecutive error", + config: newConfig(t, map[string]interface{}{ + "module": mockModuleName, + "metricsets": []string{mockMetricSetName}, + "period": "100ms", + "hosts": []string{"testhost"}, + failureThresholdKey: 3, + }), + setup: func(t *testing.T, fetcher *mockReportingFetcher, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) { + // fetcher will error out 2 times in a row + fetcher.On("Fetch", pushReporter).Return(fetchError).Times(2) + // fetcher will then succeed once + fetcher.On("Fetch", pushReporter).Return(nil).Once() + // fetcher will error out 3 more times in a row + fetcher.On("Fetch", pushReporter).Return(fetchError).Times(3) + + // expect the error to be propagated via the pushReporter at every failing iteration + pushReporter.On("Error", fetchError).Return(true).Times(5) + // expect the status running to be set when there's no error returned by the fetcher at the 3rd iteration + statusReporter.On("UpdateStatus", status.Running, mock.AnythingOfType("string")).Once() + // expect the status degraded to be set only once + statusReporter.On("UpdateStatus", status.Degraded, mock.AnythingOfType("string")).Once() + }, + iterations: 6, + assertIteration: func(t *testing.T, i int, msWrapper *metricSetWrapper, fetcher *mockReportingFetcher, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) { + t.Logf("Assertion after iteration %d", i) + switch { + case i < 2: + assert.Truef(t, statusReporter.AssertNotCalled(t, "UpdateStatus", status.Degraded, mock.AnythingOfType("string")), "stream degraded at iteration %d", i) + case i >= 2 && i < 5: + assert.Truef(t, statusReporter.AssertNotCalled(t, "UpdateStatus", status.Degraded, mock.AnythingOfType("string")), "stream degraded at iteration %d", i) + assert.Truef(t, statusReporter.AssertCalled(t, "UpdateStatus", status.Running, mock.AnythingOfType("string")), "stream degraded at iteration %d", i) + case i == 5: + assert.Truef(t, statusReporter.AssertCalled(t, "UpdateStatus", status.Degraded, mock.AnythingOfType("string")), "stream not yet degraded at iteration %d", i) + } + }, + }, + { + name: "failure_threshold = 0: stream status update never become DEGRADED", + config: newConfig(t, map[string]interface{}{ + "module": mockModuleName, + "metricsets": []string{mockMetricSetName}, + "period": "100ms", + "hosts": []string{"testhost"}, + failureThresholdKey: 0, + }), + setup: func(t *testing.T, fetcher *mockReportingFetcher, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) { + // fetcher will error out 9 times in a row + fetcher.On("Fetch", pushReporter).Return(fetchError).Times(9) + // fetcher will then succeed once + fetcher.On("Fetch", pushReporter).Return(nil).Once() + + // expect the error to be propagated via the pushReporter at every failing iteration + pushReporter.On("Error", fetchError).Return(true).Times(9) + // expect the status running to be set when there's no error returned by the fetcher at the 10th iteration + statusReporter.On("UpdateStatus", status.Running, mock.AnythingOfType("string")).Once() + }, + iterations: 10, + assertIteration: func(t *testing.T, i int, msWrapper *metricSetWrapper, fetcher *mockReportingFetcher, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) { + t.Logf("Assertion after iteration %d", i) + switch { + case i < 9: + assert.Truef(t, statusReporter.AssertNotCalled(t, "UpdateStatus", status.Degraded, mock.AnythingOfType("string")), "stream degraded at iteration %d", i) + case i == 9: + assert.Truef(t, statusReporter.AssertNotCalled(t, "UpdateStatus", status.Degraded, mock.AnythingOfType("string")), "stream degraded at iteration %d", i) + assert.Truef(t, statusReporter.AssertCalled(t, "UpdateStatus", status.Running, mock.AnythingOfType("string")), "stream degraded at iteration %d", i) + } + }, + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + // Setup mock push reporter + mpr := new(mockPushReporterV2) + + // Setup mock fetcher + mrf := new(mockReportingFetcher) + + // Setup mock StatusReporter + msr := new(mockStatusReporter) + + //Setup mock reporter (ensure proper handling of intermediate calls, no functional value here) + mr := new(mockReporter) + mr.On("StartFetchTimer").Return() + mr.On("V2").Return(mpr) + + // assert mocks expectations + t.Cleanup(func() { + mock.AssertExpectationsForObjects(t, mrf, mr, mpr, msr) + }) + + // setup mocks before starting the test + if tc.setup != nil { + tc.setup(t, mrf, mpr, msr) + } + + // add metricset in registry + r := mb.NewRegister() + err := r.AddMetricSet(mockModuleName, mockMetricSetName, func(base mb.BaseMetricSet) (mb.MetricSet, error) { + mrf.BaseMetricSet = base + return mrf, nil + }) + require.NoError(t, err) + + aModule, metricSets, err := mb.NewModule(tc.config, r) + require.NoError(t, err) + + // Set the mock status reporter + aModule.SetStatusReporter(msr) + + moduleWrapper, err := NewWrapperForMetricSet(aModule, metricSets[0], WithMetricSetInfo()) + require.NoError(t, err) + + // run metricset synchronously + wrappedMetricSet := moduleWrapper.MetricSets()[0] + + t.Cleanup(func() { + // release stats structure across testcases + releaseStats(wrappedMetricSet.stats) + }) + + for i := 0; i < tc.iterations; i++ { + wrappedMetricSet.fetch(context.TODO(), mr) + if tc.assertIteration != nil { + tc.assertIteration(t, i, wrappedMetricSet, mrf, mpr, msr) + } + } + }) + } + }) + + t.Run("ReportingMetricSetV2WithContext", func(t *testing.T) { + // These tests are the same as ReportingMetricSetV2Error, duplicated here because the generic solution to specify + // testcases only once is awkward and not very readable + + type setupFunc func(t *testing.T, fetcher *mockReportingFetcherWithContext, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) + type postIterationAssertFunc func(t *testing.T, i int, msWrapper *metricSetWrapper, fetcher *mockReportingFetcherWithContext, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) + + fetchCtx := context.TODO() + + testcases := []struct { + name string + config *conf.C + setup setupFunc + iterations int + assertIteration postIterationAssertFunc + }{ + { + name: "no failure_threshold: status DEGRADED after first error", + config: newConfig(t, map[string]interface{}{ + "module": mockModuleName, + "metricsets": []string{mockMetricSetName}, + "period": "100ms", + "hosts": []string{"testhost"}, + }), + setup: func(t *testing.T, fetcher *mockReportingFetcherWithContext, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) { + // fetcher will immediately error out + fetcher.On("Fetch", fetchCtx, pushReporter).Return(fetchError).Once() + + // expect the error to be propagated via the pushReporter + pushReporter.On("Error", fetchError).Return(true).Once() + // expect the status degraded to be set + statusReporter.On("UpdateStatus", status.Degraded, mock.AnythingOfType("string")).Once() + }, + iterations: 1, + assertIteration: nil, + }, + { + name: "no failure_threshold: status DEGRADED after first error, reset to Running after first successful fetch", + config: newConfig(t, map[string]interface{}{ + "module": mockModuleName, + "metricsets": []string{mockMetricSetName}, + "period": "100ms", + "hosts": []string{"testhost"}, + }), + setup: func(t *testing.T, fetcher *mockReportingFetcherWithContext, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) { + // fetcher will immediately error out 3 times + fetcher.On("Fetch", fetchCtx, pushReporter).Return(fetchError).Times(3) + // fetcher will never error again afterwards + fetcher.On("Fetch", fetchCtx, pushReporter).Return(nil) + // expect the error to be propagated via the pushReporter + pushReporter.On("Error", fetchError).Return(true).Times(3) + // expect the status degraded to be set 3 times + statusReporter.On("UpdateStatus", status.Degraded, mock.AnythingOfType("string")).Times(3) + // expect the status Running to be set once fetch recovers + statusReporter.On("UpdateStatus", status.Running, mock.AnythingOfType("string")).Twice() + }, + iterations: 5, + assertIteration: func(t *testing.T, i int, msWrapper *metricSetWrapper, fetcher *mockReportingFetcherWithContext, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) { + t.Logf("Assertion after iteration %d", i) + switch { + case i < 3: + assert.Truef(t, statusReporter.AssertCalled(t, "UpdateStatus", status.Degraded, mock.AnythingOfType("string")), "stream degraded at iteration %d", i) + case i >= 3: + assert.Truef(t, statusReporter.AssertCalled(t, "UpdateStatus", status.Running, mock.AnythingOfType("string")), "stream set to running at iteration %d", i) + } + }, + }, + { + name: "failure_threshold = 3: status DEGRADED at the 3rd error", + config: newConfig(t, map[string]interface{}{ + "module": mockModuleName, + "metricsets": []string{mockMetricSetName}, + "period": "100ms", + "hosts": []string{"testhost"}, + failureThresholdKey: 3, + }), + setup: func(t *testing.T, fetcher *mockReportingFetcherWithContext, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) { + // fetcher will immediately error out 3 times in a row + fetcher.On("Fetch", fetchCtx, pushReporter).Return(fetchError).Times(3) + // expect the error to be propagated via the pushReporter at every iteration + pushReporter.On("Error", fetchError).Return(true).Times(3) + // expect the status degraded to be set + statusReporter.On("UpdateStatus", status.Degraded, mock.AnythingOfType("string")).Once() + }, + iterations: 3, + assertIteration: func(t *testing.T, i int, msWrapper *metricSetWrapper, fetcher *mockReportingFetcherWithContext, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) { + t.Logf("Assertion after iteration %d", i) + switch { + case i < 2: + assert.Truef(t, statusReporter.AssertNotCalled(t, "UpdateStatus", status.Degraded, mock.AnythingOfType("string")), "stream degraded at iteration %d", i) + case i == 2: + assert.Truef(t, statusReporter.AssertCalled(t, "UpdateStatus", status.Degraded, mock.AnythingOfType("string")), "stream not yet degraded at iteration %d", i) + } + }, + }, + { + name: "failure_threshold = 3: status HEALTHY after 2 errors, 1 success and 2 more errors, DEGRADED at the 3rd consecutive error", + config: newConfig(t, map[string]interface{}{ + "module": mockModuleName, + "metricsets": []string{mockMetricSetName}, + "period": "100ms", + "hosts": []string{"testhost"}, + failureThresholdKey: 3, + }), + setup: func(t *testing.T, fetcher *mockReportingFetcherWithContext, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) { + // fetcher will error out 2 times in a row + fetcher.On("Fetch", fetchCtx, pushReporter).Return(fetchError).Times(2) + // fetcher will then succeed once + fetcher.On("Fetch", fetchCtx, pushReporter).Return(nil).Once() + // fetcher will error out 3 more times in a row + fetcher.On("Fetch", fetchCtx, pushReporter).Return(fetchError).Times(3) + + // expect the error to be propagated via the pushReporter at every failing iteration + pushReporter.On("Error", fetchError).Return(true).Times(5) + // expect the status running to be set when there's no error returned by the fetcher at the 3rd iteration + statusReporter.On("UpdateStatus", status.Running, mock.AnythingOfType("string")).Once() + // expect the status degraded to be set only once + statusReporter.On("UpdateStatus", status.Degraded, mock.AnythingOfType("string")).Once() + }, + iterations: 6, + assertIteration: func(t *testing.T, i int, msWrapper *metricSetWrapper, fetcher *mockReportingFetcherWithContext, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) { + t.Logf("Assertion after iteration %d", i) + switch { + case i < 2: + assert.Truef(t, statusReporter.AssertNotCalled(t, "UpdateStatus", status.Degraded, mock.AnythingOfType("string")), "stream degraded at iteration %d", i) + case i >= 2 && i < 5: + assert.Truef(t, statusReporter.AssertNotCalled(t, "UpdateStatus", status.Degraded, mock.AnythingOfType("string")), "stream degraded at iteration %d", i) + assert.Truef(t, statusReporter.AssertCalled(t, "UpdateStatus", status.Running, mock.AnythingOfType("string")), "stream degraded at iteration %d", i) + case i == 5: + assert.Truef(t, statusReporter.AssertCalled(t, "UpdateStatus", status.Degraded, mock.AnythingOfType("string")), "stream not yet degraded at iteration %d", i) + } + }, + }, + { + name: "failure_threshold = 0: stream status update never become DEGRADED", + config: newConfig(t, map[string]interface{}{ + "module": mockModuleName, + "metricsets": []string{mockMetricSetName}, + "period": "100ms", + "hosts": []string{"testhost"}, + failureThresholdKey: 0, + }), + setup: func(t *testing.T, fetcher *mockReportingFetcherWithContext, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) { + // fetcher will error out 9 times in a row + fetcher.On("Fetch", fetchCtx, pushReporter).Return(fetchError).Times(9) + // fetcher will then succeed once + fetcher.On("Fetch", fetchCtx, pushReporter).Return(nil).Once() + + // expect the error to be propagated via the pushReporter at every failing iteration + pushReporter.On("Error", fetchError).Return(true).Times(9) + // expect the status running to be set when there's no error returned by the fetcher at the 10th iteration + statusReporter.On("UpdateStatus", status.Running, mock.AnythingOfType("string")).Once() + }, + iterations: 10, + assertIteration: func(t *testing.T, i int, msWrapper *metricSetWrapper, fetcher *mockReportingFetcherWithContext, pushReporter *mockPushReporterV2, statusReporter *mockStatusReporter) { + t.Logf("Assertion after iteration %d", i) + switch { + case i < 9: + assert.Truef(t, statusReporter.AssertNotCalled(t, "UpdateStatus", status.Degraded, mock.AnythingOfType("string")), "stream degraded at iteration %d", i) + case i == 9: + assert.Truef(t, statusReporter.AssertNotCalled(t, "UpdateStatus", status.Degraded, mock.AnythingOfType("string")), "stream degraded at iteration %d", i) + assert.Truef(t, statusReporter.AssertCalled(t, "UpdateStatus", status.Running, mock.AnythingOfType("string")), "stream degraded at iteration %d", i) + } + }, + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + // Setup mock push reporter + mpr := new(mockPushReporterV2) + + // Setup mock fetcher + mrf := new(mockReportingFetcherWithContext) + + // Setup mock StatusReporter + msr := new(mockStatusReporter) + + //Setup mock reporter (ensure proper handling of intermediate calls, no functional value here) + mr := new(mockReporter) + mr.On("StartFetchTimer").Return() + mr.On("V2").Return(mpr) + + // assert mocks expectations + t.Cleanup(func() { + mock.AssertExpectationsForObjects(t, mrf, mr, mpr, msr) + }) + + // setup mocks before starting the test + if tc.setup != nil { + tc.setup(t, mrf, mpr, msr) + } + + // add metricset in registry + r := mb.NewRegister() + err := r.AddMetricSet(mockModuleName, mockMetricSetName, func(base mb.BaseMetricSet) (mb.MetricSet, error) { + mrf.BaseMetricSet = base + return mrf, nil + }) + require.NoError(t, err) + + aModule, metricSets, err := mb.NewModule(tc.config, r) + require.NoError(t, err) + + // Set the mock status reporter + aModule.SetStatusReporter(msr) + + moduleWrapper, err := NewWrapperForMetricSet(aModule, metricSets[0], WithMetricSetInfo()) + require.NoError(t, err) + + // run metricset synchronously + wrappedMetricSet := moduleWrapper.MetricSets()[0] + + t.Cleanup(func() { + // release stats structure across testcases + releaseStats(wrappedMetricSet.stats) + }) + + for i := 0; i < tc.iterations; i++ { + wrappedMetricSet.fetch(context.TODO(), mr) + if tc.assertIteration != nil { + tc.assertIteration(t, i, wrappedMetricSet, mrf, mpr, msr) + } + } + }) + } + }) +} + +func newConfig(t testing.TB, moduleConfig interface{}) *conf.C { + config, err := conf.NewConfigFrom(moduleConfig) + require.NoError(t, err) + return config +} diff --git a/metricbeat/metricbeat.reference.yml b/metricbeat/metricbeat.reference.yml index 409eeb168bf8..456af41f9b53 100644 --- a/metricbeat/metricbeat.reference.yml +++ b/metricbeat/metricbeat.reference.yml @@ -142,6 +142,11 @@ metricbeat.modules: # Filter systemd services based on a name pattern #service.pattern_filter: ["ssh*", "nfs*"] + # This option enables the use of performance counters to collect data for cpu/core metricset. + # Only effective for Windows. + # You should use this option if running beats on machins with more than 64 cores. + #use_performance_counters: true + #------------------------------ Aerospike Module ------------------------------ - module: aerospike metricsets: ["namespace"] @@ -268,6 +273,9 @@ metricbeat.modules: # If set to true, replace dots in labels with `_`. #labels.dedot: false + # Docker module supports metrics collection from podman's docker compatible API. In case of podman set to true. + # podman: false + # Skip metrics for certain device major numbers in docker/diskio. # Necessary on systems with software RAID, device mappers, # or other configurations where virtual disks will sum metrics from other disks. diff --git a/metricbeat/module/consul/agent/data_integration_test.go b/metricbeat/module/consul/agent/data_integration_test.go index cee25f69311d..cd756451cbd3 100644 --- a/metricbeat/module/consul/agent/data_integration_test.go +++ b/metricbeat/module/consul/agent/data_integration_test.go @@ -22,7 +22,7 @@ package agent import ( "testing" - _ "github.com/denisenkom/go-mssqldb" + _ "github.com/microsoft/go-mssqldb" "github.com/elastic/beats/v7/libbeat/tests/compose" mbtest "github.com/elastic/beats/v7/metricbeat/mb/testing" diff --git a/metricbeat/module/docker/_meta/config.reference.yml b/metricbeat/module/docker/_meta/config.reference.yml index 8d11201983cf..184d6592bf17 100644 --- a/metricbeat/module/docker/_meta/config.reference.yml +++ b/metricbeat/module/docker/_meta/config.reference.yml @@ -17,6 +17,9 @@ # If set to true, replace dots in labels with `_`. #labels.dedot: false + # Docker module supports metrics collection from podman's docker compatible API. In case of podman set to true. + # podman: false + # Skip metrics for certain device major numbers in docker/diskio. # Necessary on systems with software RAID, device mappers, # or other configurations where virtual disks will sum metrics from other disks. diff --git a/metricbeat/module/docker/_meta/config.yml b/metricbeat/module/docker/_meta/config.yml index da3c1e02a068..a7b9b9196fca 100644 --- a/metricbeat/module/docker/_meta/config.yml +++ b/metricbeat/module/docker/_meta/config.yml @@ -15,6 +15,9 @@ # If set to true, replace dots in labels with `_`. #labels.dedot: false + # Docker module supports metrics collection from podman's Docker-compatible API. In case of podman set to true. + # podman: false + # Skip metrics for certain device major numbers in docker/diskio. # Necessary on systems with software RAID, device mappers, # or other configurations where virtual disks will sum metrics from other disks. diff --git a/metricbeat/module/docker/_meta/docs.asciidoc b/metricbeat/module/docker/_meta/docs.asciidoc index e1d5437572a4..ca2da0ea26dc 100644 --- a/metricbeat/module/docker/_meta/docs.asciidoc +++ b/metricbeat/module/docker/_meta/docs.asciidoc @@ -11,6 +11,9 @@ The Docker module is currently tested on Linux and Mac with the community edition engine, versions 1.11 and 17.09.0-ce. It is not tested on Windows, but it should also work there. +The Docker module supports collection of metrics from Podman's Docker-compatible API. +It has been tested on Linux and Mac with Podman Rest API v2.0.0 and above. + [float] === Module-specific configuration notes @@ -19,3 +22,6 @@ It is strongly recommended that you run Docker metricsets with a Docker API already takes up to 2 seconds. Specifying less than 3 seconds will result in requests that timeout, and no data will be reported for those requests. +In the case of Podman, the configuration parameter `podman` should be set to `true`. +This enables streaming of container stats output, which allows for more accurate +CPU percentage calculations when using Podman. diff --git a/metricbeat/module/docker/config.go b/metricbeat/module/docker/config.go index 40698cb0baf9..b9bee9b35e9d 100644 --- a/metricbeat/module/docker/config.go +++ b/metricbeat/module/docker/config.go @@ -19,14 +19,16 @@ package docker // Config contains the config needed for the docker type Config struct { - TLS *TLSConfig `config:"ssl"` - DeDot bool `config:"labels.dedot"` + TLS *TLSConfig `config:"ssl"` + DeDot bool `config:"labels.dedot"` + Podman bool `config:"podman"` } // DefaultConfig returns default module config func DefaultConfig() Config { return Config{ - DeDot: true, + DeDot: true, + Podman: false, } } diff --git a/metricbeat/module/docker/cpu/cpu.go b/metricbeat/module/docker/cpu/cpu.go index a29ee8a00cc2..6869dd30a461 100644 --- a/metricbeat/module/docker/cpu/cpu.go +++ b/metricbeat/module/docker/cpu/cpu.go @@ -40,6 +40,7 @@ type MetricSet struct { cpuService *CPUService dockerClient *client.Client dedot bool + podman bool } // New creates a new instance of the docker cpu MetricSet. @@ -68,12 +69,13 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { dockerClient: client, cpuService: &CPUService{Cores: cpuConfig.Cores}, dedot: config.DeDot, + podman: config.Podman, }, nil } // Fetch returns a list of docker CPU stats. func (m *MetricSet) Fetch(r mb.ReporterV2) error { - stats, err := docker.FetchStats(m.dockerClient, m.Module().Config().Timeout) + stats, err := docker.FetchStats(m.dockerClient, m.Module().Config().Timeout, m.podman, m.Logger()) if err != nil { return fmt.Errorf("failed to get docker stats: %w", err) } diff --git a/metricbeat/module/docker/diskio/diskio.go b/metricbeat/module/docker/diskio/diskio.go index df5a0f2dff51..a59de2d52683 100644 --- a/metricbeat/module/docker/diskio/diskio.go +++ b/metricbeat/module/docker/diskio/diskio.go @@ -89,7 +89,7 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { // Fetch creates list of events with diskio stats for all containers. func (m *MetricSet) Fetch(r mb.ReporterV2) error { - stats, err := docker.FetchStats(m.dockerClient, m.Module().Config().Timeout) + stats, err := docker.FetchStats(m.dockerClient, m.Module().Config().Timeout, false, m.Logger()) if err != nil { return fmt.Errorf("failed to get docker stats: %w", err) } diff --git a/metricbeat/module/docker/docker.go b/metricbeat/module/docker/docker.go index 2020df91975b..d4595ef8e5ed 100644 --- a/metricbeat/module/docker/docker.go +++ b/metricbeat/module/docker/docker.go @@ -34,6 +34,7 @@ import ( "github.com/elastic/beats/v7/metricbeat/mb" "github.com/elastic/beats/v7/metricbeat/mb/parse" "github.com/elastic/elastic-agent-autodiscover/docker" + "github.com/elastic/elastic-agent-libs/logp" ) // HostParser is a TCP host parser function for docker tcp host addresses @@ -91,7 +92,7 @@ func NewDockerClient(endpoint string, config Config) (*client.Client, error) { } // FetchStats returns a list of running containers with all related stats inside -func FetchStats(client *client.Client, timeout time.Duration) ([]Stat, error) { +func FetchStats(client *client.Client, timeout time.Duration, stream bool, logger *logp.Logger) ([]Stat, error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() containers, err := client.ContainerList(ctx, container.ListOptions{}) @@ -108,7 +109,7 @@ func FetchStats(client *client.Client, timeout time.Duration) ([]Stat, error) { for _, container := range containers { go func(container types.Container) { defer wg.Done() - statsQueue <- exportContainerStats(ctx, client, &container) + statsQueue <- exportContainerStats(ctx, client, &container, stream, logger) }(container) } @@ -133,18 +134,41 @@ func FetchStats(client *client.Client, timeout time.Duration) ([]Stat, error) { // This is currently very inefficient as docker calculates the average for each request, // means each request will take at least 2s: https://github.com/docker/docker/blob/master/cli/command/container/stats_helpers.go#L148 // Getting all stats at once is implemented here: https://github.com/docker/docker/pull/25361 -func exportContainerStats(ctx context.Context, client *client.Client, container *types.Container) Stat { +// In case stream is true, we use get a stream of results for container stats. From the stream we keep the second result. +// This is needed for podman use case where in case stream is false, no precpu stats are returned. The precpu stats +// are required for the cpu percentage calculation. We keep the second result as in the first result, the stats are not correct. +func exportContainerStats(ctx context.Context, client *client.Client, container *types.Container, stream bool, logger *logp.Logger) Stat { var event Stat event.Container = container - - containerStats, err := client.ContainerStats(ctx, container.ID, false) + containerStats, err := client.ContainerStats(ctx, container.ID, stream) if err != nil { + logger.Debugf("Failed fetching container stats: %v", err) return event } - defer containerStats.Body.Close() - decoder := json.NewDecoder(containerStats.Body) - decoder.Decode(&event.Stats) + // JSON decoder + decoder := json.NewDecoder(containerStats.Body) + if !stream { + if err := decoder.Decode(&event.Stats); err != nil { + logger.Debugf("Failed decoding event: %v", err) + return event + } + } else { + // handle stream. Take the second result. + count := 0 + for decoder.More() { + if err := decoder.Decode(&event.Stats); err != nil { + logger.Debugf("Failed decoding event: %v", err) + return event + } + + count++ + // Exit after the second result + if count == 2 { + break + } + } + } return event } diff --git a/metricbeat/module/docker/memory/memory.go b/metricbeat/module/docker/memory/memory.go index 140383de833e..5c90c09d39c2 100644 --- a/metricbeat/module/docker/memory/memory.go +++ b/metricbeat/module/docker/memory/memory.go @@ -43,6 +43,7 @@ type MetricSet struct { memoryService *MemoryService dockerClient *client.Client dedot bool + podman bool logger *logp.Logger } @@ -64,13 +65,14 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { memoryService: &MemoryService{}, dockerClient: dockerClient, dedot: config.DeDot, + podman: config.Podman, logger: logger, }, nil } // Fetch creates a list of memory events for each container. func (m *MetricSet) Fetch(r mb.ReporterV2) error { - stats, err := docker.FetchStats(m.dockerClient, m.Module().Config().Timeout) + stats, err := docker.FetchStats(m.dockerClient, m.Module().Config().Timeout, m.podman, m.Logger()) if err != nil { return fmt.Errorf("failed to get docker stats: %w", err) } diff --git a/metricbeat/module/docker/network/network.go b/metricbeat/module/docker/network/network.go index 8a70fd124466..34487aa49835 100644 --- a/metricbeat/module/docker/network/network.go +++ b/metricbeat/module/docker/network/network.go @@ -66,7 +66,7 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { // Fetch methods creates a list of network events for each container. func (m *MetricSet) Fetch(r mb.ReporterV2) error { - stats, err := docker.FetchStats(m.dockerClient, m.Module().Config().Timeout) + stats, err := docker.FetchStats(m.dockerClient, m.Module().Config().Timeout, false, m.Logger()) if err != nil { return fmt.Errorf("failed to get docker stats: %w", err) } diff --git a/metricbeat/module/docker/network_summary/network_summary.go b/metricbeat/module/docker/network_summary/network_summary.go index 9753b449adde..9052e38580b0 100644 --- a/metricbeat/module/docker/network_summary/network_summary.go +++ b/metricbeat/module/docker/network_summary/network_summary.go @@ -84,7 +84,7 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { // of an error set the Error field of mb.Event or simply call report.Error(). func (m *MetricSet) Fetch(ctx context.Context, report mb.ReporterV2) error { - stats, err := docker.FetchStats(m.dockerClient, m.Module().Config().Timeout) + stats, err := docker.FetchStats(m.dockerClient, m.Module().Config().Timeout, false, m.Logger()) if err != nil { return fmt.Errorf("failed to get docker stats: %w", err) } diff --git a/metricbeat/module/elasticsearch/cluster_stats/data.go b/metricbeat/module/elasticsearch/cluster_stats/data.go index 4fe1d03f6d73..cfd89ce46c03 100644 --- a/metricbeat/module/elasticsearch/cluster_stats/data.go +++ b/metricbeat/module/elasticsearch/cluster_stats/data.go @@ -231,7 +231,7 @@ func eventMapping(r mb.ReporterV2, httpClient *helper.HTTP, info elasticsearch.I } clusterStateMetrics := []string{"version", "master_node", "nodes", "routing_table"} - clusterState, err := elasticsearch.GetClusterState(httpClient, httpClient.GetURI(), clusterStateMetrics) + clusterState, err := elasticsearch.GetClusterState(httpClient, httpClient.GetURI(), clusterStateMetrics, []string{}) if err != nil { return fmt.Errorf("failed to get cluster state from Elasticsearch: %w", err) } diff --git a/metricbeat/module/elasticsearch/elasticsearch.go b/metricbeat/module/elasticsearch/elasticsearch.go index 446a2d128bbf..7e9f22152342 100644 --- a/metricbeat/module/elasticsearch/elasticsearch.go +++ b/metricbeat/module/elasticsearch/elasticsearch.go @@ -288,13 +288,21 @@ func GetLicense(http *helper.HTTP, resetURI string) (*License, error) { } // GetClusterState returns cluster state information. -func GetClusterState(http *helper.HTTP, resetURI string, metrics []string) (mapstr.M, error) { +func GetClusterState(http *helper.HTTP, resetURI string, metrics []string, filterPaths []string) (mapstr.M, error) { + queryParams := []string{"local=true"} clusterStateURI := "_cluster/state" if len(metrics) > 0 { clusterStateURI += "/" + strings.Join(metrics, ",") } - content, err := fetchPath(http, resetURI, clusterStateURI, "local=true") + if len(filterPaths) > 0 { + filterPathQueryParam := "filter_path=" + strings.Join(filterPaths, ",") + queryParams = append(queryParams, filterPathQueryParam) + } + + queryString := strings.Join(queryParams, "&") + + content, err := fetchPath(http, resetURI, clusterStateURI, queryString) if err != nil { return nil, err } @@ -304,6 +312,28 @@ func GetClusterState(http *helper.HTTP, resetURI string, metrics []string) (maps return clusterState, err } +func GetIndexSettings(http *helper.HTTP, resetURI string, indexPattern string, filterPaths []string) (mapstr.M, error) { + + queryParams := []string{"local=true", "expand_wildcards=hidden,all"} + indicesSettingsURI := indexPattern + "/_settings" + + if len(filterPaths) > 0 { + filterPathQueryParam := "filter_path=" + strings.Join(filterPaths, ",") + queryParams = append(queryParams, filterPathQueryParam) + } + + queryString := strings.Join(queryParams, "&") + + content, err := fetchPath(http, resetURI, indicesSettingsURI, queryString) + if err != nil { + return nil, err + } + + var indicesSettings map[string]interface{} + err = json.Unmarshal(content, &indicesSettings) + return indicesSettings, err +} + // GetClusterSettingsWithDefaults returns cluster settings. func GetClusterSettingsWithDefaults(http *helper.HTTP, resetURI string, filterPaths []string) (mapstr.M, error) { return GetClusterSettings(http, resetURI, true, filterPaths) diff --git a/metricbeat/module/elasticsearch/fields.go b/metricbeat/module/elasticsearch/fields.go index 7fe1827b3ceb..5f899fdd0aac 100644 --- a/metricbeat/module/elasticsearch/fields.go +++ b/metricbeat/module/elasticsearch/fields.go @@ -32,5 +32,5 @@ func init() { // AssetElasticsearch returns asset data. // This is the base64 encoded zlib format compressed contents of module/elasticsearch. func AssetElasticsearch() string { - return "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" + return "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" } diff --git a/metricbeat/module/elasticsearch/index/_meta/data.json b/metricbeat/module/elasticsearch/index/_meta/data.json index 2fa8eeb4f18f..3b0dee2f9e24 100644 --- a/metricbeat/module/elasticsearch/index/_meta/data.json +++ b/metricbeat/module/elasticsearch/index/_meta/data.json @@ -144,6 +144,9 @@ } }, "status": "green", + "tier_preference": "data_content", + "creation_date": 1731657995821, + "version": "8505000", "hidden": true, "shards": { "total": 1, diff --git a/metricbeat/module/elasticsearch/index/_meta/fields.yml b/metricbeat/module/elasticsearch/index/_meta/fields.yml index 8182963959b3..ca1fdecff8d2 100644 --- a/metricbeat/module/elasticsearch/index/_meta/fields.yml +++ b/metricbeat/module/elasticsearch/index/_meta/fields.yml @@ -17,6 +17,12 @@ type: keyword - name: status type: keyword + - name: tier_preference + type: keyword + - name: creation_date + type: date + - name: version + type: keyword - name: name type: keyword description: > diff --git a/metricbeat/module/elasticsearch/index/data.go b/metricbeat/module/elasticsearch/index/data.go index d8bec4939d62..ce5fa82e4ac3 100644 --- a/metricbeat/module/elasticsearch/index/data.go +++ b/metricbeat/module/elasticsearch/index/data.go @@ -20,6 +20,7 @@ package index import ( "encoding/json" "fmt" + "strconv" "github.com/joeshaw/multierror" @@ -40,9 +41,12 @@ type Index struct { Primaries primaries `json:"primaries"` Total total `json:"total"` - Index string `json:"index"` - Status string `json:"status"` - Shards shardStats `json:"shards"` + Index string `json:"index"` + Status string `json:"status"` + TierPreference string `json:"tier_preference"` + CreationDate int `json:"creation_date"` + Version string `json:"version"` + Shards shardStats `json:"shards"` } type primaries struct { @@ -180,11 +184,19 @@ type bulkStats struct { func eventsMapping(r mb.ReporterV2, httpClient *helper.HTTP, info elasticsearch.Info, content []byte, isXpack bool) error { clusterStateMetrics := []string{"routing_table"} - clusterState, err := elasticsearch.GetClusterState(httpClient, httpClient.GetURI(), clusterStateMetrics) + clusterStateFilterPaths := []string{"routing_table"} + clusterState, err := elasticsearch.GetClusterState(httpClient, httpClient.GetURI(), clusterStateMetrics, clusterStateFilterPaths) if err != nil { return fmt.Errorf("failure retrieving cluster state from Elasticsearch: %w", err) } + indicesSettingsPattern := "*,.*" + indicesSettingsFilterPaths := []string{"*.settings.index.creation_date", "*.settings.index.**._tier_preference", "*.settings.index.version.created"} + indicesSettings, err := elasticsearch.GetIndexSettings(httpClient, httpClient.GetURI(), indicesSettingsPattern, indicesSettingsFilterPaths) + if err != nil { + return fmt.Errorf("failure retrieving index settings from Elasticsearch: %w", err) + } + var indicesStats stats if err := parseAPIResponse(content, &indicesStats); err != nil { return fmt.Errorf("failure parsing Indices Stats Elasticsearch API response: %w", err) @@ -204,6 +216,12 @@ func eventsMapping(r mb.ReporterV2, httpClient *helper.HTTP, info elasticsearch. continue } + err = addIndexSettings(&idx, indicesSettings) + if err != nil { + errs = append(errs, fmt.Errorf("failure adding index settings: %w", err)) + continue + } + event.ModuleFields.Put("cluster.id", info.ClusterID) event.ModuleFields.Put("cluster.name", info.ClusterName) @@ -271,6 +289,63 @@ func addClusterStateFields(idx *Index, clusterState mapstr.M) error { return nil } +func addIndexSettings(idx *Index, indicesSettings mapstr.M) error { + + // Recover the index settings for our specific index + indexSettingsValue, err := indicesSettings.GetValue(idx.Index) + if err != nil { + return fmt.Errorf("failed to get index settings for index %s: %w", idx.Index, err) + } + + indexSettings, ok := indexSettingsValue.(map[string]interface{}) + if !ok { + return fmt.Errorf("index settings is not a map for index: %s", idx.Index) + } + + indexCreationDate, err := getIndexSettingForIndex(indexSettings, idx.Index, "index.creation_date") + if err != nil { + return fmt.Errorf("failed to get index creation date: %w", err) + } + + idx.CreationDate, err = strconv.Atoi(indexCreationDate) + if err != nil { + return fmt.Errorf("failed to convert index creation date to int: %w", err) + } + + indexTierPreference, err := getIndexSettingForIndex(indexSettings, idx.Index, "index.routing.allocation.require._tier_preference") + if err != nil { + indexTierPreference, err = getIndexSettingForIndex(indexSettings, idx.Index, "index.routing.allocation.include._tier_preference") + if err != nil { + return fmt.Errorf("failed to get index tier preference: %w", err) + } + } + + idx.TierPreference = indexTierPreference + + indexVersion, err := getIndexSettingForIndex(indexSettings, idx.Index, "index.version.created") + if err != nil { + return fmt.Errorf("failed to get index version: %w", err) + } + + idx.Version = indexVersion + + return nil +} + +func getIndexSettingForIndex(indexSettings mapstr.M, index, settingKey string) (string, error) { + fieldKey := "settings." + settingKey + value, err := indexSettings.GetValue(fieldKey) + if err != nil { + return "", fmt.Errorf("'"+fieldKey+"': %w", err) + } + + setting, ok := value.(string) + if !ok { + return "", elastic.MakeErrorForMissingField(fieldKey, elastic.Elasticsearch) + } + return setting, nil +} + func getClusterStateMetricForIndex(clusterState mapstr.M, index, metricKey string) (mapstr.M, error) { fieldKey := metricKey + ".indices." + index value, err := clusterState.GetValue(fieldKey) @@ -308,8 +383,15 @@ func getIndexStatus(shards map[string]interface{}) (string, error) { shard := mapstr.M(s) - isPrimary := shard["primary"].(bool) - state := shard["state"].(string) + isPrimary, ok := shard["primary"].(bool) + if !ok { + return "", fmt.Errorf("%v.shards[%v].primary is not a boolean", indexName, shardIdx) + } + + state, ok := shard["state"].(string) + if !ok { + return "", fmt.Errorf("%v.shards[%v].state is not a string", indexName, shardIdx) + } if isPrimary { areAllPrimariesStarted = areAllPrimariesStarted && (state == "STARTED") @@ -357,8 +439,15 @@ func getIndexShardStats(shards mapstr.M) (*shardStats, error) { shard := mapstr.M(s) - isPrimary := shard["primary"].(bool) - state := shard["state"].(string) + isPrimary, ok := shard["primary"].(bool) + if !ok { + return nil, fmt.Errorf("%v.shards[%v].primary is not a boolean", indexName, shardIdx) + } + + state, ok := shard["state"].(string) + if !ok { + return nil, fmt.Errorf("%v.shards[%v].state is not a string", indexName, shardIdx) + } if isPrimary { primaries++ diff --git a/metricbeat/module/jolokia/_meta/Dockerfile b/metricbeat/module/jolokia/_meta/Dockerfile index 769749489acd..f70de549ce5b 100644 --- a/metricbeat/module/jolokia/_meta/Dockerfile +++ b/metricbeat/module/jolokia/_meta/Dockerfile @@ -6,7 +6,8 @@ ENV TC apache-tomcat-${TOMCAT_VERSION} ARG JOLOKIA_VERSION RUN apk update && \ - apk add curl openssl ca-certificates bash + apk upgrade --no-cache && \ + apk add curl openssl ca-certificates bash HEALTHCHECK --interval=1s --retries=90 CMD curl -f localhost:8778/jolokia/ EXPOSE 8778 diff --git a/metricbeat/module/jolokia/docker-compose.yml b/metricbeat/module/jolokia/docker-compose.yml index 6ad218468443..ddd274a2c880 100644 --- a/metricbeat/module/jolokia/docker-compose.yml +++ b/metricbeat/module/jolokia/docker-compose.yml @@ -1,5 +1,3 @@ -version: '2.3' - services: jolokia: image: docker.elastic.co/integrations-ci/beats-jolokia:${JOLOKIA_VERSION:-1.5.0}-1 diff --git a/metricbeat/module/kafka/README.md b/metricbeat/module/kafka/README.md index dc31ee0b82f0..5ecfc6b0aa1b 100644 --- a/metricbeat/module/kafka/README.md +++ b/metricbeat/module/kafka/README.md @@ -5,12 +5,18 @@ prepare an environment and manually test Kafka module. #### Kafka container -In order to have a Kafka instance up and running the best way to go is to use the container that is used by the CI tests. +In order to have a Kafka instance up and running the best way to go is to use the container that is used by the CI tests. Make sure to add below entry to `/etc/hosts` + +``` +127.0.0.1 kafka +``` + To bring this container up simply run the tests for Kafka module: `go test -tags integration ./metricbeat/module/kafka/...` + After the tests have been completed, the Kafka container should be still running. Verify with: ```console diff --git a/metricbeat/module/kafka/broker.go b/metricbeat/module/kafka/broker.go index 9d5046447300..be02b18ffc9e 100644 --- a/metricbeat/module/kafka/broker.go +++ b/metricbeat/module/kafka/broker.go @@ -19,6 +19,7 @@ package kafka import ( "crypto/tls" + "errors" "fmt" "io" "net" @@ -26,10 +27,9 @@ import ( "strings" "time" - "github.com/Shopify/sarama" - "github.com/elastic/beats/v7/libbeat/common" "github.com/elastic/beats/v7/libbeat/common/kafka" + "github.com/elastic/sarama" ) // Version returns a kafka version from its string representation @@ -302,13 +302,20 @@ func queryMetadataWithRetry( b *sarama.Broker, cfg *sarama.Config, topics []string, -) (r *sarama.MetadataResponse, err error) { - err = withRetry(b, cfg, func() (e error) { +) (*sarama.MetadataResponse, error) { + var r *sarama.MetadataResponse + var err error + + err = withRetry(b, cfg, func() error { requ := &sarama.MetadataRequest{Topics: topics} - r, e = b.GetMetadata(requ) - return + r, err = b.GetMetadata(requ) + return err }) - return + + if err != nil { + return nil, err + } + return r, nil } func closeBroker(b *sarama.Broker) { @@ -354,22 +361,20 @@ func checkRetryQuery(err error) (retry, reconnect bool) { return false, false } - if err == io.EOF { + if errors.Is(err, io.EOF) { return true, true } - k, ok := err.(sarama.KError) - if !ok { - return false, false - } - - switch k { - case sarama.ErrLeaderNotAvailable, sarama.ErrReplicaNotAvailable, - sarama.ErrOffsetsLoadInProgress, sarama.ErrRebalanceInProgress: - return true, false - case sarama.ErrRequestTimedOut, sarama.ErrBrokerNotAvailable, - sarama.ErrNetworkException: - return true, true + var k *sarama.KError + if errors.As(err, &k) { + switch *k { + case sarama.ErrLeaderNotAvailable, sarama.ErrReplicaNotAvailable, + sarama.ErrOffsetsLoadInProgress, sarama.ErrRebalanceInProgress: + return true, false + case sarama.ErrRequestTimedOut, sarama.ErrBrokerNotAvailable, + sarama.ErrNetworkException: + return true, true + } } return false, false diff --git a/metricbeat/module/kafka/consumergroup/consumergroup.go b/metricbeat/module/kafka/consumergroup/consumergroup.go index 5fa41b13f019..02d0c7a4a714 100644 --- a/metricbeat/module/kafka/consumergroup/consumergroup.go +++ b/metricbeat/module/kafka/consumergroup/consumergroup.go @@ -52,7 +52,7 @@ var debugf = logp.MakeDebug("kafka") // New creates a new instance of the MetricSet. func New(base mb.BaseMetricSet) (mb.MetricSet, error) { opts := kafka.MetricSetOptions{ - Version: "0.9.0.0", + Version: "2.2.0", } ms, err := kafka.NewMetricSet(base, opts) diff --git a/metricbeat/module/kafka/consumergroup/consumergroup_integration_test.go b/metricbeat/module/kafka/consumergroup/consumergroup_integration_test.go index aafb5250499d..85035ee7745e 100644 --- a/metricbeat/module/kafka/consumergroup/consumergroup_integration_test.go +++ b/metricbeat/module/kafka/consumergroup/consumergroup_integration_test.go @@ -25,7 +25,7 @@ import ( "testing" "time" - saramacluster "github.com/bsm/sarama-cluster" + "github.com/elastic/sarama" "github.com/elastic/beats/v7/libbeat/tests/compose" "github.com/elastic/beats/v7/metricbeat/mb" @@ -45,7 +45,7 @@ func TestData(t *testing.T) { compose.UpWithAdvertisedHostEnvFileForPort(9092), ) - c, err := startConsumer(t, service.HostForPort(9092), "metricbeat-test") + c, err := startConsumer(t, service.HostForPort(9092), "test-group") if err != nil { t.Fatal(fmt.Errorf("starting kafka consumer: %w", err)) } @@ -68,7 +68,7 @@ func TestFetch(t *testing.T) { compose.UpWithAdvertisedHostEnvFileForPort(9092), ) - c, err := startConsumer(t, service.HostForPort(9092), "metricbeat-test") + c, err := startConsumer(t, service.HostForPort(9092), "test-group") if err != nil { t.Fatal(fmt.Errorf("starting kafka consumer: %w", err)) } @@ -93,19 +93,25 @@ func TestFetch(t *testing.T) { } } -func startConsumer(t *testing.T, host string, topic string) (io.Closer, error) { +func startConsumer(t *testing.T, host string, groupID string) (io.Closer, error) { brokers := []string{host} - topics := []string{topic} - config := saramacluster.NewConfig() + + config := sarama.NewConfig() config.Net.SASL.Enable = true config.Net.SASL.User = kafkaSASLConsumerUsername config.Net.SASL.Password = kafkaSASLConsumerPassword - // The test panics unless CommitInterval is set due to the following bug in sarama: - // https://github.com/Shopify/sarama/issues/1638 - // To work around the issue we need to set CommitInterval, but now sarama emits - // a deprecation warning. - config.Consumer.Offsets.CommitInterval = 1 * time.Second - return saramacluster.NewConsumer(brokers, "test-group", topics, config) + + config.Consumer.Offsets.AutoCommit.Enable = true + config.Consumer.Offsets.AutoCommit.Interval = 1 * time.Second + + // Create a new consumer group + consumerGroup, err := sarama.NewConsumerGroup(brokers, groupID, config) + if err != nil { + t.Fatalf("Error creating consumer group: %v", err) + return nil, err + } + + return consumerGroup, nil } func getConfig(host string) map[string]interface{} { diff --git a/metricbeat/module/kafka/consumergroup/mock_test.go b/metricbeat/module/kafka/consumergroup/mock_test.go index e25abf46a075..bf8a133ccb15 100644 --- a/metricbeat/module/kafka/consumergroup/mock_test.go +++ b/metricbeat/module/kafka/consumergroup/mock_test.go @@ -21,9 +21,8 @@ import ( "fmt" "math/rand" - "github.com/Shopify/sarama" - "github.com/elastic/beats/v7/metricbeat/module/kafka" + "github.com/elastic/sarama" ) type mockClient struct { @@ -125,7 +124,7 @@ func makeFetchGroupOffsets( for i, offset := range partition { T[int32(i)] = &sarama.OffsetFetchResponseBlock{ - Offset: int64(offset), + Offset: offset, } } } diff --git a/metricbeat/module/kafka/consumergroup/query.go b/metricbeat/module/kafka/consumergroup/query.go index 1dc6bdb3c43a..b0659ef433a6 100644 --- a/metricbeat/module/kafka/consumergroup/query.go +++ b/metricbeat/module/kafka/consumergroup/query.go @@ -18,11 +18,10 @@ package consumergroup import ( - "github.com/Shopify/sarama" - "github.com/elastic/beats/v7/metricbeat/module/kafka" "github.com/elastic/elastic-agent-libs/logp" "github.com/elastic/elastic-agent-libs/mapstr" + "github.com/elastic/sarama" ) type client interface { diff --git a/metricbeat/module/kafka/docker-compose.yml b/metricbeat/module/kafka/docker-compose.yml index 9865faf5116e..76bea13fcf8c 100644 --- a/metricbeat/module/kafka/docker-compose.yml +++ b/metricbeat/module/kafka/docker-compose.yml @@ -1,5 +1,3 @@ -version: '2.3' - services: kafka: image: docker.elastic.co/integrations-ci/beats-kafka:${KAFKA_VERSION:-2.2.2}-2 diff --git a/metricbeat/module/kafka/partition/partition.go b/metricbeat/module/kafka/partition/partition.go index 486c9a79e24d..c71aa6198be4 100644 --- a/metricbeat/module/kafka/partition/partition.go +++ b/metricbeat/module/kafka/partition/partition.go @@ -21,13 +21,12 @@ import ( "errors" "fmt" - "github.com/Shopify/sarama" - "github.com/elastic/beats/v7/metricbeat/mb" "github.com/elastic/beats/v7/metricbeat/mb/parse" "github.com/elastic/beats/v7/metricbeat/module/kafka" "github.com/elastic/elastic-agent-libs/logp" "github.com/elastic/elastic-agent-libs/mapstr" + "github.com/elastic/sarama" ) // init registers the partition MetricSet with the central registry. @@ -52,7 +51,7 @@ var debugf = logp.MakeDebug("kafka") // New creates a new instance of the partition MetricSet. func New(base mb.BaseMetricSet) (mb.MetricSet, error) { opts := kafka.MetricSetOptions{ - Version: "0.8.2.0", + Version: "2.2.0", } ms, err := kafka.NewMetricSet(base, opts) @@ -125,7 +124,7 @@ func (m *MetricSet) Fetch(r mb.ReporterV2) error { err = errFailQueryOffset } - msg := fmt.Errorf("Failed to query kafka partition (%v:%v) offsets: %v", + msg := fmt.Errorf("failed to query kafka partition (%v:%v) offsets: %w", topic.Name, partition.ID, err) m.Logger().Warn(msg) r.Error(msg) diff --git a/metricbeat/module/kafka/partition/partition_integration_test.go b/metricbeat/module/kafka/partition/partition_integration_test.go index b9e91b943b92..b7d992ba6830 100644 --- a/metricbeat/module/kafka/partition/partition_integration_test.go +++ b/metricbeat/module/kafka/partition/partition_integration_test.go @@ -26,9 +26,10 @@ import ( "testing" "time" - "github.com/Shopify/sarama" "github.com/stretchr/testify/assert" + "github.com/elastic/sarama" + "github.com/elastic/beats/v7/libbeat/tests/compose" mbtest "github.com/elastic/beats/v7/metricbeat/mb/testing" "github.com/elastic/elastic-agent-libs/logp" @@ -107,13 +108,13 @@ func TestTopic(t *testing.T) { // Its possible that other topics exists -> select the right data for _, data := range dataBefore { if data.ModuleFields["topic"].(mapstr.M)["name"] == testTopic { - offsetBefore = data.MetricSetFields["offset"].(mapstr.M)["newest"].(int64) + offsetBefore, _ = data.MetricSetFields["offset"].(mapstr.M)["newest"].(int64) } } for _, data := range dataAfter { if data.ModuleFields["topic"].(mapstr.M)["name"] == testTopic { - offsetAfter = data.MetricSetFields["offset"].(mapstr.M)["newest"].(int64) + offsetAfter, _ = data.MetricSetFields["offset"].(mapstr.M)["newest"].(int64) } } diff --git a/metricbeat/module/linux/conntrack/conntrack.go b/metricbeat/module/linux/conntrack/conntrack.go index 602a786b5742..42c2114f92ce 100644 --- a/metricbeat/module/linux/conntrack/conntrack.go +++ b/metricbeat/module/linux/conntrack/conntrack.go @@ -19,6 +19,7 @@ package conntrack import ( "fmt" + "os" "github.com/prometheus/procfs" @@ -50,7 +51,10 @@ type MetricSet struct { func New(base mb.BaseMetricSet) (mb.MetricSet, error) { cfgwarn.Beta("The linux conntrack metricset is beta.") - sys := base.Module().(resolve.Resolver) + sys, ok := base.Module().(resolve.Resolver) + if !ok { + return nil, fmt.Errorf("unexpected module type: %T", base.Module()) + } return &MetricSet{ BaseMetricSet: base, @@ -68,6 +72,9 @@ func (m *MetricSet) Fetch(report mb.ReporterV2) error { } conntrackStats, err := newFS.ConntrackStat() if err != nil { + if os.IsNotExist(err) { + err = mb.PartialMetricsError{Err: fmt.Errorf("nf_conntrack kernel module not loaded: %w", err)} + } return fmt.Errorf("error fetching conntrack stats: %w", err) } diff --git a/metricbeat/module/linux/conntrack/conntrack_test.go b/metricbeat/module/linux/conntrack/conntrack_test.go index cc3b2a052306..0d1ad2a46775 100644 --- a/metricbeat/module/linux/conntrack/conntrack_test.go +++ b/metricbeat/module/linux/conntrack/conntrack_test.go @@ -18,10 +18,15 @@ package conntrack import ( + "errors" + "os" + "path/filepath" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/elastic/beats/v7/metricbeat/mb" mbtest "github.com/elastic/beats/v7/metricbeat/mb/testing" _ "github.com/elastic/beats/v7/metricbeat/module/linux" "github.com/elastic/elastic-agent-libs/mapstr" @@ -60,6 +65,23 @@ func TestFetch(t *testing.T) { assert.Equal(t, testConn, rawEvent) } +func TestFetchConntrackModuleNotLoaded(t *testing.T) { + // Create a temporary directory to simulate a missing /proc/net/stat/nf_conntrack file + tmpDir := t.TempDir() + assert.NoError(t, os.MkdirAll(filepath.Join(tmpDir, "proc/net/stat"), 0755)) + c := getConfig() + c["hostfs"] = tmpDir + + f := mbtest.NewReportingMetricSetV2Error(t, c) + events, errs := mbtest.ReportingFetchV2Error(f) + + require.Len(t, errs, 1) + err := errors.Join(errs...) + assert.ErrorAs(t, err, &mb.PartialMetricsError{}) + assert.Contains(t, err.Error(), "error fetching conntrack stats: nf_conntrack kernel module not loaded") + require.Empty(t, events) +} + func getConfig() map[string]interface{} { return map[string]interface{}{ "module": "linux", diff --git a/metricbeat/module/system/_meta/config.reference.yml b/metricbeat/module/system/_meta/config.reference.yml index 974df87cb0bc..777a6444ecae 100644 --- a/metricbeat/module/system/_meta/config.reference.yml +++ b/metricbeat/module/system/_meta/config.reference.yml @@ -81,3 +81,8 @@ # Filter systemd services based on a name pattern #service.pattern_filter: ["ssh*", "nfs*"] + + # This option enables the use of performance counters to collect data for cpu/core metricset. + # Only effective for Windows. + # You should use this option if running beats on machins with more than 64 cores. + #use_performance_counters: true diff --git a/metricbeat/module/system/core/_meta/docs.asciidoc b/metricbeat/module/system/core/_meta/docs.asciidoc index e70e55f0db71..751c4759a9c3 100644 --- a/metricbeat/module/system/core/_meta/docs.asciidoc +++ b/metricbeat/module/system/core/_meta/docs.asciidoc @@ -14,6 +14,10 @@ This metricset is available on: *`core.metrics`*:: This option controls what metrics are reported for each CPU core. The value is a list and two metric types are supported - `percentages` and `ticks`. The default value is `core.metrics: [percentages]`. +*`use_performance_counters`*:: This option enables the use of performance counters to +collect data for the CPU/core metricset. It is only effective on Windows. +You should use this option if running beats on machins with more than 64 cores. +The default value is `use_performance_counters: true` + [source,yaml] ---- @@ -21,4 +25,5 @@ metricbeat.modules: - module: system metricsets: [core] core.metrics: [percentages, ticks] + #use_performance_counters: true ---- diff --git a/metricbeat/module/system/core/config.go b/metricbeat/module/system/core/config.go index 8ac1d2f9575a..940a23282165 100644 --- a/metricbeat/module/system/core/config.go +++ b/metricbeat/module/system/core/config.go @@ -34,8 +34,9 @@ const ( // Config for the system core metricset. type Config struct { - Metrics []string `config:"core.metrics"` - CPUTicks *bool `config:"cpu_ticks"` // Deprecated. + Metrics []string `config:"core.metrics"` + CPUTicks *bool `config:"cpu_ticks"` // Deprecated. + UserPerformanceCounters bool `config:"use_performance_counters"` } // Validate validates the core config. @@ -65,5 +66,6 @@ func (c Config) Validate() (metrics.MetricOpts, error) { } var defaultConfig = Config{ - Metrics: []string{percentages}, + Metrics: []string{percentages}, + UserPerformanceCounters: true, } diff --git a/metricbeat/module/system/core/core.go b/metricbeat/module/system/core/core.go index 1bf2f3f3a3db..fc5e7b9e3945 100644 --- a/metricbeat/module/system/core/core.go +++ b/metricbeat/module/system/core/core.go @@ -41,6 +41,7 @@ type MetricSet struct { mb.BaseMetricSet opts metrics.MetricOpts cores *metrics.Monitor + sys resolve.Resolver } // New returns a new core MetricSet. @@ -58,11 +59,25 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { if config.CPUTicks != nil && *config.CPUTicks { config.Metrics = append(config.Metrics, "ticks") } - sys := base.Module().(resolve.Resolver) + sys, ok := base.Module().(resolve.Resolver) + if !ok { + return nil, fmt.Errorf("unexpected module type: %T", base.Module()) + } + + cpuOpts := make([]metrics.OptionFunc, 0) + if config.UserPerformanceCounters { + cpuOpts = append(cpuOpts, metrics.WithWindowsPerformanceCounter()) + } + cpu, err := metrics.New(sys, cpuOpts...) + if err != nil { + return nil, fmt.Errorf("error initializing system.cpu metricset: %w", err) + } + return &MetricSet{ BaseMetricSet: base, opts: opts, - cores: metrics.New(sys), + cores: cpu, + sys: sys, }, nil } @@ -109,6 +124,5 @@ func (m *MetricSet) Diagnostics() []diagnostics.DiagnosticSetup { } func (m *MetricSet) getDiagData() []byte { - sys := m.BaseMetricSet.Module().(resolve.Resolver) - return diagnostics.GetRawFileOrErrorString(sys, "/proc/stat") + return diagnostics.GetRawFileOrErrorString(m.sys, "/proc/stat") } diff --git a/metricbeat/module/system/cpu/_meta/docs.asciidoc b/metricbeat/module/system/cpu/_meta/docs.asciidoc index fb83c41e500a..b0d9da584591 100644 --- a/metricbeat/module/system/cpu/_meta/docs.asciidoc +++ b/metricbeat/module/system/cpu/_meta/docs.asciidoc @@ -15,6 +15,10 @@ This metricset is available on: is a list and three metric types are supported - `percentages`, `normalized_percentages`, and `ticks`. The default value is `cpu.metrics: [percentages]`. +*`use_performance_counters`*:: This option enables the use of performance counters to +collect data for the CPU/core metricset. It is only effective on Windows. +You should use this option if running beats on machins with more than 64 cores. +The default value is `use_performance_counters: true` + [source,yaml] ---- @@ -22,4 +26,5 @@ metricbeat.modules: - module: system metricsets: [cpu] cpu.metrics: [percentages, normalized_percentages, ticks] + #use_performance_counters: true ---- diff --git a/metricbeat/module/system/cpu/config.go b/metricbeat/module/system/cpu/config.go index ef9d78fe0ced..7cfffed57a53 100644 --- a/metricbeat/module/system/cpu/config.go +++ b/metricbeat/module/system/cpu/config.go @@ -35,8 +35,9 @@ const ( // Config for the system cpu metricset. type Config struct { - Metrics []string `config:"cpu.metrics"` - CPUTicks *bool `config:"cpu_ticks"` // Deprecated. + Metrics []string `config:"cpu.metrics"` + CPUTicks *bool `config:"cpu_ticks"` // Deprecated. + UserPerformanceCounters bool `config:"use_performance_counters"` } // Validate validates the cpu config. @@ -69,5 +70,6 @@ func (c Config) Validate() (metrics.MetricOpts, error) { } var defaultConfig = Config{ - Metrics: []string{percentages, normalizedPercentages}, + Metrics: []string{percentages, normalizedPercentages}, + UserPerformanceCounters: true, } diff --git a/metricbeat/module/system/cpu/cpu.go b/metricbeat/module/system/cpu/cpu.go index 8eb06c2427bd..ace37b809e85 100644 --- a/metricbeat/module/system/cpu/cpu.go +++ b/metricbeat/module/system/cpu/cpu.go @@ -44,6 +44,7 @@ type MetricSet struct { mb.BaseMetricSet opts metrics.MetricOpts cpu *metrics.Monitor + sys resolve.Resolver } // New is a mb.MetricSetFactory that returns a cpu.MetricSet. @@ -61,11 +62,25 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { if config.CPUTicks != nil && *config.CPUTicks { config.Metrics = append(config.Metrics, "ticks") } - sys := base.Module().(resolve.Resolver) + sys, ok := base.Module().(resolve.Resolver) + if !ok { + return nil, fmt.Errorf("unexpected module type: %T", base.Module()) + } + + cpuOpts := make([]metrics.OptionFunc, 0) + if config.UserPerformanceCounters { + cpuOpts = append(cpuOpts, metrics.WithWindowsPerformanceCounter()) + } + cpu, err := metrics.New(sys, cpuOpts...) + + if err != nil { + return nil, fmt.Errorf("error initializing system.cpu metricset: %w", err) + } return &MetricSet{ BaseMetricSet: base, opts: opts, - cpu: metrics.New(sys), + cpu: cpu, + sys: sys, }, nil } @@ -125,13 +140,11 @@ func (m *MetricSet) Diagnostics() []diagnostics.DiagnosticSetup { } func (m *MetricSet) fetchRawCPU() []byte { - sys := m.BaseMetricSet.Module().(resolve.Resolver) - return diagnostics.GetRawFileOrErrorString(sys, "/proc/stat") + return diagnostics.GetRawFileOrErrorString(m.sys, "/proc/stat") } func (m *MetricSet) fetchCPUInfo() []byte { - sys := m.BaseMetricSet.Module().(resolve.Resolver) - return diagnostics.GetRawFileOrErrorString(sys, "/proc/cpuinfo") + return diagnostics.GetRawFileOrErrorString(m.sys, "/proc/cpuinfo") } // copyFieldsOrDefault copies the field specified by key to the given map. It will diff --git a/metricbeat/module/system/network/network.go b/metricbeat/module/system/network/network.go index 97700ba66f5b..e97561f012a3 100644 --- a/metricbeat/module/system/network/network.go +++ b/metricbeat/module/system/network/network.go @@ -29,7 +29,7 @@ import ( "github.com/elastic/elastic-agent-libs/logp" "github.com/elastic/elastic-agent-libs/mapstr" - "github.com/shirou/gopsutil/v3/net" + "github.com/shirou/gopsutil/v4/net" ) var debugf = logp.MakeDebug("system-network") diff --git a/metricbeat/module/system/raid/blockinfo/getdev.go b/metricbeat/module/system/raid/blockinfo/getdev.go index 02527c806367..7c92b0fc8815 100644 --- a/metricbeat/module/system/raid/blockinfo/getdev.go +++ b/metricbeat/module/system/raid/blockinfo/getdev.go @@ -19,14 +19,15 @@ package blockinfo import ( "fmt" - "io/ioutil" "os" "path/filepath" + + "github.com/elastic/beats/v7/metricbeat/mb" ) // ListAll lists all the multi-disk devices in a RAID array func ListAll(path string) ([]MDDevice, error) { - dir, err := ioutil.ReadDir(path) + dir, err := os.ReadDir(path) if err != nil { return nil, fmt.Errorf("could not read directory: %w", err) } @@ -44,7 +45,7 @@ func ListAll(path string) ([]MDDevice, error) { } if len(mds) == 0 { - return nil, fmt.Errorf("no matches from path %s", path) + return nil, mb.PartialMetricsError{Err: fmt.Errorf("no RAID devices found. You have probably enabled the RAID metrics on a non-RAID system.")} } return mds, nil @@ -69,8 +70,5 @@ func getMDDevice(path string) (MDDevice, error) { // Right now, we're doing this by looking for an `md` directory in the device dir. func isMD(path string) bool { _, err := os.Stat(filepath.Join(path, "md")) - if err != nil { - return false - } - return true + return err == nil } diff --git a/metricbeat/module/system/raid/raid.go b/metricbeat/module/system/raid/raid.go index 191027657d7f..7b07e36c4d2d 100644 --- a/metricbeat/module/system/raid/raid.go +++ b/metricbeat/module/system/raid/raid.go @@ -41,8 +41,11 @@ type MetricSet struct { // New creates a new instance of the raid metricset. func New(base mb.BaseMetricSet) (mb.MetricSet, error) { + sys, ok := base.Module().(resolve.Resolver) + if !ok { + return nil, fmt.Errorf("unexpected module type: %T", base.Module()) + } - sys := base.Module().(resolve.Resolver) return &MetricSet{ BaseMetricSet: base, @@ -62,7 +65,7 @@ func blockto1024(b int64) int64 { func (m *MetricSet) Fetch(r mb.ReporterV2) error { devices, err := blockinfo.ListAll(m.mod.ResolveHostFS("/sys/block")) if err != nil { - return fmt.Errorf("failed to parse sysfs: %w", err) + return fmt.Errorf("failed to list RAID devices: %w", err) } for _, blockDev := range devices { diff --git a/metricbeat/module/system/raid/raid_test.go b/metricbeat/module/system/raid/raid_test.go index 4c35394413af..28b3358f685d 100644 --- a/metricbeat/module/system/raid/raid_test.go +++ b/metricbeat/module/system/raid/raid_test.go @@ -18,10 +18,14 @@ package raid import ( + "errors" + "os" + "path/filepath" "testing" "github.com/stretchr/testify/assert" + "github.com/elastic/beats/v7/metricbeat/mb" mbtest "github.com/elastic/beats/v7/metricbeat/mb/testing" _ "github.com/elastic/beats/v7/metricbeat/module/system" ) @@ -46,6 +50,22 @@ func TestFetch(t *testing.T) { events[0].BeatEvent("system", "raid").Fields.StringToPrint()) } +func TestFetchNoRAID(t *testing.T) { + // Ensure that we return partial metrics when no RAID devices are present. + tmpDir := t.TempDir() + assert.NoError(t, os.MkdirAll(filepath.Join(tmpDir, "sys/block"), 0755)) + c := getConfig() + c["hostfs"] = tmpDir + + f := mbtest.NewReportingMetricSetV2Error(t, c) + events, errs := mbtest.ReportingFetchV2Error(f) + + assert.Len(t, errs, 1) + assert.ErrorAs(t, errors.Join(errs...), &mb.PartialMetricsError{}) + assert.Contains(t, errors.Join(errs...).Error(), "failed to list RAID devices: no RAID devices found. You have probably enabled the RAID metrics on a non-RAID system.") + assert.Empty(t, events) +} + func getConfig() map[string]interface{} { return map[string]interface{}{ "module": "system", diff --git a/metricbeat/module/system/socket_summary/socket_summary.go b/metricbeat/module/system/socket_summary/socket_summary.go index 5301887413a6..a2116cbed4ed 100644 --- a/metricbeat/module/system/socket_summary/socket_summary.go +++ b/metricbeat/module/system/socket_summary/socket_summary.go @@ -18,10 +18,11 @@ package socket_summary import ( + "errors" "fmt" "syscall" - "github.com/shirou/gopsutil/v3/net" + "github.com/shirou/gopsutil/v4/net" "github.com/elastic/beats/v7/metricbeat/mb" "github.com/elastic/elastic-agent-libs/mapstr" @@ -45,14 +46,16 @@ func init() { // interface methods except for Fetch. type MetricSet struct { mb.BaseMetricSet - sockstat string - mod resolve.Resolver + mod resolve.Resolver } // New creates a new instance of the MetricSet. New is responsible for unpacking // any MetricSet specific configuration options if there are any. func New(base mb.BaseMetricSet) (mb.MetricSet, error) { - sys := base.Module().(resolve.Resolver) + sys, ok := base.Module().(resolve.Resolver) + if !ok { + return nil, errors.New("base.Module is not resolve.Resolver") + } return &MetricSet{ mod: sys, BaseMetricSet: base, diff --git a/metricbeat/module/system/socket_summary/socket_summary_test.go b/metricbeat/module/system/socket_summary/socket_summary_test.go index 172fbdb20ae5..733fccea3cbd 100644 --- a/metricbeat/module/system/socket_summary/socket_summary_test.go +++ b/metricbeat/module/system/socket_summary/socket_summary_test.go @@ -21,7 +21,7 @@ import ( "syscall" "testing" - "github.com/shirou/gopsutil/v3/net" + "github.com/shirou/gopsutil/v4/net" "github.com/stretchr/testify/assert" ) diff --git a/metricbeat/module/system/socket_summary/sockstat_linux.go b/metricbeat/module/system/socket_summary/sockstat_linux.go index 965cea3bd14f..4b9569ac2b8e 100644 --- a/metricbeat/module/system/socket_summary/sockstat_linux.go +++ b/metricbeat/module/system/socket_summary/sockstat_linux.go @@ -24,7 +24,7 @@ import ( "fmt" "os" - "github.com/shirou/gopsutil/v3/net" + "github.com/shirou/gopsutil/v4/net" "github.com/elastic/elastic-agent-libs/mapstr" "github.com/elastic/elastic-agent-system-metrics/metric/system/resolve" diff --git a/metricbeat/module/system/socket_summary/sockstat_other.go b/metricbeat/module/system/socket_summary/sockstat_other.go index e0548f3f1f3b..eda33644e10b 100644 --- a/metricbeat/module/system/socket_summary/sockstat_other.go +++ b/metricbeat/module/system/socket_summary/sockstat_other.go @@ -20,7 +20,7 @@ package socket_summary import ( - "github.com/shirou/gopsutil/v3/net" + "github.com/shirou/gopsutil/v4/net" "github.com/elastic/elastic-agent-libs/mapstr" "github.com/elastic/elastic-agent-system-metrics/metric/system/resolve" diff --git a/metricbeat/modules.d/docker.yml.disabled b/metricbeat/modules.d/docker.yml.disabled index 88af5d212889..726c535af1aa 100644 --- a/metricbeat/modules.d/docker.yml.disabled +++ b/metricbeat/modules.d/docker.yml.disabled @@ -18,6 +18,9 @@ # If set to true, replace dots in labels with `_`. #labels.dedot: false + # Docker module supports metrics collection from podman's Docker-compatible API. In case of podman set to true. + # podman: false + # Skip metrics for certain device major numbers in docker/diskio. # Necessary on systems with software RAID, device mappers, # or other configurations where virtual disks will sum metrics from other disks. diff --git a/metricbeat/tests/system/test_base.py b/metricbeat/tests/system/test_base.py index 5a5f1583203e..edee856d1144 100644 --- a/metricbeat/tests/system/test_base.py +++ b/metricbeat/tests/system/test_base.py @@ -59,7 +59,7 @@ def test_index_management(self): assert len(es.cat.templates(name='metricbeat-*', h='name')) > 0 @unittest.skipUnless(INTEGRATION_TESTS, "integration test") - @pytest.mark.timeout(8*60, func_only=True) + @pytest.mark.timeout(8 * 60, func_only=True) def test_dashboards(self): """ Test that the dashboards can be loaded with `setup --dashboards` diff --git a/packetbeat/protos/tls/parse.go b/packetbeat/protos/tls/parse.go index dbe20d44bc4c..37e04a1e9a17 100644 --- a/packetbeat/protos/tls/parse.go +++ b/packetbeat/protos/tls/parse.go @@ -18,7 +18,7 @@ package tls import ( - "crypto/dsa" //lint:ignore SA1019 Deprecated, but still used. So we have to handle it. + "crypto/dsa" //nolint:staticcheck // SA1019 Deprecated, but still used. So we have to handle it. "crypto/ecdsa" "crypto/rsa" "crypto/x509" @@ -270,7 +270,7 @@ func (parser *parser) parse(buf *streambuf.Buffer) parserResult { debugf("handshake completed") } // discard remaining data for this stream (encrypted) - buf.Advance(buf.Len()) + _ = buf.Advance(buf.Len()) return resultEncrypted case recordTypeHandshake: @@ -300,7 +300,7 @@ func (parser *parser) parse(buf *streambuf.Buffer) parserResult { } } - buf.Advance(limit) + _ = buf.Advance(limit) } if buf.Len() == 0 { @@ -350,10 +350,10 @@ func (parser *parser) bufferHandshake(buf *streambuf.Buffer, length int) (err er } if !parser.parseHandshake(header.handshakeType, bufferView{&parser.handshakeBuf, handshakeHeaderSize, limit}) { - parser.handshakeBuf.Advance(limit) + _ = parser.handshakeBuf.Advance(limit) return fmt.Errorf("bad handshake %+v", header) } - parser.handshakeBuf.Advance(limit) + _ = parser.handshakeBuf.Advance(limit) } if parser.handshakeBuf.Len() == 0 { parser.handshakeBuf.Reset() @@ -639,7 +639,7 @@ func certToMap(cert *x509.Certificate) mapstr.M { certMap := mapstr.M{ "signature_algorithm": cert.SignatureAlgorithm.String(), "public_key_algorithm": toString(cert.PublicKeyAlgorithm), - "serial_number": cert.SerialNumber.Text(10), + "serial_number": strings.ToUpper(cert.SerialNumber.Text(16)), "issuer": toMap(&cert.Issuer), "subject": toMap(&cert.Subject), "not_before": cert.NotBefore, diff --git a/packetbeat/protos/tls/parse_test.go b/packetbeat/protos/tls/parse_test.go index 7ca71e607adf..6e9f22a3e969 100644 --- a/packetbeat/protos/tls/parse_test.go +++ b/packetbeat/protos/tls/parse_test.go @@ -302,7 +302,7 @@ func TestCertificates(t *testing.T) { "not_before": "2015-11-03 00:00:00 +0000 UTC", "public_key_algorithm": "RSA", "public_key_size": "2048", - "serial_number": "19132437207909210467858529073412672688", + "serial_number": "E64C5FBC236ADE14B172AEB41C78CB0", "signature_algorithm": "SHA256-RSA", "issuer.common_name": "DigiCert SHA2 High Assurance Server CA", "issuer.country": "US", diff --git a/packetbeat/protos/tls/tls_test.go b/packetbeat/protos/tls/tls_test.go index 8d01e3bd1279..4874f90d01c6 100644 --- a/packetbeat/protos/tls/tls_test.go +++ b/packetbeat/protos/tls/tls_test.go @@ -26,8 +26,8 @@ import ( "testing" "time" - "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/beats/v7/libbeat/common" @@ -312,7 +312,7 @@ func TestOCSPStatus(t *testing.T) { "not_after": time.Date(2035, 3, 4, 9, 0, 0, 0, time.UTC), "public_key_algorithm": "RSA", "public_key_size": 4096, - "serial_number": "1492448539999078269498416841973088004758827", + "serial_number": "1121E97D5D37348C572C555A3A59B7B65D2B", "signature_algorithm": "SHA256-RSA", "subject": mapstr.M{ "common_name": "Orange Devices PKI TV LAB CA", @@ -335,7 +335,7 @@ func TestOCSPStatus(t *testing.T) { "not_before": time.Date(2020, 3, 2, 17, 0, 0, 0, time.UTC), "public_key_algorithm": "RSA", "public_key_size": 4096, - "serial_number": "1492246295378596931754418352553114016724120", + "serial_number": "112151567790FB40C755010CA9169CF4B498", "signature_algorithm": "SHA256-RSA", "subject": mapstr.M{ "common_name": "Orange Devices Root LAB CA", @@ -402,7 +402,7 @@ func TestOCSPStatus(t *testing.T) { "not_before": time.Date(2021, 6, 3, 13, 38, 16, 0, time.UTC), "public_key_algorithm": "ECDSA", "public_key_size": 256, - "serial_number": "189790697042017246339292011338547986350262673379", + "serial_number": "213E825A875EB349390D11117C6C14F894135FE3", "signature_algorithm": "SHA256-RSA", "subject": mapstr.M{ "common_name": "server2 test PKI TV LAB", @@ -421,9 +421,7 @@ func TestOCSPStatus(t *testing.T) { } got := results.events[0].Fields - if !cmp.Equal(got, want) { - t.Errorf("unexpected result: %s", cmp.Diff(got, want)) - } + require.Equal(t, want, got) } func TestFragmentedHandshake(t *testing.T) { diff --git a/packetbeat/sniffer/sniffer.go b/packetbeat/sniffer/sniffer.go index d8043032a64a..24c77180b46a 100644 --- a/packetbeat/sniffer/sniffer.go +++ b/packetbeat/sniffer/sniffer.go @@ -25,6 +25,7 @@ import ( "os" "runtime" "strings" + "sync/atomic" "time" "github.com/google/gopacket" @@ -33,7 +34,6 @@ import ( "github.com/google/gopacket/pcapgo" "golang.org/x/sync/errgroup" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/elastic-agent-libs/logp" "github.com/elastic/beats/v7/packetbeat/config" @@ -51,7 +51,7 @@ type Sniffer struct { type sniffer struct { config config.InterfaceConfig - state atomic.Int32 // store snifferState + state *atomic.Int32 // store snifferState // device is the first active device after calling New. // It is not updated by default route polling. @@ -103,13 +103,14 @@ func New(id string, testMode bool, _ string, decoders map[string]Decoders, inter return nil, fmt.Errorf("no decoder for %s", iface.Device) } child := sniffer{ - state: atomic.MakeInt32(snifferInactive), + state: &atomic.Int32{}, followDefault: iface.PollDefaultRoute > 0 && strings.HasPrefix(iface.Device, "default_route"), id: id, idx: i, decoders: dec, log: s.log, } + child.state.Store(snifferInactive) s.log.Debugf("interface: %d, BPF filter: '%s'", i, iface.BpfFilter) @@ -373,7 +374,7 @@ func (s *sniffer) sniffHandle(ctx context.Context, handle snifferHandle, dec *de // Mark inactive sniffer as active. In case of the sniffer/packetbeat closing // before/while Run is executed, the state will be snifferClosing. // => return if state is already snifferClosing. - if !s.state.CAS(snifferInactive, snifferActive) { + if !s.state.CompareAndSwap(snifferInactive, snifferActive) { return nil } defer s.state.Store(snifferInactive) diff --git a/packetbeat/tests/system/golden/established_tls-expected.json b/packetbeat/tests/system/golden/established_tls-expected.json index ddd584bbfed9..4de1087b9385 100644 --- a/packetbeat/tests/system/golden/established_tls-expected.json +++ b/packetbeat/tests/system/golden/established_tls-expected.json @@ -127,7 +127,7 @@ "not_before": "2013-03-08T12:00:00.000Z", "public_key_algorithm": "RSA", "public_key_size": 2048, - "serial_number": "2646203786665923649276728595390119057", + "serial_number": "1FDA3EB6ECA75C888438B724BCFBC91", "signature_algorithm": "SHA256-RSA", "subject": { "common_name": "DigiCert SHA2 Secure Server CA", @@ -149,7 +149,7 @@ "not_before": "2006-11-10T00:00:00.000Z", "public_key_algorithm": "RSA", "public_key_size": 2048, - "serial_number": "10944719598952040374951832963794454346", + "serial_number": "83BE056904246B1A1756AC95991C74A", "signature_algorithm": "SHA1-RSA", "subject": { "common_name": "DigiCert Global Root CA", @@ -204,7 +204,7 @@ "tls.server.x509.not_before": "2018-11-28T00:00:00.000Z", "tls.server.x509.public_key_algorithm": "RSA", "tls.server.x509.public_key_size": 2048, - "tls.server.x509.serial_number": "21020869104500376438182461249190639870", + "tls.server.x509.serial_number": "FD078DD48F1A2BD4D0F2BA96B6038FE", "tls.server.x509.signature_algorithm": "SHA256-RSA", "tls.server.x509.subject.common_name": "www.example.org", "tls.server.x509.subject.country": "US", diff --git a/packetbeat/tests/system/golden/tls_all_options-expected.json b/packetbeat/tests/system/golden/tls_all_options-expected.json index e8dcf374b1d9..95e9ebccdb2b 100644 --- a/packetbeat/tests/system/golden/tls_all_options-expected.json +++ b/packetbeat/tests/system/golden/tls_all_options-expected.json @@ -127,7 +127,7 @@ "not_before": "2013-03-08T12:00:00.000Z", "public_key_algorithm": "RSA", "public_key_size": 2048, - "serial_number": "2646203786665923649276728595390119057", + "serial_number": "1FDA3EB6ECA75C888438B724BCFBC91", "signature_algorithm": "SHA256-RSA", "subject": { "common_name": "DigiCert SHA2 Secure Server CA", @@ -149,7 +149,7 @@ "not_before": "2006-11-10T00:00:00.000Z", "public_key_algorithm": "RSA", "public_key_size": 2048, - "serial_number": "10944719598952040374951832963794454346", + "serial_number": "83BE056904246B1A1756AC95991C74A", "signature_algorithm": "SHA1-RSA", "subject": { "common_name": "DigiCert Global Root CA", @@ -211,7 +211,7 @@ "tls.server.x509.not_before": "2018-11-28T00:00:00.000Z", "tls.server.x509.public_key_algorithm": "RSA", "tls.server.x509.public_key_size": 2048, - "tls.server.x509.serial_number": "21020869104500376438182461249190639870", + "tls.server.x509.serial_number": "FD078DD48F1A2BD4D0F2BA96B6038FE", "tls.server.x509.signature_algorithm": "SHA256-RSA", "tls.server.x509.subject.common_name": "www.example.org", "tls.server.x509.subject.country": "US", diff --git a/testing/environments/docker/kafka/Dockerfile b/testing/environments/docker/kafka/Dockerfile index afb2df2d9d7c..58fbdb0ddeda 100644 --- a/testing/environments/docker/kafka/Dockerfile +++ b/testing/environments/docker/kafka/Dockerfile @@ -1,13 +1,13 @@ FROM debian:buster -ENV KAFKA_HOME /kafka +ENV KAFKA_HOME=/kafka # Controls the hostname advertised within the Docker network, should generally match the container # name in a docker-compose file. -ENV KAFKA_ADVERTISED_HOST kafka +ENV KAFKA_ADVERTISED_HOST=kafka ENV KAFKA_LOGS_DIR="/kafka-logs" -ENV KAFKA_VERSION 2.2.2 -ENV _JAVA_OPTIONS "-Djava.net.preferIPv4Stack=true" +ENV KAFKA_VERSION=2.2.2 +ENV _JAVA_OPTIONS="-Djava.net.preferIPv4Stack=true" ENV TERM=linux RUN apt-get update && apt-get install -y curl openjdk-11-jre-headless netcat-openbsd diff --git a/winlogbeat/_meta/fields.common.yml b/winlogbeat/_meta/fields.common.yml index ba2af74bb148..c1bef43568ec 100644 --- a/winlogbeat/_meta/fields.common.yml +++ b/winlogbeat/_meta/fields.common.yml @@ -27,8 +27,8 @@ required: true description: > The event log API type used to read the record. The possible values are - "wineventlog" for the Windows Event Log API or "wineventlog-experimental" for its - experimental implementation. + "wineventlog" for the Windows Event Log XML reader or "wineventlog-raw" for its + more performant implementation. - name: activity_id type: keyword diff --git a/winlogbeat/beater/acker.go b/winlogbeat/beater/acker.go index e9cc2e77c33c..d35a01664846 100644 --- a/winlogbeat/beater/acker.go +++ b/winlogbeat/beater/acker.go @@ -20,20 +20,20 @@ package beater import ( "context" "sync" + "sync/atomic" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/winlogbeat/checkpoint" ) type eventACKer struct { - active *atomic.Int + active *atomic.Int64 wg *sync.WaitGroup checkpoint *checkpoint.Checkpoint } func newEventACKer(checkpoint *checkpoint.Checkpoint) *eventACKer { return &eventACKer{ - active: atomic.NewInt(0), + active: &atomic.Int64{}, wg: &sync.WaitGroup{}, checkpoint: checkpoint, } @@ -55,7 +55,7 @@ func (a *eventACKer) ACKEvents(data []interface{}) { } // Mark events as done (subtract). - a.active.Add(-1 * len(data)) + a.active.Add(-1 * int64(len(data))) a.wg.Add(-1 * len(data)) } @@ -71,11 +71,11 @@ func (a *eventACKer) Wait(ctx context.Context) { // Add adds to the number of active events. func (a *eventACKer) Add(delta int) { - a.active.Add(delta) + a.active.Add(int64(delta)) a.wg.Add(delta) } // Active returns the number of active events (published but not yet ACKed). func (a *eventACKer) Active() int { - return a.active.Load() + return int(a.active.Load()) } diff --git a/winlogbeat/docs/fields.asciidoc b/winlogbeat/docs/fields.asciidoc index 567a78e4a911..c669e55bd3e8 100644 --- a/winlogbeat/docs/fields.asciidoc +++ b/winlogbeat/docs/fields.asciidoc @@ -16282,7 +16282,7 @@ All fields specific to the Windows Event Log are defined here. *`winlog.api`*:: + -- -The event log API type used to read the record. The possible values are "wineventlog" for the Windows Event Log API or "wineventlog-experimental" for its experimental implementation. +The event log API type used to read the record. The possible values are "wineventlog" for the Windows Event Log XML reader or "wineventlog-raw" for its more performant implementation. required: True diff --git a/winlogbeat/docs/winlogbeat-options.asciidoc b/winlogbeat/docs/winlogbeat-options.asciidoc index 27a86bc04fbe..1702561a7a66 100644 --- a/winlogbeat/docs/winlogbeat-options.asciidoc +++ b/winlogbeat/docs/winlogbeat-options.asciidoc @@ -500,24 +500,19 @@ example of how to read from an `.evtx` file in the <>. ==== `event_logs.api` This selects the event log reader implementation that is used to read events -from the Windows APIs. You should only set this option when testing experimental -features. When the value is set to `wineventlog-experimental` Winlogbeat will -replace the default event log reader with the **experimental** implementation. -We are evaluating this implementation to see if it can provide increased -performance and reduce CPU usage. *{vista_and_newer}* +from the Windows APIs. When the value is set to `wineventlog-raw` Winlogbeat will +replace the default XML event log reader with a more performant implementation. +*{vista_and_newer}* [source,yaml] -------------------------------------------------------------------------------- winlogbeat.event_logs: - name: ForwardedEvents - api: wineventlog-experimental + api: wineventlog-raw -------------------------------------------------------------------------------- -There are a few notable differences in the events: - -* Events that contained data under `winlog.user_data` will now have it under - `winlog.event_data`. -* Setting `include_xml: true` has no effect. +* If `include_xml` is `true` the performance will be the same as the default API, +as performance improvements are lost when parsing the XML. [float] diff --git a/winlogbeat/eventlog/bench_test.go b/winlogbeat/eventlog/bench_test.go index 44b25fb81f2f..97946a509b3f 100644 --- a/winlogbeat/eventlog/bench_test.go +++ b/winlogbeat/eventlog/bench_test.go @@ -60,22 +60,25 @@ func TestBenchmarkRead(t *testing.T) { for _, api := range []string{winEventLogAPIName, winEventLogExpAPIName} { t.Run("api="+api, func(t *testing.T) { - for _, batchSize := range []int{10, 100, 500, 1000} { - t.Run(fmt.Sprintf("batch_size=%d", batchSize), func(t *testing.T) { - result := testing.Benchmark(benchmarkEventLog(api, batchSize)) - outputBenchmarkResults(t, result) - }) + for _, includexml := range []bool{true, false} { + for _, batchSize := range []int{10, 100, 500, 1000} { + t.Run(fmt.Sprintf("include_xml=%v/batch_size=%d", includexml, batchSize), func(t *testing.T) { + result := testing.Benchmark(benchmarkEventLog(api, includexml, batchSize)) + outputBenchmarkResults(t, result) + }) + } } }) } } -func benchmarkEventLog(api string, batchSize int) func(b *testing.B) { +func benchmarkEventLog(api string, includexml bool, batchSize int) func(b *testing.B) { return func(b *testing.B) { conf := mapstr.M{ "name": providerName, "batch_read_size": batchSize, "no_more_events": "stop", + "include_xml": includexml, } log := openLog(b, api, nil, conf) diff --git a/winlogbeat/eventlog/cache.go b/winlogbeat/eventlog/cache.go index 3280267d0c72..985c28f433c0 100644 --- a/winlogbeat/eventlog/cache.go +++ b/winlogbeat/eventlog/cache.go @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +//go:build windows + package eventlog // This component of the eventlog package provides a cache for storing Handles @@ -26,6 +28,7 @@ import ( "github.com/elastic/beats/v7/libbeat/common" "github.com/elastic/beats/v7/winlogbeat/sys" + win "github.com/elastic/beats/v7/winlogbeat/sys/wineventlog" "github.com/elastic/elastic-agent-libs/logp" ) @@ -92,7 +95,7 @@ func newMessageFilesCache(eventLogName string, loader messageFileLoaderFunc, // If no item is cached, then one is loaded, stored, and returned. // Callers should check the MessageFiles.Err value to see if an error occurred // while loading the message files. -func (hc *messageFilesCache) get(sourceName string) sys.MessageFiles { +func (hc *messageFilesCache) get(sourceName string) win.EvtHandle { v := hc.cache.Get(sourceName) if v == nil { hc.miss() @@ -111,7 +114,12 @@ func (hc *messageFilesCache) get(sourceName string) sys.MessageFiles { // Return the existing cached value. messageFiles, _ = existing.(sys.MessageFiles) - return messageFiles + + if messageFiles.Err == nil { + // There is only ever a single handle when using the Windows Event + // Log API. + return win.EvtHandle(messageFiles.Handles[0].Handle) + } } hc.size() } else { @@ -119,7 +127,12 @@ func (hc *messageFilesCache) get(sourceName string) sys.MessageFiles { } messageFiles, _ := v.(sys.MessageFiles) - return messageFiles + if messageFiles.Err == nil { + // There is only ever a single handle when using the Windows Event + // Log API. + return win.EvtHandle(messageFiles.Handles[0].Handle) + } + return win.NilHandle } // evictionHandler is the callback handler that receives notifications when diff --git a/winlogbeat/eventlog/wineventlog.go b/winlogbeat/eventlog/wineventlog.go index 43654284218a..4fee3824122c 100644 --- a/winlogbeat/eventlog/wineventlog.go +++ b/winlogbeat/eventlog/wineventlog.go @@ -538,7 +538,7 @@ func (l *winEventLog) buildRecordFromXML(x []byte, recoveredErr error) Record { } // Get basic string values for raw fields. - winevent.EnrichRawValuesWithNames(l.winMeta(e.Provider.Name), &e) + winevent.EnrichRawValuesWithNames(l.winMeta(e.Provider.Name, l.config.EventLanguage), &e) if e.Level == "" { // Fallback on LevelRaw if the Level is not set in the RenderingInfo. e.Level = win.EventLevel(e.LevelRaw).String() @@ -605,7 +605,7 @@ func newWinMetaCache(ttl time.Duration) winMetaCache { return winMetaCache{cache: make(map[string]winMetaCacheEntry), ttl: ttl, logger: logp.L()} } -func (c *winMetaCache) winMeta(provider string) *winevent.WinMeta { +func (c *winMetaCache) winMeta(provider string, locale uint32) *winevent.WinMeta { c.mu.RLock() e, ok := c.cache[provider] c.mu.RUnlock() @@ -624,7 +624,7 @@ func (c *winMetaCache) winMeta(provider string) *winevent.WinMeta { return e.WinMeta } - s, err := win.NewPublisherMetadataStore(win.NilHandle, provider, c.logger) + s, err := win.NewPublisherMetadataStore(win.NilHandle, provider, locale, c.logger) if err != nil { // Return an empty store on error (can happen in cases where the // log was forwarded and the provider doesn't exist on collector). diff --git a/winlogbeat/eventlog/wineventlog_experimental.go b/winlogbeat/eventlog/wineventlog_raw.go similarity index 84% rename from winlogbeat/eventlog/wineventlog_experimental.go rename to winlogbeat/eventlog/wineventlog_raw.go index 126e92fdacef..7a6917e9b7ad 100644 --- a/winlogbeat/eventlog/wineventlog_experimental.go +++ b/winlogbeat/eventlog/wineventlog_raw.go @@ -28,7 +28,6 @@ import ( "go.uber.org/multierr" "golang.org/x/sys/windows" - "github.com/elastic/beats/v7/libbeat/common/cfgwarn" "github.com/elastic/beats/v7/winlogbeat/checkpoint" win "github.com/elastic/beats/v7/winlogbeat/sys/wineventlog" conf "github.com/elastic/elastic-agent-libs/config" @@ -39,19 +38,23 @@ const ( // winEventLogExpApiName is the name used to identify the Windows Event Log API // as both an event type and an API. winEventLogExpAPIName = "wineventlog-experimental" + // winEventLogRawAPIName is the name used to identify the Windows Event Log API + // as both an event type and an API. + winEventLogRawAPIName = "wineventlog-raw" ) func init() { // Register wineventlog API if it is available. available, _ := win.IsAvailable() if available { - Register(winEventLogExpAPIName, 10, newWinEventLogExp, win.Channels) + Register(winEventLogExpAPIName, 10, newWinEventLogRaw, win.Channels) + Register(winEventLogRawAPIName, 11, newWinEventLogRaw, win.Channels) } } -// winEventLogExp implements the EventLog interface for reading from the Windows +// winEventLogRaw implements the EventLog interface for reading from the Windows // Event Log API. -type winEventLogExp struct { +type winEventLogRaw struct { config winEventLogConfig query string id string // Identifier of this event log. @@ -62,21 +65,19 @@ type winEventLogExp struct { log *logp.Logger iterator *win.EventIterator - renderer *win.Renderer + renderer win.EventRenderer metrics *inputMetrics } -// newWinEventLogExp creates and returns a new EventLog for reading event logs +// newWinEventLogRaw creates and returns a new EventLog for reading event logs // using the Windows Event Log. -func newWinEventLogExp(options *conf.C) (EventLog, error) { +func newWinEventLogRaw(options *conf.C) (EventLog, error) { var xmlQuery string var err error var isFile bool var log *logp.Logger - cfgwarn.Experimental("The %s event log reader is experimental.", winEventLogExpAPIName) - c := winEventLogConfig{BatchReadSize: 512} if err := readConfig(options, &c); err != nil { return nil, err @@ -115,46 +116,60 @@ func newWinEventLogExp(options *conf.C) (EventLog, error) { log = logp.NewLogger("wineventlog").With("id", id).With("channel", c.Name) } - renderer, err := win.NewRenderer(win.NilHandle, log) - if err != nil { - return nil, err - } - - l := &winEventLogExp{ + l := &winEventLogRaw{ config: c, query: xmlQuery, id: id, channelName: c.Name, file: isFile, maxRead: c.BatchReadSize, - renderer: renderer, log: log, } + switch c.IncludeXML { + case true: + l.renderer = win.NewXMLRenderer( + win.RenderConfig{ + IsForwarded: l.isForwarded(), + Locale: c.EventLanguage, + }, + win.NilHandle, log) + case false: + l.renderer, err = win.NewRenderer( + win.RenderConfig{ + IsForwarded: l.isForwarded(), + Locale: c.EventLanguage, + }, + win.NilHandle, log) + if err != nil { + return nil, err + } + } + return l, nil } -func (l *winEventLogExp) isForwarded() bool { +func (l *winEventLogRaw) isForwarded() bool { c := l.config return (c.Forwarded != nil && *c.Forwarded) || (c.Forwarded == nil && c.Name == "ForwardedEvents") } // Name returns the name of the event log (i.e. Application, Security, etc.). -func (l *winEventLogExp) Name() string { +func (l *winEventLogRaw) Name() string { return l.id } // Channel returns the event log's channel name. -func (l *winEventLogExp) Channel() string { +func (l *winEventLogRaw) Channel() string { return l.channelName } // IsFile returns true if the event log is an evtx file. -func (l *winEventLogExp) IsFile() bool { +func (l *winEventLogRaw) IsFile() bool { return l.file } -func (l *winEventLogExp) Open(state checkpoint.EventLogState) error { +func (l *winEventLogRaw) Open(state checkpoint.EventLogState) error { l.lastRead = state // we need to defer metrics initialization since when the event log // is used from winlog input it would register it twice due to CheckConfig calls @@ -171,7 +186,7 @@ func (l *winEventLogExp) Open(state checkpoint.EventLogState) error { return err } -func (l *winEventLogExp) open(state checkpoint.EventLogState) (win.EvtHandle, error) { +func (l *winEventLogRaw) open(state checkpoint.EventLogState) (win.EvtHandle, error) { var bookmark win.Bookmark if len(state.Bookmark) > 0 { var err error @@ -188,7 +203,7 @@ func (l *winEventLogExp) open(state checkpoint.EventLogState) (win.EvtHandle, er return l.openChannel(bookmark) } -func (l *winEventLogExp) openFile(state checkpoint.EventLogState, bookmark win.Bookmark) (win.EvtHandle, error) { +func (l *winEventLogRaw) openFile(state checkpoint.EventLogState, bookmark win.Bookmark) (win.EvtHandle, error) { path := l.channelName h, err := win.EvtQuery(0, path, l.query, win.EvtQueryFilePath|win.EvtQueryForwardDirection) @@ -225,7 +240,7 @@ func (l *winEventLogExp) openFile(state checkpoint.EventLogState, bookmark win.B return h, err } -func (l *winEventLogExp) openChannel(bookmark win.Bookmark) (win.EvtHandle, error) { +func (l *winEventLogRaw) openChannel(bookmark win.Bookmark) (win.EvtHandle, error) { // Using a pull subscription to receive events. See: // https://msdn.microsoft.com/en-us/library/windows/desktop/aa385771(v=vs.85).aspx#pull signalEvent, err := windows.CreateEvent(nil, 0, 0, nil) @@ -267,7 +282,7 @@ func (l *winEventLogExp) openChannel(bookmark win.Bookmark) (win.EvtHandle, erro } } -func (l *winEventLogExp) Read() ([]Record, error) { +func (l *winEventLogRaw) Read() ([]Record, error) { //nolint:prealloc // Avoid unnecessary preallocation for each reader every second when event log is inactive. var records []Record defer func() { @@ -305,11 +320,11 @@ func (l *winEventLogExp) Read() ([]Record, error) { return records, nil } -func (l *winEventLogExp) processHandle(h win.EvtHandle) (*Record, error) { +func (l *winEventLogRaw) processHandle(h win.EvtHandle) (*Record, error) { defer h.Close() // NOTE: Render can return an error and a partial event. - evt, err := l.renderer.Render(h) + evt, xml, err := l.renderer.Render(h) if evt == nil { return nil, err } @@ -317,14 +332,15 @@ func (l *winEventLogExp) processHandle(h win.EvtHandle) (*Record, error) { evt.RenderErr = append(evt.RenderErr, err.Error()) } - //nolint:godox // Bad linter! Keep to have a record of feature disparity between non-experimental vs experimental. - // TODO: Need to add XML when configured. - r := &Record{ API: winEventLogExpAPIName, Event: *evt, } + if l.config.IncludeXML { + r.XML = xml + } + if l.file { r.File = l.id } @@ -342,7 +358,7 @@ func (l *winEventLogExp) processHandle(h win.EvtHandle) (*Record, error) { return r, nil } -func (l *winEventLogExp) createBookmarkFromEvent(evtHandle win.EvtHandle) (string, error) { +func (l *winEventLogRaw) createBookmarkFromEvent(evtHandle win.EvtHandle) (string, error) { bookmark, err := win.NewBookmarkFromEvent(evtHandle) if err != nil { return "", fmt.Errorf("failed to create new bookmark from event handle: %w", err) @@ -352,18 +368,18 @@ func (l *winEventLogExp) createBookmarkFromEvent(evtHandle win.EvtHandle) (strin return bookmark.XML() } -func (l *winEventLogExp) Reset() error { +func (l *winEventLogRaw) Reset() error { l.log.Debug("Closing event log reader handles for reset.") return l.close() } -func (l *winEventLogExp) Close() error { +func (l *winEventLogRaw) Close() error { l.log.Debug("Closing event log reader handles.") l.metrics.close() return l.close() } -func (l *winEventLogExp) close() error { +func (l *winEventLogRaw) close() error { if l.iterator == nil { return l.renderer.Close() } diff --git a/winlogbeat/eventlog/wineventlog_test.go b/winlogbeat/eventlog/wineventlog_test.go index 81e32afa373a..9aafe31a258d 100644 --- a/winlogbeat/eventlog/wineventlog_test.go +++ b/winlogbeat/eventlog/wineventlog_test.go @@ -167,14 +167,17 @@ func TestWinEventLogConfig_Validate(t *testing.T) { } func TestWindowsEventLogAPI(t *testing.T) { - testWindowsEventLog(t, winEventLogAPIName) + testWindowsEventLog(t, winEventLogAPIName, false) } -func TestWindowsEventLogAPIExperimental(t *testing.T) { - testWindowsEventLog(t, winEventLogExpAPIName) +func TestWindowsEventLogAPIRaw(t *testing.T) { + // for the raw api using include xml behave differently than not + // so we must test both settings + testWindowsEventLog(t, winEventLogRawAPIName, true) + testWindowsEventLog(t, winEventLogRawAPIName, false) } -func testWindowsEventLog(t *testing.T, api string) { +func testWindowsEventLog(t *testing.T, api string, includeXML bool) { writer, teardown := createLog(t) defer teardown() @@ -192,7 +195,7 @@ func testWindowsEventLog(t *testing.T, api string) { } t.Run("has_message", func(t *testing.T) { - log := openLog(t, map[string]interface{}{"name": providerName, "batch_read_size": 1}) + log := openLog(t, map[string]interface{}{"name": providerName, "batch_read_size": 1, "include_xml": includeXML}) defer log.Close() for i := 0; i < 10; i++ { @@ -208,8 +211,9 @@ func testWindowsEventLog(t *testing.T, api string) { // Test reading from an event log using a custom XML query. t.Run("custom_xml_query", func(t *testing.T) { cfg := map[string]interface{}{ - "id": "custom-xml-query", - "xml_query": customXMLQuery, + "id": "custom-xml-query", + "xml_query": customXMLQuery, + "include_xml": includeXML, } log := openLog(t, cfg) @@ -236,7 +240,7 @@ func testWindowsEventLog(t *testing.T, api string) { t.Run("batch_read_size_config", func(t *testing.T) { const batchReadSize = 2 - log := openLog(t, map[string]interface{}{"name": providerName, "batch_read_size": batchReadSize}) + log := openLog(t, map[string]interface{}{"name": providerName, "batch_read_size": batchReadSize, "include_xml": includeXML}) defer log.Close() records, err := log.Read() @@ -251,7 +255,7 @@ func testWindowsEventLog(t *testing.T, api string) { // When combined with large messages this causes EvtNext to fail with // RPC_S_INVALID_BOUND error. The reader should recover from the error. t.Run("large_batch_read", func(t *testing.T) { - log := openLog(t, map[string]interface{}{"name": providerName, "batch_read_size": 1024}) + log := openLog(t, map[string]interface{}{"name": providerName, "batch_read_size": 1024, "include_xml": includeXML}) defer log.Close() var eventCount int @@ -282,6 +286,7 @@ func testWindowsEventLog(t *testing.T, api string) { log := openLog(t, map[string]interface{}{ "name": path, "no_more_events": "stop", + "include_xml": includeXML, }) defer log.Close() @@ -310,6 +315,7 @@ func testWindowsEventLog(t *testing.T, api string) { "name": path, "no_more_events": "stop", "event_id": "3, 5", + "include_xml": includeXML, }) defer log.Close() @@ -401,8 +407,8 @@ func openLog(t testing.TB, api string, state *checkpoint.EventLogState, config m switch api { case winEventLogAPIName: log, err = newWinEventLog(cfg) - case winEventLogExpAPIName: - log, err = newWinEventLogExp(cfg) + case winEventLogRawAPIName: + log, err = newWinEventLogRaw(cfg) default: t.Fatalf("Unknown API name: '%s'", api) } diff --git a/winlogbeat/include/fields.go b/winlogbeat/include/fields.go index b40185bdf54c..e372ca95ed2e 100644 --- a/winlogbeat/include/fields.go +++ b/winlogbeat/include/fields.go @@ -32,5 +32,5 @@ func init() { // AssetBuildFieldsFieldsCommonYml returns asset data. // This is the base64 encoded zlib format compressed contents of build/fields/fields.common.yml. func AssetBuildFieldsFieldsCommonYml() string { - return "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" + return "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" } diff --git a/winlogbeat/sys/wineventlog/format_message_test.go b/winlogbeat/sys/wineventlog/format_message_test.go index b2090528104a..c677bc148acb 100644 --- a/winlogbeat/sys/wineventlog/format_message_test.go +++ b/winlogbeat/sys/wineventlog/format_message_test.go @@ -33,7 +33,7 @@ func TestFormatMessage(t *testing.T) { evtHandle := mustNextHandle(t, log) defer evtHandle.Close() - publisherMetadata, err := NewPublisherMetadata(NilHandle, "Microsoft-Windows-Security-Auditing") + publisherMetadata, err := NewPublisherMetadata(NilHandle, "Microsoft-Windows-Security-Auditing", 0) if err != nil { t.Fatal(err) } diff --git a/winlogbeat/sys/wineventlog/metadata_store.go b/winlogbeat/sys/wineventlog/metadata_store.go index 13d818071afc..4373451717a1 100644 --- a/winlogbeat/sys/wineventlog/metadata_store.go +++ b/winlogbeat/sys/wineventlog/metadata_store.go @@ -25,6 +25,7 @@ import ( "strings" "sync" "text/template" + "text/template/parse" "go.uber.org/multierr" @@ -54,19 +55,24 @@ type PublisherMetadataStore struct { // Event ID to map of fingerprints to event metadata. The fingerprint value // is hash of the event data parameters count and types. EventFingerprints map[uint16]map[uint64]*EventMetadata + // Stores used messages by their ID. Message can be found in events as references + // such as %%1111. This need to be formatted the first time, and they are stored + // from that point after. + MessagesByID map[uint32]string mutex sync.RWMutex log *logp.Logger } -func NewPublisherMetadataStore(session EvtHandle, provider string, log *logp.Logger) (*PublisherMetadataStore, error) { - md, err := NewPublisherMetadata(session, provider) +func NewPublisherMetadataStore(session EvtHandle, provider string, locale uint32, log *logp.Logger) (*PublisherMetadataStore, error) { + md, err := NewPublisherMetadata(session, provider, locale) if err != nil { return nil, err } store := &PublisherMetadataStore{ Metadata: md, EventFingerprints: map[uint16]map[uint64]*EventMetadata{}, + MessagesByID: map[uint32]string{}, log: log.With("publisher", provider), } @@ -98,6 +104,7 @@ func NewEmptyPublisherMetadataStore(provider string, log *logp.Logger) *Publishe }, Events: map[uint16]*EventMetadata{}, EventFingerprints: map[uint16]map[uint64]*EventMetadata{}, + MessagesByID: map[uint32]string{}, log: log.With("publisher", provider, "empty", true), } } @@ -268,6 +275,45 @@ func (s *PublisherMetadataStore) getEventMetadata(eventID uint16, eventDataFinge return em } +// getMessageByID returns the rendered message from its ID. If it is not cached it will format it. +// In case of any error this never fails, and will return the original reference instead. +func (s *PublisherMetadataStore) getMessageByID(messageID uint32) string { + // Use a read lock to get a cached value. + s.mutex.RLock() + message, found := s.MessagesByID[messageID] + if found { + s.mutex.RUnlock() + return message + } + + // Elevate to write lock. + s.mutex.RUnlock() + s.mutex.Lock() + defer s.mutex.Unlock() + + message, found = s.MessagesByID[messageID] + if found { + return message + } + + handle := NilHandle + if s.Metadata != nil { + handle = s.Metadata.Handle + } + + message, err := evtFormatMessage(handle, NilHandle, messageID, nil, EvtFormatMessageId) + if err != nil { + s.log.Debugw("Failed to format message. "+ + "Will not try to format it anymore", + "message_id", messageID, + "error", err) + message = fmt.Sprintf("%%%%%d", messageID) + } + + s.MessagesByID[messageID] = message + return message +} + func (s *PublisherMetadataStore) Close() error { if s.Metadata != nil { s.mutex.Lock() @@ -284,6 +330,7 @@ type EventMetadata struct { MsgStatic string // Used when the message has no parameters. MsgTemplate *template.Template `json:"-"` // Template that expects an array of values as its data. EventData []EventData // Names of parameters from XML template. + HasUserData bool // Event has a UserData section or not. } // newEventMetadataFromEventHandle collects metadata about an event type using @@ -310,6 +357,7 @@ func newEventMetadataFromEventHandle(publisher *PublisherMetadata, eventHandle E em.EventData = append(em.EventData, EventData{Name: pair.Key}) } } else { + em.HasUserData = true for _, pair := range event.UserData.Pairs { em.EventData = append(em.EventData, EventData{Name: pair.Key}) } @@ -420,16 +468,29 @@ func (em *EventMetadata) setMessage(msg string) error { return fmt.Errorf("failed to parse message template for event ID %v (template='%v'): %w", em.EventID, msg, err) } - // One node means there were no parameters so this will optimize that case - // by using a static string rather than a text/template. - if len(tmpl.Root.Nodes) == 1 { - em.MsgStatic = msg - } else { + // If there is no dynamic content in the template then we can use a static message. + if containsTemplatedValues(tmpl) { em.MsgTemplate = tmpl + } else { + em.MsgStatic = msg } return nil } +// containsTemplatedValues traverses the template nodes to check if there are +// any dynamic values. +func containsTemplatedValues(tmpl *template.Template) bool { + // Walk through the parsed nodes and look for actionable template nodes + for _, node := range tmpl.Tree.Root.Nodes { + switch node.(type) { + case *parse.ActionNode, *parse.CommandNode, + *parse.IfNode, *parse.RangeNode, *parse.WithNode: + return true + } + } + return false +} + func (em *EventMetadata) equal(other *EventMetadata) bool { if em == other { return true @@ -455,6 +516,82 @@ func (em *EventMetadata) equal(other *EventMetadata) bool { eventDataNamesEqual(em.EventData, other.EventData) } +type publisherMetadataCache struct { + // Mutex to guard the metadataCache. The other members are immutable. + mutex sync.RWMutex + // Cache of publisher metadata. Maps publisher names to stored metadata. + metadataCache map[string]*PublisherMetadataStore + locale uint32 + session EvtHandle + log *logp.Logger +} + +func newPublisherMetadataCache(session EvtHandle, locale uint32, log *logp.Logger) *publisherMetadataCache { + return &publisherMetadataCache{ + metadataCache: map[string]*PublisherMetadataStore{}, + locale: locale, + session: session, + log: log.Named("publisher_metadata_cache"), + } +} + +// getPublisherStore returns a PublisherMetadataStore for the provider. It +// never returns nil, as if it does not exists it tries to initialise it, +// but may return an error if it couldn't open a publisher. +func (c *publisherMetadataCache) getPublisherStore(publisher string) (*PublisherMetadataStore, error) { + var err error + + // NOTE: This code uses double-check locking to elevate to a write-lock + // when a cache value needs initialized. + c.mutex.RLock() + + // Lookup cached value. + md, found := c.metadataCache[publisher] + if !found { + // Elevate to write lock. + c.mutex.RUnlock() + c.mutex.Lock() + defer c.mutex.Unlock() + + // Double-check if the condition changed while upgrading the lock. + md, found = c.metadataCache[publisher] + if found { + return md, nil + } + + // Load metadata from the publisher. + md, err = NewPublisherMetadataStore(c.session, publisher, c.locale, c.log) + if err != nil { + // Return an empty store on error (can happen in cases where the + // log was forwarded and the provider doesn't exist on collector). + md = NewEmptyPublisherMetadataStore(publisher, c.log) + err = fmt.Errorf("failed to load publisher metadata for %v "+ + "(returning an empty metadata store): %w", publisher, err) + } + c.metadataCache[publisher] = md + } else { + c.mutex.RUnlock() + } + + return md, err +} + +func (c *publisherMetadataCache) close() error { + if c == nil { + return nil + } + c.mutex.Lock() + defer c.mutex.Unlock() + + errs := []error{} + for _, md := range c.metadataCache { + if err := md.Close(); err != nil { + errs = append(errs, err) + } + } + return multierr.Combine(errs...) +} + // --- Template Funcs // eventParam return an event data value inside a text/template. diff --git a/winlogbeat/sys/wineventlog/metadata_store_test.go b/winlogbeat/sys/wineventlog/metadata_store_test.go index 2ee7ef9dcebb..86b02edd6815 100644 --- a/winlogbeat/sys/wineventlog/metadata_store_test.go +++ b/winlogbeat/sys/wineventlog/metadata_store_test.go @@ -33,6 +33,7 @@ func TestPublisherMetadataStore(t *testing.T) { s, err := NewPublisherMetadataStore( NilHandle, "Microsoft-Windows-Security-Auditing", + 0, logp.NewLogger("metadata")) if err != nil { t.Fatal(err) diff --git a/winlogbeat/sys/wineventlog/publisher_metadata.go b/winlogbeat/sys/wineventlog/publisher_metadata.go index eb99bfb43ce5..2e5ed2411c5b 100644 --- a/winlogbeat/sys/wineventlog/publisher_metadata.go +++ b/winlogbeat/sys/wineventlog/publisher_metadata.go @@ -42,7 +42,7 @@ func (m *PublisherMetadata) Close() error { // NewPublisherMetadata opens the publisher's metadata. Close must be called on // the returned PublisherMetadata to release its handle. -func NewPublisherMetadata(session EvtHandle, name string) (*PublisherMetadata, error) { +func NewPublisherMetadata(session EvtHandle, name string, locale uint32) (*PublisherMetadata, error) { var publisherName, logFile *uint16 if info, err := os.Stat(name); err == nil && info.Mode().IsRegular() { logFile, err = syscall.UTF16PtrFromString(name) diff --git a/winlogbeat/sys/wineventlog/publisher_metadata_test.go b/winlogbeat/sys/wineventlog/publisher_metadata_test.go index f2daa0b69cf8..8851407f9f9d 100644 --- a/winlogbeat/sys/wineventlog/publisher_metadata_test.go +++ b/winlogbeat/sys/wineventlog/publisher_metadata_test.go @@ -39,7 +39,7 @@ func TestPublisherMetadata(t *testing.T) { func testPublisherMetadata(t *testing.T, provider string) { t.Run(provider, func(t *testing.T) { - md, err := NewPublisherMetadata(NilHandle, provider) + md, err := NewPublisherMetadata(NilHandle, provider, 0) if err != nil { t.Fatalf("%+v", err) } @@ -224,6 +224,6 @@ func testPublisherMetadata(t *testing.T, provider string) { } func TestNewPublisherMetadataUnknown(t *testing.T) { - _, err := NewPublisherMetadata(NilHandle, "Fake-Publisher") + _, err := NewPublisherMetadata(NilHandle, "Fake-Publisher", 0) assert.ErrorIs(t, err, fs.ErrNotExist) } diff --git a/winlogbeat/sys/wineventlog/renderer.go b/winlogbeat/sys/wineventlog/renderer.go index 4471b7b6affc..6b7042d25dd1 100644 --- a/winlogbeat/sys/wineventlog/renderer.go +++ b/winlogbeat/sys/wineventlog/renderer.go @@ -23,8 +23,11 @@ import ( "encoding/binary" "errors" "fmt" + "io" + "regexp" "strconv" - "sync" + "strings" + "syscall" "text/template" "time" "unsafe" @@ -38,21 +41,27 @@ import ( "github.com/elastic/elastic-agent-libs/logp" ) +type RenderConfig struct { + IsForwarded bool + Locale uint32 +} + +type EventRenderer interface { + Render(handle EvtHandle) (event *winevent.Event, xml string, err error) + Close() error +} + // Renderer is used for converting event log handles into complete events. type Renderer struct { - // Mutex to guard the metadataCache. The other members are immutable. - mutex sync.RWMutex - // Cache of publisher metadata. Maps publisher names to stored metadata. - metadataCache map[string]*PublisherMetadataStore - - session EvtHandle // Session handle if working with remote log. + conf RenderConfig + metadataCache *publisherMetadataCache systemContext EvtHandle // Render context for system values. userContext EvtHandle // Render context for user values (event data). log *logp.Logger } // NewRenderer returns a new Renderer. -func NewRenderer(session EvtHandle, log *logp.Logger) (*Renderer, error) { +func NewRenderer(conf RenderConfig, session EvtHandle, log *logp.Logger) (*Renderer, error) { systemContext, err := _EvtCreateRenderContext(0, nil, EvtRenderContextSystem) if err != nil { return nil, fmt.Errorf("failed in EvtCreateRenderContext for system context: %w", err) @@ -63,12 +72,14 @@ func NewRenderer(session EvtHandle, log *logp.Logger) (*Renderer, error) { return nil, fmt.Errorf("failed in EvtCreateRenderContext for user context: %w", err) } + rlog := log.Named("renderer") + return &Renderer{ - metadataCache: map[string]*PublisherMetadataStore{}, - session: session, + conf: conf, + metadataCache: newPublisherMetadataCache(session, conf.Locale, rlog), systemContext: systemContext, userContext: userContext, - log: log.Named("renderer"), + log: rlog, }, nil } @@ -77,24 +88,19 @@ func (r *Renderer) Close() error { if r == nil { return errors.New("closing nil renderer") } - r.mutex.Lock() - defer r.mutex.Unlock() - - errs := []error{r.systemContext.Close(), r.userContext.Close()} - for _, md := range r.metadataCache { - if err := md.Close(); err != nil { - errs = append(errs, err) - } - } - return multierr.Combine(errs...) + return multierr.Combine( + r.metadataCache.close(), + r.systemContext.Close(), + r.userContext.Close(), + ) } // Render renders the event handle into an Event. -func (r *Renderer) Render(handle EvtHandle) (*winevent.Event, error) { +func (r *Renderer) Render(handle EvtHandle) (*winevent.Event, string, error) { event := &winevent.Event{} if err := r.renderSystem(handle, event); err != nil { - return nil, fmt.Errorf("failed to render system properties: %w", err) + return nil, "", fmt.Errorf("failed to render system properties: %w", err) } // From this point on it will return both the event and any errors. It's @@ -102,15 +108,19 @@ func (r *Renderer) Render(handle EvtHandle) (*winevent.Event, error) { var errs []error // This always returns a non-nil value (even on error). - md, err := r.getPublisherMetadata(event.Provider.Name) + md, err := r.metadataCache.getPublisherStore(event.Provider.Name) if err != nil { errs = append(errs, err) } // Associate raw system properties to names (e.g. level=2 to Error). winevent.EnrichRawValuesWithNames(&md.WinMeta, event) + if event.Level == "" { + // Fallback on LevelRaw if the Level is not set in the RenderingInfo. + event.Level = EventLevel(event.LevelRaw).String() + } - eventData, fingerprint, err := r.renderUser(handle, event) + eventData, fingerprint, err := r.renderUser(md, handle, event) if err != nil { errs = append(errs, fmt.Errorf("failed to render event data: %w", err)) } @@ -121,54 +131,14 @@ func (r *Renderer) Render(handle EvtHandle) (*winevent.Event, error) { // Associate key names with the event data values. r.addEventData(eventMeta, eventData, event) - if event.Message, err = r.formatMessage(md, eventMeta, handle, eventData, uint16(event.EventIdentifier.ID)); err != nil { + if event.Message, err = r.formatMessage(md.Metadata, eventMeta, handle, eventData, uint16(event.EventIdentifier.ID)); err != nil { errs = append(errs, fmt.Errorf("failed to get the event message string: %w", err)) } if len(errs) > 0 { - return event, multierr.Combine(errs...) + return event, "", multierr.Combine(errs...) } - return event, nil -} - -// getPublisherMetadata return a PublisherMetadataStore for the provider. It -// never returns nil, but may return an error if it couldn't open a publisher. -func (r *Renderer) getPublisherMetadata(publisher string) (*PublisherMetadataStore, error) { - var err error - - // NOTE: This code uses double-check locking to elevate to a write-lock - // when a cache value needs initialized. - r.mutex.RLock() - - // Lookup cached value. - md, found := r.metadataCache[publisher] - if !found { - // Elevate to write lock. - r.mutex.RUnlock() - r.mutex.Lock() - defer r.mutex.Unlock() - - // Double-check if the condition changed while upgrading the lock. - md, found = r.metadataCache[publisher] - if found { - return md, nil - } - - // Load metadata from the publisher. - md, err = NewPublisherMetadataStore(r.session, publisher, r.log) - if err != nil { - // Return an empty store on error (can happen in cases where the - // log was forwarded and the provider doesn't exist on collector). - md = NewEmptyPublisherMetadataStore(publisher, r.log) - err = fmt.Errorf("failed to load publisher metadata for %v "+ - "(returning an empty metadata store): %w", publisher, err) - } - r.metadataCache[publisher] = md - } else { - r.mutex.RUnlock() - } - - return md, err + return event, "", nil } // renderSystem writes all the system context properties into the event. @@ -242,7 +212,7 @@ func (r *Renderer) renderSystem(handle EvtHandle, event *winevent.Event) error { // renderUser returns the event/user data values. This does not provide the // parameter names. It computes a fingerprint of the values types to help the // caller match the correct names to the returned values. -func (r *Renderer) renderUser(handle EvtHandle, event *winevent.Event) (values []interface{}, fingerprint uint64, err error) { +func (r *Renderer) renderUser(mds *PublisherMetadataStore, handle EvtHandle, event *winevent.Event) (values []interface{}, fingerprint uint64, err error) { bb, propertyCount, err := r.render(r.userContext, handle) if err != nil { return nil, 0, fmt.Errorf("failed to get user values: %w", err) @@ -277,11 +247,27 @@ func (r *Renderer) renderUser(handle EvtHandle, event *winevent.Event) (values [ "error", err, ) } + if str, ok := values[i].(string); ok { + values[i] = expandMessageIDs(mds, str) + } } return values, argumentHash.Sum64(), nil } +var messageIDsRegexp = regexp.MustCompile(`%%\d+`) + +func expandMessageIDs(mds *PublisherMetadataStore, v string) string { + // Replace each occurrence by finding a message based on its value + return messageIDsRegexp.ReplaceAllStringFunc(v, func(match string) string { + messageID, err := strconv.Atoi(strings.Trim(match, `%`)) + if err != nil { + return match + } + return mds.getMessageByID(uint32(messageID)) + }) +} + // render uses EvtRender to event data. The caller must free() the returned when // done accessing the bytes. func (r *Renderer) render(context EvtHandle, eventHandle EvtHandle) (*sys.PooledByteBuffer, int, error) { @@ -342,6 +328,7 @@ func (r *Renderer) addEventData(evtMeta *EventMetadata, values []interface{}, ev return "param" + strconv.Itoa(idx) } + pairs := make([]winevent.KeyValue, len(values)) for i, v := range values { var strVal string switch t := v.(type) { @@ -353,15 +340,21 @@ func (r *Renderer) addEventData(evtMeta *EventMetadata, values []interface{}, ev strVal = fmt.Sprintf("%v", v) } - event.EventData.Pairs = append(event.EventData.Pairs, winevent.KeyValue{ + pairs[i] = winevent.KeyValue{ Key: paramName(i), Value: strVal, - }) + } + } + + if evtMeta != nil && evtMeta.HasUserData { + event.UserData.Pairs = pairs + } else { + event.EventData.Pairs = pairs } } // formatMessage adds the message to the event. -func (r *Renderer) formatMessage(publisherMeta *PublisherMetadataStore, +func (r *Renderer) formatMessage(publisherMeta *PublisherMetadata, eventMeta *EventMetadata, eventHandle EvtHandle, values []interface{}, eventID uint16) (string, error, ) { @@ -375,11 +368,13 @@ func (r *Renderer) formatMessage(publisherMeta *PublisherMetadataStore, // Fallback to the trying EvtFormatMessage mechanism. // This is the path for forwarded events in RenderedText mode where the - // local publisher metadata is not present. NOTE that if the local publisher - // metadata exists it will be preferred over the RenderedText. A config - // option might be desirable to control this behavior. + // local publisher metadata is not present. r.log.Debugf("Falling back to EvtFormatMessage for event ID %d.", eventID) - return getMessageString(publisherMeta.Metadata, eventHandle, 0, nil) + metadata := publisherMeta + if r.conf.IsForwarded { + metadata = nil + } + return getMessageString(metadata, eventHandle, 0, nil) } // formatMessageFromTemplate creates the message by executing the stored Go @@ -394,3 +389,119 @@ func (r *Renderer) formatMessageFromTemplate(msgTmpl *template.Template, values return string(bb.Bytes()), nil } + +// XMLRenderer is used for converting event log handles into complete events. +type XMLRenderer struct { + conf RenderConfig + metadataCache *publisherMetadataCache + renderBuf []byte + outBuf *sys.ByteBuffer + + render func(event EvtHandle, out io.Writer) error // Function for rendering the event to XML. + + log *logp.Logger +} + +// NewXMLRenderer returns a new Renderer. +func NewXMLRenderer(conf RenderConfig, session EvtHandle, log *logp.Logger) *XMLRenderer { + const renderBufferSize = 1 << 19 // 512KB, 256K wide characters + rlog := log.Named("xml_renderer") + r := &XMLRenderer{ + conf: conf, + renderBuf: make([]byte, renderBufferSize), + outBuf: sys.NewByteBuffer(renderBufferSize), + metadataCache: newPublisherMetadataCache(session, conf.Locale, rlog), + log: rlog, + } + // Forwarded events should be rendered using RenderEventXML. It is more + // efficient and does not attempt to use local message files for rendering + // the event's message. + switch conf.IsForwarded { + case true: + r.render = func(event EvtHandle, out io.Writer) error { + return RenderEventXML(event, r.renderBuf, out) + } + case false: + r.render = func(event EvtHandle, out io.Writer) error { + get := func(providerName string) EvtHandle { + md, _ := r.metadataCache.getPublisherStore(providerName) + if md.Metadata != nil { + return md.Metadata.Handle + } + return NilHandle + } + return RenderEvent(event, conf.Locale, r.renderBuf, get, out) + } + } + return r +} + +// Close closes all handles held by the Renderer. +func (r *XMLRenderer) Close() error { + if r == nil { + return errors.New("closing nil renderer") + } + return r.metadataCache.close() +} + +// Render renders the event handle into an Event. +func (r *XMLRenderer) Render(handle EvtHandle) (*winevent.Event, string, error) { + // From this point on it will return both the event and any errors. It's + // critical to not drop data. + var errs []error + + r.outBuf.Reset() + err := r.render(handle, r.outBuf) + if err != nil { + errs = append(errs, err) + } + outBytes := r.outBuf.Bytes() + event := r.buildEventFromXML(outBytes, err) + + // This always returns a non-nil value (even on error). + md, err := r.metadataCache.getPublisherStore(event.Provider.Name) + if err != nil { + errs = append(errs, err) + } + + // Associate raw system properties to names (e.g. level=2 to Error). + winevent.EnrichRawValuesWithNames(&md.WinMeta, event) + if event.Level == "" { + // Fallback on LevelRaw if the Level is not set in the RenderingInfo. + event.Level = EventLevel(event.LevelRaw).String() + } + + if event.Message == "" && !r.conf.IsForwarded { + if event.Message, err = getMessageString(md.Metadata, handle, 0, nil); err != nil { + errs = append(errs, fmt.Errorf("failed to get the event message string: %w", err)) + } + } + + if len(errs) > 0 { + return event, string(outBytes), multierr.Combine(errs...) + } + return event, string(outBytes), nil +} + +func (r *XMLRenderer) buildEventFromXML(x []byte, recoveredErr error) *winevent.Event { + e, err := winevent.UnmarshalXML(x) + if err != nil { + e.RenderErr = append(e.RenderErr, err.Error()) + } + + err = winevent.PopulateAccount(&e.User) + if err != nil { + r.log.Debugf("SID %s account lookup failed. %v", + e.User.Identifier, err) + } + + if e.RenderErrorCode != 0 { + // Convert the render error code to an error message that can be + // included in the "error.message" field. + e.RenderErr = append(e.RenderErr, syscall.Errno(e.RenderErrorCode).Error()) + } else if recoveredErr != nil { + e.RenderErr = append(e.RenderErr, recoveredErr.Error()) + } + + return &e +} diff --git a/winlogbeat/sys/wineventlog/renderer_test.go b/winlogbeat/sys/wineventlog/renderer_test.go index 026082df5a5f..01089b5a112e 100644 --- a/winlogbeat/sys/wineventlog/renderer_test.go +++ b/winlogbeat/sys/wineventlog/renderer_test.go @@ -26,13 +26,13 @@ import ( "runtime" "strconv" "strings" + "sync/atomic" "testing" "text/template" "time" "github.com/stretchr/testify/assert" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/winlogbeat/sys/winevent" "github.com/elastic/elastic-agent-libs/logp" ) @@ -44,7 +44,7 @@ func TestRenderer(t *testing.T) { log := openLog(t, sysmon9File) defer log.Close() - r, err := NewRenderer(NilHandle, logp.L()) + r, err := NewRenderer(RenderConfig{}, NilHandle, logp.L()) if err != nil { t.Fatal(err) } @@ -62,7 +62,7 @@ func TestRenderer(t *testing.T) { log := openLog(t, security4752File) defer log.Close() - r, err := NewRenderer(NilHandle, logp.L()) + r, err := NewRenderer(RenderConfig{}, NilHandle, logp.L()) if err != nil { t.Fatal(err) } @@ -108,7 +108,7 @@ func TestRenderer(t *testing.T) { log := openLog(t, winErrorReportingFile) defer log.Close() - r, err := NewRenderer(NilHandle, logp.L()) + r, err := NewRenderer(RenderConfig{}, NilHandle, logp.L()) if err != nil { t.Fatal(err) } @@ -148,6 +148,68 @@ func TestRenderer(t *testing.T) { logAsJSON(t, events) } }) + + t.Run(filepath.Base(security4738File), func(t *testing.T) { + log := openLog(t, security4738File) + defer log.Close() + + r, err := NewRenderer(RenderConfig{}, NilHandle, logp.L()) + if err != nil { + t.Fatal(err) + } + defer r.Close() + + events := renderAllEvents(t, log, r, false) + if !assert.Len(t, events, 2) { + return + } + e := events[0] + + assert.EqualValues(t, 4738, e.EventIdentifier.ID) + assert.Equal(t, "Microsoft-Windows-Security-Auditing", e.Provider.Name) + assertEqualIgnoreCase(t, "{54849625-5478-4994-a5ba-3e3b0328c30d}", e.Provider.GUID) + assert.Equal(t, "WIN-41OB2LO92CR", e.Computer) + assert.Equal(t, "Security", e.Channel) + assert.EqualValues(t, 2866, e.RecordID) + + assert.Equal(t, e.Keywords, []string{"Audit Success"}) + + assert.NotNil(t, 0, e.OpcodeRaw) + assert.EqualValues(t, 0, *e.OpcodeRaw) + assert.Equal(t, "Info", e.Opcode) + + assert.EqualValues(t, 0, e.LevelRaw) + assert.Equal(t, "Information", e.Level) + + assert.EqualValues(t, 13824, e.TaskRaw) + assert.Equal(t, "User Account Management", e.Task) + + assert.EqualValues(t, 780, e.Execution.ProcessID) + assert.EqualValues(t, 808, e.Execution.ThreadID) + assert.Len(t, e.EventData.Pairs, 27) + + assert.NotEmpty(t, e.Message) + + // Check for message replacements in form of %%xxxx + for _, p := range e.EventData.Pairs { + switch p.Key { + case "HomeDirectory", "HomePath", + "ScriptPath", "ProfilePath", "UserWorkstations", + "UserParameters": + assert.EqualValues(t, "", p.Value) + case "AccountExpires": + assert.EqualValues(t, "", p.Value) + case "Logon Hours": + assert.EqualValues(t, "All", p.Value) + case "UserAccountControl": + assert.EqualValues(t, "\r\n\t\t'Don't Expire Password' - Enabled", p.Value) + } + } + + if t.Failed() { + logAsJSON(t, events) + } + }) } func TestTemplateFunc(t *testing.T) { @@ -178,9 +240,9 @@ func renderAllEvents(t *testing.T, log EvtHandle, renderer *Renderer, ignoreMiss func() { defer h.Close() - evt, err := renderer.Render(h) + evt, _, err := renderer.Render(h) if err != nil { - md := renderer.metadataCache[evt.Provider.Name] + md, _ := renderer.metadataCache.getPublisherStore(evt.Provider.Name) if !ignoreMissingMetadataError || md.Metadata != nil { t.Fatalf("Render failed: %+v", err) } @@ -220,7 +282,7 @@ func BenchmarkRenderer(b *testing.B) { b.Fatal(err) } - r, err := NewRenderer(NilHandle, logp.NewLogger("bench")) + r, err := NewRenderer(RenderConfig{}, NilHandle, logp.NewLogger("bench")) if err != nil { log.Close() itr.Close() @@ -235,7 +297,7 @@ func BenchmarkRenderer(b *testing.B) { defer itr.Close() defer r.Close() - count := atomic.NewUint64(0) + count := atomic.Uint64{} start := time.Now() b.ResetTimer() @@ -247,12 +309,12 @@ func BenchmarkRenderer(b *testing.B) { } // Render it. - _, err := r.Render(h) + _, _, err := r.Render(h) if err != nil { b.Fatal(err) } - count.Inc() + count.Add(1) } elapsed := time.Since(start) @@ -264,7 +326,7 @@ func BenchmarkRenderer(b *testing.B) { defer itr.Close() defer r.Close() - count := atomic.NewUint64(0) + var count atomic.Uint64 start := time.Now() b.ResetTimer() @@ -277,11 +339,11 @@ func BenchmarkRenderer(b *testing.B) { } // Render it. - _, err := r.Render(h) + _, _, err := r.Render(h) if err != nil { b.Fatal(err) } - count.Inc() + count.Add(1) } }) diff --git a/winlogbeat/sys/wineventlog/testdata/4738.evtx b/winlogbeat/sys/wineventlog/testdata/4738.evtx new file mode 100644 index 000000000000..9f521b36a0c7 Binary files /dev/null and b/winlogbeat/sys/wineventlog/testdata/4738.evtx differ diff --git a/winlogbeat/sys/wineventlog/testdata/experimental.evtx b/winlogbeat/sys/wineventlog/testdata/raw.evtx similarity index 100% rename from winlogbeat/sys/wineventlog/testdata/experimental.evtx rename to winlogbeat/sys/wineventlog/testdata/raw.evtx diff --git a/winlogbeat/sys/wineventlog/testdata/experimental.xml b/winlogbeat/sys/wineventlog/testdata/raw.xml similarity index 100% rename from winlogbeat/sys/wineventlog/testdata/experimental.xml rename to winlogbeat/sys/wineventlog/testdata/raw.xml diff --git a/winlogbeat/sys/wineventlog/util_test.go b/winlogbeat/sys/wineventlog/util_test.go index 7927f91ce8b8..c29e5ed8d1f9 100644 --- a/winlogbeat/sys/wineventlog/util_test.go +++ b/winlogbeat/sys/wineventlog/util_test.go @@ -38,6 +38,7 @@ const ( winlogbeatTestLogName = "WinEventLogTestGo" security4752File = "testdata/4752.evtx" + security4738File = "testdata/4738.evtx" sysmon9File = "testdata/sysmon-9.01.evtx" winErrorReportingFile = "testdata/application-windows-error-reporting.evtx" ) diff --git a/winlogbeat/sys/wineventlog/wineventlog_windows.go b/winlogbeat/sys/wineventlog/wineventlog_windows.go index 66ab869fb24d..3c70799535e7 100644 --- a/winlogbeat/sys/wineventlog/wineventlog_windows.go +++ b/winlogbeat/sys/wineventlog/wineventlog_windows.go @@ -219,7 +219,7 @@ func RenderEvent( eventHandle EvtHandle, lang uint32, renderBuf []byte, - pubHandleProvider func(string) sys.MessageFiles, + pubHandleProvider func(string) EvtHandle, out io.Writer, ) error { providerName, err := evtRenderProviderName(renderBuf, eventHandle) @@ -227,19 +227,9 @@ func RenderEvent( return err } - var publisherHandle uintptr - if pubHandleProvider != nil { - messageFiles := pubHandleProvider(providerName) - if messageFiles.Err == nil { - // There is only ever a single handle when using the Windows Event - // Log API. - publisherHandle = messageFiles.Handles[0].Handle - } - } - // Only a single string is returned when rendering XML. err = FormatEventString(EvtFormatMessageXml, - eventHandle, providerName, EvtHandle(publisherHandle), lang, renderBuf, out) + eventHandle, providerName, pubHandleProvider(providerName), lang, renderBuf, out) // Recover by rendering the XML without the RenderingInfo (message string). if err != nil { err = RenderEventXML(eventHandle, renderBuf, out) @@ -250,22 +240,13 @@ func RenderEvent( // Message reads the event data associated with the EvtHandle and renders // and returns the message only. -func Message(h EvtHandle, renderBuf []byte, pubHandleProvider func(string) sys.MessageFiles) (message string, err error) { +func Message(h EvtHandle, renderBuf []byte, pubHandleProvider func(string) EvtHandle) (message string, err error) { providerName, err := evtRenderProviderName(renderBuf, h) if err != nil { return "", err } - var pub EvtHandle - if pubHandleProvider != nil { - messageFiles := pubHandleProvider(providerName) - if messageFiles.Err == nil { - // There is only ever a single handle when using the Windows Event - // Log API. - pub = EvtHandle(messageFiles.Handles[0].Handle) - } - } - return getMessageStringFromHandle(&PublisherMetadata{Handle: pub}, h, nil) + return getMessageStringFromHandle(&PublisherMetadata{Handle: pubHandleProvider(providerName)}, h, nil) } // RenderEventXML renders the event as XML. If the event is already rendered, as diff --git a/winlogbeat/sys/wineventlog/wineventlog_windows_test.go b/winlogbeat/sys/wineventlog/wineventlog_windows_test.go index e6b494e3b242..8c23098cd3a8 100644 --- a/winlogbeat/sys/wineventlog/wineventlog_windows_test.go +++ b/winlogbeat/sys/wineventlog/wineventlog_windows_test.go @@ -44,13 +44,13 @@ func TestWinEventLog(t *testing.T) { }{ {path: "application-windows-error-reporting.evtx", events: 1}, {path: "sysmon-9.01.evtx", events: 32}, - {path: "ec1.evtx", events: 1}, // eventcreate /id 1000 /t error /l application /d "My custom error event for the application log" - {path: "ec2.evtx", events: 1}, // eventcreate /id 999 /t error /l application /so WinWord /d "Winword event 999 happened due to low diskspace" - {path: "ec3.evtx", events: 1}, // eventcreate /id 5 /t error /l system /d "Catastrophe!" - {path: "ec4.evtx", events: 1}, // eventcreate /id 5 /t error /l system /so Backup /d "Backup failure" - {path: "ec3and4.evtx", events: 2}, // ec3 and ec3 exported as a single evtx. - {path: "original.evtx", events: 5}, // a capture from a short generation of the eventlog WindowsEventLogAPI test. - {path: "experimental.evtx", events: 5}, // a capture from a short generation of the eventlog WindowsEventLogAPIExperimental test. + {path: "ec1.evtx", events: 1}, // eventcreate /id 1000 /t error /l application /d "My custom error event for the application log" + {path: "ec2.evtx", events: 1}, // eventcreate /id 999 /t error /l application /so WinWord /d "Winword event 999 happened due to low diskspace" + {path: "ec3.evtx", events: 1}, // eventcreate /id 5 /t error /l system /d "Catastrophe!" + {path: "ec4.evtx", events: 1}, // eventcreate /id 5 /t error /l system /so Backup /d "Backup failure" + {path: "ec3and4.evtx", events: 2}, // ec3 and ec3 exported as a single evtx. + {path: "original.evtx", events: 5}, // a capture from a short generation of the eventlog WindowsEventLogAPI test. + {path: "raw.evtx", events: 5}, // a capture from a short generation of the eventlog WindowsEventLogAPIRaw test. } { t.Run(test.path, func(t *testing.T) { evtx, err := filepath.Abs(filepath.Join("testdata", test.path)) diff --git a/x-pack/agentbeat/agentbeat.spec.yml b/x-pack/agentbeat/agentbeat.spec.yml index a2af5ce6bf8f..5b6c33e4ceb1 100644 --- a/x-pack/agentbeat/agentbeat.spec.yml +++ b/x-pack/agentbeat/agentbeat.spec.yml @@ -507,6 +507,11 @@ inputs: platforms: *platforms outputs: *outputs command: *metricbeat_command + - name: openai/metrics + description: "OpenAI metrics" + platforms: *platforms + outputs: *outputs + command: *metricbeat_command - name: panw/metrics description: "Palo Alto Networks metrics" platforms: *platforms diff --git a/x-pack/agentbeat/main.go b/x-pack/agentbeat/main.go index f96031ec081e..44cc6ce33062 100644 --- a/x-pack/agentbeat/main.go +++ b/x-pack/agentbeat/main.go @@ -42,7 +42,7 @@ into a single agentbeat binary.`, prepareCommand(auditbeat.RootCmd), prepareCommand(filebeat.Filebeat()), prepareCommand(heartbeat.RootCmd), - prepareCommand(metricbeat.RootCmd), + prepareCommand(metricbeat.Initialize()), prepareCommand(osquerybeat.RootCmd), prepareCommand(packetbeat.RootCmd), ) diff --git a/x-pack/auditbeat/module/system/process/gosysinfo_provider.go b/x-pack/auditbeat/module/system/process/gosysinfo_provider.go new file mode 100644 index 000000000000..da82a2e18106 --- /dev/null +++ b/x-pack/auditbeat/module/system/process/gosysinfo_provider.go @@ -0,0 +1,461 @@ +// 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 process + +import ( + "fmt" + "os" + "os/user" + "runtime" + "strconv" + "time" + + "github.com/cespare/xxhash/v2" + "github.com/gofrs/uuid/v5" + + "github.com/elastic/beats/v7/auditbeat/datastore" + "github.com/elastic/beats/v7/auditbeat/helper/hasher" + "github.com/elastic/beats/v7/libbeat/common/capabilities" + "github.com/elastic/beats/v7/metricbeat/mb" + "github.com/elastic/beats/v7/x-pack/auditbeat/cache" + "github.com/elastic/beats/v7/x-pack/auditbeat/module/system" + "github.com/elastic/elastic-agent-libs/mapstr" + "github.com/elastic/go-sysinfo" + "github.com/elastic/go-sysinfo/types" +) + +const ( + bucketName = "auditbeat.process.v1" + bucketKeyStateTimestamp = "state_timestamp" +) + +// SysinfoMetricSet collects data about the host. +type SysInfoMetricSet struct { + system.SystemMetricSet + MetricSet + hasher *hasher.FileHasher + cache *cache.Cache + bucket datastore.Bucket + lastState time.Time + + suppressPermissionWarnings bool +} + +// Process represents information about a process. +type Process struct { + Info types.ProcessInfo + UserInfo *types.UserInfo + User *user.User + Group *user.Group + CapEffective []string + CapPermitted []string + Hashes map[hasher.HashType]hasher.Digest + Error error +} + +// Hash creates a hash for Process. +func (p Process) Hash() uint64 { + h := xxhash.New() + //nolint:errcheck // always return nil err + h.WriteString(strconv.Itoa(p.Info.PID)) + //nolint:errcheck // always return nil err + h.WriteString(p.Info.StartTime.String()) + return h.Sum64() +} + +func (p Process) toMapStr() mapstr.M { + return mapstr.M{ + // https://github.com/elastic/ecs#-process-fields + "name": p.Info.Name, + "args": p.Info.Args, + "pid": p.Info.PID, + "parent": mapstr.M{ + "pid": p.Info.PPID, + }, + "working_directory": p.Info.CWD, + "executable": p.Info.Exe, + "start": p.Info.StartTime, + } +} + +// NewFromSysInfo constructs a new MetricSet backed by go-sysinfo. +func NewFromSysInfo(base mb.BaseMetricSet, ms MetricSet) (mb.MetricSet, error) { + bucket, err := datastore.OpenBucket(bucketName) + if err != nil { + return nil, fmt.Errorf("failed to open persistent datastore: %w", err) + } + + // Load from disk: Time when state was last sent + var lastState time.Time + err = bucket.Load(bucketKeyStateTimestamp, func(blob []byte) error { + if len(blob) > 0 { + return lastState.UnmarshalBinary(blob) + } + return nil + }) + if err != nil { + bucket.Close() + return nil, err + } + if !lastState.IsZero() { + ms.log.Debugf("Last state was sent at %v. Next state update by %v.", + lastState, lastState.Add(ms.config.effectiveStatePeriod())) + } else { + ms.log.Debug("No state timestamp found") + } + + hasher, err := hasher.NewFileHasher(ms.config.HasherConfig, nil) + if err != nil { + bucket.Close() + return nil, err + } + + if runtime.GOOS != "windows" && os.Geteuid() != 0 { + ms.log.Warn("Running as non-root user, will likely not report all processes.") + } + + sm := &SysInfoMetricSet{ + SystemMetricSet: system.NewSystemMetricSet(base), + MetricSet: ms, + cache: cache.New(), + bucket: bucket, + lastState: lastState, + hasher: hasher, + } + + return sm, nil +} + +// Close cleans up the MetricSet when it finishes. +func (ms *SysInfoMetricSet) Close() error { + if ms.bucket != nil { + return ms.bucket.Close() + } + return nil +} + +// Fetch collects process information. It is invoked periodically. +func (ms *SysInfoMetricSet) Fetch(report mb.ReporterV2) { + needsStateUpdate := time.Since(ms.lastState) > ms.config.effectiveStatePeriod() + if needsStateUpdate || ms.cache.IsEmpty() { + ms.log.Debugf("State update needed (needsStateUpdate=%v, cache.IsEmpty()=%v)", needsStateUpdate, ms.cache.IsEmpty()) + err := ms.reportState(report) + if err != nil { + ms.log.Error(err) + report.Error(err) + } + ms.log.Debugf("Next state update by %v", ms.lastState.Add(ms.config.effectiveStatePeriod())) + } + + err := ms.reportChanges(report) + if err != nil { + ms.log.Error(err) + report.Error(err) + } +} + +// reportState reports all running processes on the system. +func (ms *SysInfoMetricSet) reportState(report mb.ReporterV2) error { + // Only update lastState if this state update was regularly scheduled, + // i.e. not caused by an Auditbeat restart (when the cache would be empty). + if !ms.cache.IsEmpty() { + ms.lastState = time.Now() + } + + processes, err := ms.getProcesses() + if err != nil { + return fmt.Errorf("failed to get process infos: %w", err) + } + ms.log.Debugf("Found %v processes", len(processes)) + + stateID, err := uuid.NewV4() + if err != nil { + return fmt.Errorf("error generating state ID: %w", err) + } + for _, p := range processes { + ms.enrichProcess(p) + + if p.Error == nil { + event := ms.processEvent(p, eventTypeState, eventActionExistingProcess) + event.RootFields.Put("event.id", stateID.String()) + report.Event(event) + } else { + ms.log.Warn(p.Error) + report.Event(ms.processEvent(p, eventTypeEvent, eventActionProcessError)) + } + } + + if ms.cache != nil { + // This will initialize the cache with the current processes + ms.cache.DiffAndUpdateCache(convertToCacheable(processes)) + } + + // Save time so we know when to send the state again (config.StatePeriod) + timeBytes, err := ms.lastState.MarshalBinary() + if err != nil { + return err + } + err = ms.bucket.Store(bucketKeyStateTimestamp, timeBytes) + if err != nil { + return fmt.Errorf("error writing state timestamp to disk: %w", err) + } + + return nil +} + +// reportChanges detects and reports any changes to processes on this system since the last call. +func (ms *SysInfoMetricSet) reportChanges(report mb.ReporterV2) error { + processes, err := ms.getProcesses() + if err != nil { + return fmt.Errorf("failed to get processes: %w", err) + } + ms.log.Debugf("Found %v processes", len(processes)) + + started, stopped := ms.cache.DiffAndUpdateCache(convertToCacheable(processes)) + + for _, cacheValue := range started { + p, ok := cacheValue.(*Process) + if !ok { + return fmt.Errorf("cache type error") + } + ms.enrichProcess(p) + + if p.Error == nil { + report.Event(ms.processEvent(p, eventTypeEvent, eventActionProcessStarted)) + } else { + ms.log.Warn(p.Error) + report.Event(ms.processEvent(p, eventTypeEvent, eventActionProcessError)) + } + } + + for _, cacheValue := range stopped { + p, ok := cacheValue.(*Process) + if !ok { + return fmt.Errorf("cache type error") + } + + if p.Error == nil { + report.Event(ms.processEvent(p, eventTypeEvent, eventActionProcessStopped)) + } + } + + return nil +} + +// enrichProcess enriches a process with user lookup information +// and executable file hash. +func (ms *SysInfoMetricSet) enrichProcess(process *Process) { + if process.UserInfo != nil { + goUser, err := user.LookupId(process.UserInfo.UID) + if err == nil { + process.User = goUser + } + + group, err := user.LookupGroupId(process.UserInfo.GID) + if err == nil { + process.Group = group + } + } + + if process.Info.Exe != "" { + sharedMntNS, err := isNsSharedWith(process.Info.PID, "mnt") + if err != nil { + if process.Error == nil { + process.Error = fmt.Errorf("failed to get namespaces for %v PID %v: %w", process.Info.Exe, process.Info.PID, err) + } + return + } + if !sharedMntNS { + return + } + hashes, err := ms.hasher.HashFile(process.Info.Exe) + if err != nil { + if process.Error == nil { + process.Error = fmt.Errorf("failed to hash executable %v for PID %v: %w", process.Info.Exe, process.Info.PID, err) + } + return + } + process.Hashes = hashes + } +} + +func (ms *SysInfoMetricSet) processEvent(process *Process, eventType string, action eventAction) mb.Event { + event := mb.Event{ + RootFields: mapstr.M{ + "event": mapstr.M{ + "kind": eventType, + "category": []string{"process"}, + "type": []string{action.Type()}, + "action": action.String(), + }, + "process": process.toMapStr(), + "message": processMessage(process, action), + }, + } + + if process.UserInfo != nil { + putIfNotEmpty(&event.RootFields, "user.id", process.UserInfo.UID) + putIfNotEmpty(&event.RootFields, "user.group.id", process.UserInfo.GID) + + putIfNotEmpty(&event.RootFields, "user.effective.id", process.UserInfo.EUID) + putIfNotEmpty(&event.RootFields, "user.effective.group.id", process.UserInfo.EGID) + + putIfNotEmpty(&event.RootFields, "user.saved.id", process.UserInfo.SUID) + putIfNotEmpty(&event.RootFields, "user.saved.group.id", process.UserInfo.SGID) + } + + if process.User != nil { + if process.User.Username != "" { + event.RootFields.Put("user.name", process.User.Username) + } else if process.User.Name != "" { + event.RootFields.Put("user.name", process.User.Name) + } + } + + if process.Group != nil { + event.RootFields.Put("user.group.name", process.Group.Name) + } + + if len(process.CapEffective) > 0 { + event.RootFields.Put("process.thread.capabilities.effective", process.CapEffective) + } + if len(process.CapPermitted) > 0 { + event.RootFields.Put("process.thread.capabilities.permitted", process.CapPermitted) + } + + if process.Hashes != nil { + for hashType, digest := range process.Hashes { + fieldName := "process.hash." + string(hashType) + event.RootFields.Put(fieldName, digest) + } + } + + if process.Error != nil { + event.RootFields.Put("error.message", process.Error.Error()) + } + + if ms.HostID() != "" { + event.RootFields.Put("process.entity_id", + entityID(ms.HostID(), process.Info.PID, process.Info.StartTime)) + } + + return event +} + +func putIfNotEmpty(mapstr *mapstr.M, key string, value string) { + if value != "" { + mapstr.Put(key, value) + } +} + +func processMessage(process *Process, action eventAction) string { + if process.Error != nil { + return fmt.Sprintf("ERROR for PID %d: %v", process.Info.PID, process.Error) + } + + var actionString string + switch action { + case eventActionProcessStarted: + actionString = "STARTED" + case eventActionProcessStopped: + actionString = "STOPPED" + case eventActionExistingProcess: + actionString = "is RUNNING" + } + + var userString string + if process.User != nil { + userString = fmt.Sprintf(" by user %v", process.User.Username) + } + + return fmt.Sprintf("Process %v (PID: %d)%v %v", + process.Info.Name, process.Info.PID, userString, actionString) +} + +func convertToCacheable(processes []*Process) []cache.Cacheable { + c := make([]cache.Cacheable, 0, len(processes)) + + for _, p := range processes { + c = append(c, p) + } + + return c +} + +func (ms *SysInfoMetricSet) getProcesses() ([]*Process, error) { + sysinfoProcs, err := sysinfo.Processes() + if err != nil { + return nil, fmt.Errorf("failed to fetch processes: %w", err) + } + + processes := make([]*Process, 0, len(sysinfoProcs)) + for _, sysinfoProc := range sysinfoProcs { + var process *Process + + pInfo, err := sysinfoProc.Info() + if err != nil { + if os.IsNotExist(err) { + // Skip - process probably just terminated since our call to Processes(). + continue + } + + if os.Geteuid() != 0 && os.IsPermission(err) { + // Running as non-root, permission issues when trying to access + // other user's private process information are expected. + + if !ms.suppressPermissionWarnings { + ms.log.Warnf("Failed to load process information for PID %d as non-root user. "+ + "Will suppress further errors of this kind. Error: %v", sysinfoProc.PID(), err) + + // Only warn once at the start of Auditbeat. + ms.suppressPermissionWarnings = true + } + + continue + } + + // Record what we can and continue + process = &Process{ + Info: pInfo, + Error: fmt.Errorf("failed to load process information for PID %d: %w", sysinfoProc.PID(), err), + } + process.Info.PID = sysinfoProc.PID() // in case pInfo did not contain it + } else { + process = &Process{ + Info: pInfo, + } + } + + userInfo, err := sysinfoProc.User() + if err != nil { + if process.Error == nil { + process.Error = fmt.Errorf("failed to load user for PID %d: %w", sysinfoProc.PID(), err) + } + } else { + process.UserInfo = &userInfo + } + + // Exclude Linux kernel processes, they are not very interesting. + if runtime.GOOS == "linux" { + if userInfo.UID == "0" && process.Info.Exe == "" { + continue + } + + // Fetch Effective and Permitted capabilities + process.CapEffective, err = capabilities.FromPid(capabilities.Effective, pInfo.PID) + if err != nil && process.Error == nil { + process.Error = err + } + process.CapPermitted, err = capabilities.FromPid(capabilities.Permitted, pInfo.PID) + if err != nil && process.Error == nil { + process.Error = err + } + } + + processes = append(processes, process) + } + + return processes, nil +} diff --git a/x-pack/auditbeat/module/system/process/process.go b/x-pack/auditbeat/module/system/process/process.go index 793bb70a4fb0..c79e87ce0fad 100644 --- a/x-pack/auditbeat/module/system/process/process.go +++ b/x-pack/auditbeat/module/system/process/process.go @@ -7,40 +7,29 @@ package process import ( "encoding/binary" "fmt" - "os" - "os/user" - "runtime" - "strconv" "time" - "github.com/cespare/xxhash/v2" - "github.com/gofrs/uuid/v5" - "github.com/elastic/beats/v7/auditbeat/ab" - "github.com/elastic/beats/v7/auditbeat/datastore" - "github.com/elastic/beats/v7/auditbeat/helper/hasher" - "github.com/elastic/beats/v7/libbeat/common/capabilities" "github.com/elastic/beats/v7/libbeat/common/cfgwarn" "github.com/elastic/beats/v7/metricbeat/mb" - "github.com/elastic/beats/v7/x-pack/auditbeat/cache" "github.com/elastic/beats/v7/x-pack/auditbeat/module/system" "github.com/elastic/elastic-agent-libs/logp" - "github.com/elastic/elastic-agent-libs/mapstr" - "github.com/elastic/go-sysinfo" - "github.com/elastic/go-sysinfo/types" ) const ( metricsetName = "process" namespace = "system.audit.process" - bucketName = "auditbeat.process.v1" - bucketKeyStateTimestamp = "state_timestamp" - eventTypeState = "state" eventTypeEvent = "event" ) +// MetricSet collects data about the host. +type MetricSet struct { + config Config + log *logp.Logger +} + type eventAction uint8 const ( @@ -87,439 +76,29 @@ func init() { ) } -// MetricSet collects data about the host. -type MetricSet struct { - system.SystemMetricSet - config Config - cache *cache.Cache - log *logp.Logger - bucket datastore.Bucket - lastState time.Time - hasher *hasher.FileHasher - - suppressPermissionWarnings bool -} +// New constructs a new MetricSet. +func New(base mb.BaseMetricSet) (mb.MetricSet, error) { + var ms MetricSet -// Process represents information about a process. -type Process struct { - Info types.ProcessInfo - UserInfo *types.UserInfo - User *user.User - Group *user.Group - CapEffective []string - CapPermitted []string - Hashes map[hasher.HashType]hasher.Digest - Error error -} + cfgwarn.Beta("The %v/%v dataset is beta", system.ModuleName, metricsetName) -// Hash creates a hash for Process. -func (p Process) Hash() uint64 { - h := xxhash.New() - //nolint:errcheck // always return nil err - h.WriteString(strconv.Itoa(p.Info.PID)) - //nolint:errcheck // always return nil err - h.WriteString(p.Info.StartTime.String()) - return h.Sum64() -} + ms.config = defaultConfig + ms.log = logp.NewLogger(metricsetName) -func (p Process) toMapStr() mapstr.M { - return mapstr.M{ - // https://github.com/elastic/ecs#-process-fields - "name": p.Info.Name, - "args": p.Info.Args, - "pid": p.Info.PID, - "parent": mapstr.M{ - "pid": p.Info.PPID, - }, - "working_directory": p.Info.CWD, - "executable": p.Info.Exe, - "start": p.Info.StartTime, + if err := base.Module().UnpackConfig(&ms.config); err != nil { + return nil, fmt.Errorf("failed to unpack the %v/%v config: %w", system.ModuleName, metricsetName, err) } + + return NewFromSysInfo(base, ms) } // entityID creates an ID that uniquely identifies this process across machines. -func (p Process) entityID(hostID string) string { +func entityID(hostID string, pid int, startTime time.Time) string { h := system.NewEntityHash() h.Write([]byte(hostID)) //nolint:errcheck // no error handling - binary.Write(h, binary.LittleEndian, int64(p.Info.PID)) + binary.Write(h, binary.LittleEndian, int64(pid)) //nolint:errcheck // no error handling - binary.Write(h, binary.LittleEndian, int64(p.Info.StartTime.Nanosecond())) + binary.Write(h, binary.LittleEndian, int64(startTime.Nanosecond())) return h.Sum() } - -// New constructs a new MetricSet. -func New(base mb.BaseMetricSet) (mb.MetricSet, error) { - cfgwarn.Beta("The %v/%v dataset is beta", system.ModuleName, metricsetName) - - config := defaultConfig - if err := base.Module().UnpackConfig(&config); err != nil { - return nil, fmt.Errorf("failed to unpack the %v/%v config: %w", system.ModuleName, metricsetName, err) - } - - bucket, err := datastore.OpenBucket(bucketName) - if err != nil { - return nil, fmt.Errorf("failed to open persistent datastore: %w", err) - } - - hasher, err := hasher.NewFileHasher(config.HasherConfig, nil) - if err != nil { - return nil, err - } - - ms := &MetricSet{ - SystemMetricSet: system.NewSystemMetricSet(base), - config: config, - log: logp.NewLogger(metricsetName), - cache: cache.New(), - bucket: bucket, - hasher: hasher, - } - - // Load from disk: Time when state was last sent - err = bucket.Load(bucketKeyStateTimestamp, func(blob []byte) error { - if len(blob) > 0 { - return ms.lastState.UnmarshalBinary(blob) - } - return nil - }) - if err != nil { - return nil, err - } - if !ms.lastState.IsZero() { - ms.log.Debugf("Last state was sent at %v. Next state update by %v.", ms.lastState, ms.lastState.Add(ms.config.effectiveStatePeriod())) - } else { - ms.log.Debug("No state timestamp found") - } - - if runtime.GOOS != "windows" && os.Geteuid() != 0 { - ms.log.Warn("Running as non-root user, will likely not report all processes.") - } - - return ms, nil -} - -// Close cleans up the MetricSet when it finishes. -func (ms *MetricSet) Close() error { - if ms.bucket != nil { - return ms.bucket.Close() - } - return nil -} - -// Fetch collects process information. It is invoked periodically. -func (ms *MetricSet) Fetch(report mb.ReporterV2) { - needsStateUpdate := time.Since(ms.lastState) > ms.config.effectiveStatePeriod() - if needsStateUpdate || ms.cache.IsEmpty() { - ms.log.Debugf("State update needed (needsStateUpdate=%v, cache.IsEmpty()=%v)", needsStateUpdate, ms.cache.IsEmpty()) - err := ms.reportState(report) - if err != nil { - ms.log.Error(err) - report.Error(err) - } - ms.log.Debugf("Next state update by %v", ms.lastState.Add(ms.config.effectiveStatePeriod())) - } - - err := ms.reportChanges(report) - if err != nil { - ms.log.Error(err) - report.Error(err) - } -} - -// reportState reports all running processes on the system. -func (ms *MetricSet) reportState(report mb.ReporterV2) error { - // Only update lastState if this state update was regularly scheduled, - // i.e. not caused by an Auditbeat restart (when the cache would be empty). - if !ms.cache.IsEmpty() { - ms.lastState = time.Now() - } - - processes, err := ms.getProcesses() - if err != nil { - return fmt.Errorf("failed to get process infos: %w", err) - } - ms.log.Debugf("Found %v processes", len(processes)) - - stateID, err := uuid.NewV4() - if err != nil { - return fmt.Errorf("error generating state ID: %w", err) - } - for _, p := range processes { - ms.enrichProcess(p) - - if p.Error == nil { - event := ms.processEvent(p, eventTypeState, eventActionExistingProcess) - event.RootFields.Put("event.id", stateID.String()) - report.Event(event) - } else { - ms.log.Warn(p.Error) - report.Event(ms.processEvent(p, eventTypeEvent, eventActionProcessError)) - } - } - - if ms.cache != nil { - // This will initialize the cache with the current processes - ms.cache.DiffAndUpdateCache(convertToCacheable(processes)) - } - - // Save time so we know when to send the state again (config.StatePeriod) - timeBytes, err := ms.lastState.MarshalBinary() - if err != nil { - return err - } - err = ms.bucket.Store(bucketKeyStateTimestamp, timeBytes) - if err != nil { - return fmt.Errorf("error writing state timestamp to disk: %w", err) - } - - return nil -} - -// reportChanges detects and reports any changes to processes on this system since the last call. -func (ms *MetricSet) reportChanges(report mb.ReporterV2) error { - processes, err := ms.getProcesses() - if err != nil { - return fmt.Errorf("failed to get processes: %w", err) - } - ms.log.Debugf("Found %v processes", len(processes)) - - started, stopped := ms.cache.DiffAndUpdateCache(convertToCacheable(processes)) - - for _, cacheValue := range started { - p := cacheValue.(*Process) - ms.enrichProcess(p) - - if p.Error == nil { - report.Event(ms.processEvent(p, eventTypeEvent, eventActionProcessStarted)) - } else { - ms.log.Warn(p.Error) - report.Event(ms.processEvent(p, eventTypeEvent, eventActionProcessError)) - } - } - - for _, cacheValue := range stopped { - p := cacheValue.(*Process) - - if p.Error == nil { - report.Event(ms.processEvent(p, eventTypeEvent, eventActionProcessStopped)) - } - } - - return nil -} - -// enrichProcess enriches a process with user lookup information -// and executable file hash. -func (ms *MetricSet) enrichProcess(process *Process) { - if process.UserInfo != nil { - goUser, err := user.LookupId(process.UserInfo.UID) - if err == nil { - process.User = goUser - } - - group, err := user.LookupGroupId(process.UserInfo.GID) - if err == nil { - process.Group = group - } - } - - if process.Info.Exe != "" { - sharedMntNS, err := isNsSharedWith(process.Info.PID, "mnt") - if err != nil { - if process.Error == nil { - process.Error = fmt.Errorf("failed to get namespaces for %v PID %v: %w", process.Info.Exe, process.Info.PID, err) - } - return - } - if !sharedMntNS { - return - } - hashes, err := ms.hasher.HashFile(process.Info.Exe) - if err != nil { - if process.Error == nil { - process.Error = fmt.Errorf("failed to hash executable %v for PID %v: %w", process.Info.Exe, process.Info.PID, err) - } - return - } - process.Hashes = hashes - } -} - -func (ms *MetricSet) processEvent(process *Process, eventType string, action eventAction) mb.Event { - event := mb.Event{ - RootFields: mapstr.M{ - "event": mapstr.M{ - "kind": eventType, - "category": []string{"process"}, - "type": []string{action.Type()}, - "action": action.String(), - }, - "process": process.toMapStr(), - "message": processMessage(process, action), - }, - } - - if process.UserInfo != nil { - putIfNotEmpty(&event.RootFields, "user.id", process.UserInfo.UID) - putIfNotEmpty(&event.RootFields, "user.group.id", process.UserInfo.GID) - - putIfNotEmpty(&event.RootFields, "user.effective.id", process.UserInfo.EUID) - putIfNotEmpty(&event.RootFields, "user.effective.group.id", process.UserInfo.EGID) - - putIfNotEmpty(&event.RootFields, "user.saved.id", process.UserInfo.SUID) - putIfNotEmpty(&event.RootFields, "user.saved.group.id", process.UserInfo.SGID) - } - - if process.User != nil { - if process.User.Username != "" { - event.RootFields.Put("user.name", process.User.Username) - } else if process.User.Name != "" { - event.RootFields.Put("user.name", process.User.Name) - } - } - - if process.Group != nil { - event.RootFields.Put("user.group.name", process.Group.Name) - } - - if len(process.CapEffective) > 0 { - event.RootFields.Put("process.thread.capabilities.effective", process.CapEffective) - } - if len(process.CapPermitted) > 0 { - event.RootFields.Put("process.thread.capabilities.permitted", process.CapPermitted) - } - - if process.Hashes != nil { - for hashType, digest := range process.Hashes { - fieldName := "process.hash." + string(hashType) - event.RootFields.Put(fieldName, digest) - } - } - - if process.Error != nil { - event.RootFields.Put("error.message", process.Error.Error()) - } - - if ms.HostID() != "" { - event.RootFields.Put("process.entity_id", process.entityID(ms.HostID())) - } - - return event -} - -func putIfNotEmpty(mapstr *mapstr.M, key string, value string) { - if value != "" { - mapstr.Put(key, value) - } -} - -func processMessage(process *Process, action eventAction) string { - if process.Error != nil { - return fmt.Sprintf("ERROR for PID %d: %v", process.Info.PID, process.Error) - } - - var actionString string - switch action { - case eventActionProcessStarted: - actionString = "STARTED" - case eventActionProcessStopped: - actionString = "STOPPED" - case eventActionExistingProcess: - actionString = "is RUNNING" - } - - var userString string - if process.User != nil { - userString = fmt.Sprintf(" by user %v", process.User.Username) - } - - return fmt.Sprintf("Process %v (PID: %d)%v %v", - process.Info.Name, process.Info.PID, userString, actionString) -} - -func convertToCacheable(processes []*Process) []cache.Cacheable { - c := make([]cache.Cacheable, 0, len(processes)) - - for _, p := range processes { - c = append(c, p) - } - - return c -} - -func (ms *MetricSet) getProcesses() ([]*Process, error) { - sysinfoProcs, err := sysinfo.Processes() - if err != nil { - return nil, fmt.Errorf("failed to fetch processes: %w", err) - } - - processes := make([]*Process, 0, len(sysinfoProcs)) - for _, sysinfoProc := range sysinfoProcs { - var process *Process - - pInfo, err := sysinfoProc.Info() - if err != nil { - if os.IsNotExist(err) { - // Skip - process probably just terminated since our call to Processes(). - continue - } - - if os.Geteuid() != 0 && os.IsPermission(err) { - // Running as non-root, permission issues when trying to access - // other user's private process information are expected. - - if !ms.suppressPermissionWarnings { - ms.log.Warnf("Failed to load process information for PID %d as non-root user. "+ - "Will suppress further errors of this kind. Error: %v", sysinfoProc.PID(), err) - - // Only warn once at the start of Auditbeat. - ms.suppressPermissionWarnings = true - } - - continue - } - - // Record what we can and continue - process = &Process{ - Info: pInfo, - Error: fmt.Errorf("failed to load process information for PID %d: %w", sysinfoProc.PID(), err), - } - process.Info.PID = sysinfoProc.PID() // in case pInfo did not contain it - } else { - process = &Process{ - Info: pInfo, - } - } - - userInfo, err := sysinfoProc.User() - if err != nil { - if process.Error == nil { - process.Error = fmt.Errorf("failed to load user for PID %d: %w", sysinfoProc.PID(), err) - } - } else { - process.UserInfo = &userInfo - } - - // Exclude Linux kernel processes, they are not very interesting. - if runtime.GOOS == "linux" { - if userInfo.UID == "0" && process.Info.Exe == "" { - continue - } - - // Fetch Effective and Permitted capabilities - process.CapEffective, err = capabilities.FromPid(capabilities.Effective, pInfo.PID) - if err != nil && process.Error == nil { - process.Error = err - } - process.CapPermitted, err = capabilities.FromPid(capabilities.Permitted, pInfo.PID) - if err != nil && process.Error == nil { - process.Error = err - } - } - - processes = append(processes, process) - } - - return processes, nil -} diff --git a/x-pack/auditbeat/module/system/process/process_test.go b/x-pack/auditbeat/module/system/process/process_test.go index 25508072f021..17283fe9e346 100644 --- a/x-pack/auditbeat/module/system/process/process_test.go +++ b/x-pack/auditbeat/module/system/process/process_test.go @@ -27,9 +27,9 @@ func TestData(t *testing.T) { f := mbtest.NewReportingMetricSetV2WithRegistry(t, getConfig(), ab.Registry) // Set lastState and add test process to cache so it will be reported as stopped. - f.(*MetricSet).lastState = time.Now() + f.(*SysInfoMetricSet).lastState = time.Now() p := testProcess() - f.(*MetricSet).cache.DiffAndUpdateCache(convertToCacheable([]*Process{p})) + f.(*SysInfoMetricSet).cache.DiffAndUpdateCache(convertToCacheable([]*Process{p})) events, errs := mbtest.ReportingFetchV2(f) if len(errs) > 0 { @@ -56,7 +56,8 @@ func getConfig() map[string]interface{} { } func TestProcessEvent(t *testing.T) { - ms := mbtest.NewReportingMetricSetV2WithRegistry(t, getConfig(), ab.Registry).(*MetricSet) + ms, ok := mbtest.NewReportingMetricSetV2WithRegistry(t, getConfig(), ab.Registry).(*SysInfoMetricSet) + assert.True(t, ok) eventType := eventTypeEvent eventAction := eventActionProcessStarted diff --git a/x-pack/auditbeat/module/system/socket/state.go b/x-pack/auditbeat/module/system/socket/state.go index 347c5385921f..f102127e783c 100644 --- a/x-pack/auditbeat/module/system/socket/state.go +++ b/x-pack/auditbeat/module/system/socket/state.go @@ -570,6 +570,7 @@ func (s *state) ForkProcess(parentPID, childPID uint32, ts kernelTime) error { for k, v := range parent.resolvedDomains { child.resolvedDomains[k] = v } + s.log.Debugf("forking process %d with %d associated domains", childPID, len(child.resolvedDomains)) s.processes[childPID] = child } return nil @@ -579,6 +580,7 @@ func (s *state) TerminateProcess(pid uint32) error { if pid == 0 { return errors.New("can't terminate process with PID 0") } + s.log.Debugf("terminating process %d", pid) s.Lock() defer s.Unlock() delete(s.processes, pid) @@ -676,6 +678,7 @@ func (s *state) CreateSocket(ref flow) error { func (s *state) OnDNSTransaction(tr dns.Transaction) error { s.Lock() defer s.Unlock() + s.log.Debugf("adding DNS transaction for domain %s for client %s", tr.Domain, tr.Client.String()) s.dns.AddTransaction(tr) return nil } @@ -721,6 +724,10 @@ func (s *state) mutualEnrich(sock *socket, f *flow) { } func (s *state) createFlow(ref flow) error { + if ref.process != nil { + s.log.Debugf("creating flow for pid %s", ref.process.pid) + } + // Get or create a socket for this flow sock := s.getSocket(ref.sock) ref.createdTime = ref.lastSeenTime @@ -821,6 +828,9 @@ func (s *state) enrichDNS(f *flow) { IP: f.local.addr.IP, Port: f.local.addr.Port, } + if f.process != nil { + s.log.Debugf("registering endpoint %s for process %d", localUDP.String(), f.process.pid) + } s.dns.RegisterEndpoint(localUDP, f.process) } } diff --git a/x-pack/auditbeat/processors/sessionmd/processdb/db.go b/x-pack/auditbeat/processors/sessionmd/processdb/db.go index 1f97f7d0fd58..e9e53eb965ac 100644 --- a/x-pack/auditbeat/processors/sessionmd/processdb/db.go +++ b/x-pack/auditbeat/processors/sessionmd/processdb/db.go @@ -20,6 +20,7 @@ import ( "sync" "time" + "github.com/elastic/beats/v7/auditbeat/helper/tty" "github.com/elastic/beats/v7/libbeat/common/capabilities" "github.com/elastic/beats/v7/x-pack/auditbeat/processors/sessionmd/procfs" "github.com/elastic/beats/v7/x-pack/auditbeat/processors/sessionmd/timeutils" @@ -27,15 +28,6 @@ import ( "github.com/elastic/elastic-agent-libs/logp" ) -type TTYType int - -const ( - TTYUnknown TTYType = iota - Pts - TTY - TTYConsole -) - type EntryType string const ( @@ -67,18 +59,13 @@ var filteredExecutables = [...]string{ } const ( - ptsMinMajor = 136 - ptsMaxMajor = 143 - ttyMajor = 4 - consoleMaxMinor = 63 - ttyMaxMinor = 255 - retryCount = 2 + retryCount = 2 ) type Process struct { PIDs types.PIDInfo Creds types.CredInfo - CTTY types.TTYDev + CTTY tty.TTYDev Argv []string Cwd string Env map[string]string @@ -142,8 +129,8 @@ func credInfoFromProto(p types.CredInfo) types.CredInfo { } } -func ttyTermiosFromProto(p types.TTYTermios) types.TTYTermios { - return types.TTYTermios{ +func ttyTermiosFromProto(p tty.TTYTermios) tty.TTYTermios { + return tty.TTYTermios{ CIflag: p.CIflag, COflag: p.COflag, CLflag: p.CLflag, @@ -151,15 +138,15 @@ func ttyTermiosFromProto(p types.TTYTermios) types.TTYTermios { } } -func ttyWinsizeFromProto(p types.TTYWinsize) types.TTYWinsize { - return types.TTYWinsize{ +func ttyWinsizeFromProto(p tty.TTYWinsize) tty.TTYWinsize { + return tty.TTYWinsize{ Rows: p.Rows, Cols: p.Cols, } } -func ttyDevFromProto(p types.TTYDev) types.TTYDev { - return types.TTYDev{ +func ttyDevFromProto(p tty.TTYDev) tty.TTYDev { + return tty.TTYDev{ Major: p.Major, Minor: p.Minor, Winsize: ttyWinsizeFromProto(p.Winsize), @@ -319,15 +306,15 @@ func (db *DB) evaluateEntryLeader(p Process) *uint32 { // could be an entry leader if p.PIDs.Tgid == p.PIDs.Sid { - ttyType := getTTYType(p.CTTY.Major, p.CTTY.Minor) + ttyType := tty.GetTTYType(p.CTTY.Major, p.CTTY.Minor) procBasename := basename(p.Filename) switch { - case ttyType == TTY: + case ttyType == tty.TTY: db.createEntryLeader(pid, Terminal) db.logger.Debugf("entry_eval %d: entry type is terminal", p.PIDs.Tgid) return &pid - case ttyType == TTYConsole && procBasename == "login": + case ttyType == tty.TTYConsole && procBasename == "login": db.createEntryLeader(pid, EntryConsole) db.logger.Debugf("entry_eval %d: entry type is console", p.PIDs.Tgid) return &pid @@ -338,7 +325,7 @@ func (db *DB) evaluateEntryLeader(p Process) *uint32 { case !isFilteredExecutable(procBasename): if parent, ok := db.processes[p.PIDs.Ppid]; ok { parentBasename := basename(parent.Filename) - if ttyType == Pts && parentBasename == "ssm-session-worker" { + if ttyType == tty.Pts && parentBasename == "ssm-session-worker" { db.createEntryLeader(pid, Ssm) db.logger.Debugf("entry_eval %d: entry type is ssm", p.PIDs.Tgid) return &pid @@ -433,13 +420,9 @@ func (db *DB) InsertExit(exit types.ProcessExitEvent) { }) } -func interactiveFromTTY(tty types.TTYDev) bool { - return TTYUnknown != getTTYType(tty.Major, tty.Minor) -} - func fullProcessFromDBProcess(p Process) types.Process { reducedPrecisionStartTime := timeutils.ReduceTimestampPrecision(p.PIDs.StartTimeNS) - interactive := interactiveFromTTY(p.CTTY) + interactive := tty.InteractiveFromTTY(p.CTTY) ret := types.Process{ PID: p.PIDs.Tgid, @@ -475,7 +458,7 @@ func fullProcessFromDBProcess(p Process) types.Process { func fillParent(process *types.Process, parent Process) { reducedPrecisionStartTime := timeutils.ReduceTimestampPrecision(parent.PIDs.StartTimeNS) - interactive := interactiveFromTTY(parent.CTTY) + interactive := tty.InteractiveFromTTY(parent.CTTY) euid := parent.Creds.Euid egid := parent.Creds.Egid process.Parent.PID = parent.PIDs.Tgid @@ -500,7 +483,7 @@ func fillParent(process *types.Process, parent Process) { func fillGroupLeader(process *types.Process, groupLeader Process) { reducedPrecisionStartTime := timeutils.ReduceTimestampPrecision(groupLeader.PIDs.StartTimeNS) - interactive := interactiveFromTTY(groupLeader.CTTY) + interactive := tty.InteractiveFromTTY(groupLeader.CTTY) euid := groupLeader.Creds.Euid egid := groupLeader.Creds.Egid process.GroupLeader.PID = groupLeader.PIDs.Tgid @@ -525,7 +508,7 @@ func fillGroupLeader(process *types.Process, groupLeader Process) { func fillSessionLeader(process *types.Process, sessionLeader Process) { reducedPrecisionStartTime := timeutils.ReduceTimestampPrecision(sessionLeader.PIDs.StartTimeNS) - interactive := interactiveFromTTY(sessionLeader.CTTY) + interactive := tty.InteractiveFromTTY(sessionLeader.CTTY) euid := sessionLeader.Creds.Euid egid := sessionLeader.Creds.Egid process.SessionLeader.PID = sessionLeader.PIDs.Tgid @@ -550,7 +533,7 @@ func fillSessionLeader(process *types.Process, sessionLeader Process) { func fillEntryLeader(process *types.Process, entryType EntryType, entryLeader Process) { reducedPrecisionStartTime := timeutils.ReduceTimestampPrecision(entryLeader.PIDs.StartTimeNS) - interactive := interactiveFromTTY(entryLeader.CTTY) + interactive := tty.InteractiveFromTTY(entryLeader.CTTY) euid := entryLeader.Creds.Euid egid := entryLeader.Creds.Egid process.EntryLeader.PID = entryLeader.PIDs.Tgid @@ -743,22 +726,6 @@ func isFilteredExecutable(executable string) bool { return stringStartsWithEntryInList(executable, filteredExecutables[:]) } -func getTTYType(major uint32, minor uint32) TTYType { - if major >= ptsMinMajor && major <= ptsMaxMajor { - return Pts - } - - if ttyMajor == major { - if minor <= consoleMaxMinor { - return TTYConsole - } else if minor > consoleMaxMinor && minor <= ttyMaxMinor { - return TTY - } - } - - return TTYUnknown -} - func (db *DB) Close() { close(db.stopChan) } diff --git a/x-pack/auditbeat/processors/sessionmd/processdb/db_test.go b/x-pack/auditbeat/processors/sessionmd/processdb/db_test.go index 086c694f51fa..5cd1eed1ffcb 100644 --- a/x-pack/auditbeat/processors/sessionmd/processdb/db_test.go +++ b/x-pack/auditbeat/processors/sessionmd/processdb/db_test.go @@ -11,14 +11,15 @@ import ( "github.com/stretchr/testify/require" + "github.com/elastic/beats/v7/auditbeat/helper/tty" "github.com/elastic/elastic-agent-libs/logp" ) var logger = logp.NewLogger("processdb") func TestGetTTYType(t *testing.T) { - require.Equal(t, TTYConsole, getTTYType(4, 0)) - require.Equal(t, Pts, getTTYType(136, 0)) - require.Equal(t, TTY, getTTYType(4, 64)) - require.Equal(t, TTYUnknown, getTTYType(1000, 1000)) + require.Equal(t, tty.TTYConsole, tty.GetTTYType(4, 0)) + require.Equal(t, tty.Pts, tty.GetTTYType(136, 0)) + require.Equal(t, tty.TTY, tty.GetTTYType(4, 64)) + require.Equal(t, tty.TTYUnknown, tty.GetTTYType(1000, 1000)) } diff --git a/x-pack/auditbeat/processors/sessionmd/processdb/entry_leader_test.go b/x-pack/auditbeat/processors/sessionmd/processdb/entry_leader_test.go index fa0bc6e17993..a3315d61b4c4 100644 --- a/x-pack/auditbeat/processors/sessionmd/processdb/entry_leader_test.go +++ b/x-pack/auditbeat/processors/sessionmd/processdb/entry_leader_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" + "github.com/elastic/beats/v7/auditbeat/helper/tty" "github.com/elastic/beats/v7/x-pack/auditbeat/processors/sessionmd/procfs" "github.com/elastic/beats/v7/x-pack/auditbeat/processors/sessionmd/types" ) @@ -201,7 +202,7 @@ func TestSingleProcessSessionLeaderEntryTypeTerminal(t *testing.T) { Tgid: pid, Sid: pid, }, - CTTY: types.TTYDev{ + CTTY: tty.TTYDev{ Major: 4, Minor: 64, }, @@ -225,7 +226,7 @@ func TestSingleProcessSessionLeaderLoginProcess(t *testing.T) { Tgid: pid, Sid: pid, }, - CTTY: types.TTYDev{ + CTTY: tty.TTYDev{ Major: 4, Minor: 62, }, @@ -255,7 +256,7 @@ func TestSingleProcessSessionLeaderChildOfInit(t *testing.T) { Sid: pid, Ppid: 1, }, - CTTY: types.TTYDev{ + CTTY: tty.TTYDev{ Major: 136, Minor: 62, }, @@ -294,7 +295,7 @@ func TestSingleProcessSessionLeaderChildOfSsmSessionWorker(t *testing.T) { Sid: bashPID, Ppid: ssmPID, }, - CTTY: types.TTYDev{ + CTTY: tty.TTYDev{ Major: 136, Minor: 62, }, @@ -329,7 +330,7 @@ func TestSingleProcessSessionLeaderChildOfSshd(t *testing.T) { Sid: bashPID, Ppid: sshdPID, }, - CTTY: types.TTYDev{ + CTTY: tty.TTYDev{ Major: 136, Minor: 62, }, @@ -364,7 +365,7 @@ func TestSingleProcessSessionLeaderChildOfContainerdShim(t *testing.T) { Sid: bashPID, Ppid: containerdShimPID, }, - CTTY: types.TTYDev{ + CTTY: tty.TTYDev{ Major: 136, Minor: 62, }, @@ -400,7 +401,7 @@ func TestSingleProcessSessionLeaderChildOfRunc(t *testing.T) { Sid: bashPID, Ppid: runcPID, }, - CTTY: types.TTYDev{ + CTTY: tty.TTYDev{ Major: 136, Minor: 62, }, @@ -428,7 +429,7 @@ func TestSingleProcessEmptyProcess(t *testing.T) { Tgid: pid, Sid: pid, }, - CTTY: types.TTYDev{ + CTTY: tty.TTYDev{ Major: 136, Minor: 62, }, @@ -471,7 +472,7 @@ func TestSingleProcessOverwriteOldEntryLeader(t *testing.T) { Sid: ssmPID, Ppid: ssmPID, }, - CTTY: types.TTYDev{ + CTTY: tty.TTYDev{ Major: 136, Minor: 62, }, @@ -492,7 +493,7 @@ func TestSingleProcessOverwriteOldEntryLeader(t *testing.T) { Sid: bashPID, Ppid: ssmPID, }, - CTTY: types.TTYDev{ + CTTY: tty.TTYDev{ Major: 136, Minor: 62, }, diff --git a/x-pack/auditbeat/processors/sessionmd/procfs/procfs.go b/x-pack/auditbeat/processors/sessionmd/procfs/procfs.go index 992e24858363..2d5d26bc3883 100644 --- a/x-pack/auditbeat/processors/sessionmd/procfs/procfs.go +++ b/x-pack/auditbeat/processors/sessionmd/procfs/procfs.go @@ -13,6 +13,7 @@ import ( "github.com/prometheus/procfs" "golang.org/x/sys/unix" + "github.com/elastic/beats/v7/auditbeat/helper/tty" "github.com/elastic/beats/v7/x-pack/auditbeat/processors/sessionmd/timeutils" "github.com/elastic/beats/v7/x-pack/auditbeat/processors/sessionmd/types" "github.com/elastic/elastic-agent-libs/logp" @@ -47,7 +48,7 @@ type Stat procfs.ProcStat type ProcessInfo struct { PIDs types.PIDInfo Creds types.CredInfo - CTTY types.TTYDev + CTTY tty.TTYDev Argv []string Cwd string Env map[string]string @@ -165,7 +166,7 @@ func (r ProcfsReader) getProcessInfo(proc procfs.Proc) (ProcessInfo, error) { Sid: uint32(stat.Session), }, Creds: creds, - CTTY: types.TTYDev{ + CTTY: tty.TTYDev{ Major: MajorTTY(uint32(stat.TTY)), Minor: MinorTTY(uint32(stat.TTY)), }, diff --git a/x-pack/auditbeat/processors/sessionmd/provider/kerneltracingprovider/kerneltracingprovider_linux.go b/x-pack/auditbeat/processors/sessionmd/provider/kerneltracingprovider/kerneltracingprovider_linux.go index d3ec4ba7bd3d..e57c5d693557 100644 --- a/x-pack/auditbeat/processors/sessionmd/provider/kerneltracingprovider/kerneltracingprovider_linux.go +++ b/x-pack/auditbeat/processors/sessionmd/provider/kerneltracingprovider/kerneltracingprovider_linux.go @@ -20,6 +20,7 @@ import ( quark "github.com/elastic/go-quark" + "github.com/elastic/beats/v7/auditbeat/helper/tty" "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/beats/v7/x-pack/auditbeat/processors/sessionmd/provider" "github.com/elastic/beats/v7/x-pack/auditbeat/processors/sessionmd/types" @@ -38,15 +39,6 @@ type prvdr struct { backoffSkipped int } -type TTYType int - -const ( - TTYUnknown TTYType = iota - Pts - TTY - TTYConsole -) - const ( Init = "init" Sshd = "sshd" @@ -58,14 +50,6 @@ const ( EntryUnknown = "unknown" ) -const ( - ptsMinMajor = 136 - ptsMaxMajor = 143 - ttyMajor = 4 - consoleMaxMinor = 63 - ttyMaxMinor = 255 -) - var ( bootID string pidNsInode uint64 @@ -241,7 +225,7 @@ func (p *prvdr) GetProcess(pid uint32) (*types.Process, error) { return nil, fmt.Errorf("PID %d not found in cache", pid) } - interactive := interactiveFromTTY(types.TTYDev{ + interactive := tty.InteractiveFromTTY(tty.TTYDev{ Major: proc.Proc.TtyMajor, Minor: proc.Proc.TtyMinor, }) @@ -303,7 +287,7 @@ func (p prvdr) fillParent(process *types.Process, ppid uint32) { } start := time.Unix(0, int64(proc.Proc.TimeBoot)) - interactive := interactiveFromTTY(types.TTYDev{ + interactive := tty.InteractiveFromTTY(tty.TTYDev{ Major: proc.Proc.TtyMajor, Minor: proc.Proc.TtyMinor, }) @@ -338,7 +322,7 @@ func (p prvdr) fillGroupLeader(process *types.Process, pgid uint32) { start := time.Unix(0, int64(proc.Proc.TimeBoot)) - interactive := interactiveFromTTY(types.TTYDev{ + interactive := tty.InteractiveFromTTY(tty.TTYDev{ Major: proc.Proc.TtyMajor, Minor: proc.Proc.TtyMinor, }) @@ -373,7 +357,7 @@ func (p prvdr) fillSessionLeader(process *types.Process, sid uint32) { start := time.Unix(0, int64(proc.Proc.TimeBoot)) - interactive := interactiveFromTTY(types.TTYDev{ + interactive := tty.InteractiveFromTTY(tty.TTYDev{ Major: proc.Proc.TtyMajor, Minor: proc.Proc.TtyMinor, }) @@ -408,7 +392,7 @@ func (p prvdr) fillEntryLeader(process *types.Process, elid uint32) { start := time.Unix(0, int64(proc.Proc.TimeBoot)) - interactive := interactiveFromTTY(types.TTYDev{ + interactive := tty.InteractiveFromTTY(tty.TTYDev{ Major: proc.Proc.TtyMajor, Minor: proc.Proc.TtyMinor, }) @@ -475,28 +459,6 @@ func setSameAsProcess(process *types.Process) { } } -// interactiveFromTTY returns if this is an interactive tty device. -func interactiveFromTTY(tty types.TTYDev) bool { - return TTYUnknown != getTTYType(tty.Major, tty.Minor) -} - -// getTTYType returns the type of a TTY device based on its major and minor numbers. -func getTTYType(major uint32, minor uint32) TTYType { - if major >= ptsMinMajor && major <= ptsMaxMajor { - return Pts - } - - if ttyMajor == major { - if minor <= consoleMaxMinor { - return TTYConsole - } else if minor > consoleMaxMinor && minor <= ttyMaxMinor { - return TTY - } - } - - return TTYUnknown -} - // calculateEntityIDv1 calculates the entity ID for a process. // This is a globally unique identifier for the process. func calculateEntityIDv1(pid uint32, startTime time.Time) string { diff --git a/x-pack/auditbeat/processors/sessionmd/types/events.go b/x-pack/auditbeat/processors/sessionmd/types/events.go index 857ab8fa2c10..2f5cc3109e9d 100644 --- a/x-pack/auditbeat/processors/sessionmd/types/events.go +++ b/x-pack/auditbeat/processors/sessionmd/types/events.go @@ -6,6 +6,8 @@ package types //go:generate stringer -linecomment=true -type=Type,HookPoint,Field -output=gen_types_string.go +import "github.com/elastic/beats/v7/auditbeat/helper/tty" + type Type uint64 const ( @@ -47,25 +49,6 @@ type CredInfo struct { CapEffective uint64 } -type TTYWinsize struct { - Rows uint16 - Cols uint16 -} - -type TTYTermios struct { - CIflag uint32 - COflag uint32 - CLflag uint32 - CCflag uint32 -} - -type TTYDev struct { - Minor uint32 - Major uint32 - Winsize TTYWinsize - Termios TTYTermios -} - type ProcessForkEvent struct { ParentPIDs PIDInfo ChildPIDs PIDInfo @@ -75,7 +58,7 @@ type ProcessForkEvent struct { type ProcessExecEvent struct { PIDs PIDInfo Creds CredInfo - CTTY TTYDev + CTTY tty.TTYDev // varlen fields CWD string diff --git a/x-pack/filebeat/_meta/config/filebeat.inputs.reference.xpack.yml.tmpl b/x-pack/filebeat/_meta/config/filebeat.inputs.reference.xpack.yml.tmpl index 4188035f832a..4e966d594c57 100644 --- a/x-pack/filebeat/_meta/config/filebeat.inputs.reference.xpack.yml.tmpl +++ b/x-pack/filebeat/_meta/config/filebeat.inputs.reference.xpack.yml.tmpl @@ -102,6 +102,9 @@ # Bucket ARN used for polling AWS S3 buckets #bucket_arn: arn:aws:s3:::test-s3-bucket + # Access Point ARN used for polling AWS S3 buckets + #access_point_arn: arn:aws:s3:us-east-1:123456789:accesspoint/my-accesspoint + # Bucket Name used for polling non-AWS S3 buckets #non_aws_bucket_name: test-s3-bucket diff --git a/x-pack/filebeat/docs/inputs/input-aws-s3.asciidoc b/x-pack/filebeat/docs/inputs/input-aws-s3.asciidoc index aa8ecbf72595..406f9a00fed1 100644 --- a/x-pack/filebeat/docs/inputs/input-aws-s3.asciidoc +++ b/x-pack/filebeat/docs/inputs/input-aws-s3.asciidoc @@ -348,7 +348,7 @@ configuring multiline options. [float] ==== `queue_url` -URL of the AWS SQS queue that messages will be received from. (Required when `bucket_arn` and `non_aws_bucket_name` are not set). +URL of the AWS SQS queue that messages will be received from. (Required when `bucket_arn`, `access_point_arn`, and `non_aws_bucket_name` are not set). [float] ==== `region` @@ -472,7 +472,12 @@ value is `20s`. [float] ==== `bucket_arn` -ARN of the AWS S3 bucket that will be polled for list operation. (Required when `queue_url` and `non_aws_bucket_name` are not set). +ARN of the AWS S3 bucket that will be polled for list operation. (Required when `queue_url`, `access_point_arn, and `non_aws_bucket_name` are not set). + +[float] +==== `access_point_arn` + +ARN of the AWS S3 Access Point that will be polled for list operation. (Required when `queue_url`, `bucket_arn`, and `non_aws_bucket_name` are not set). [float] ==== `non_aws_bucket_name` @@ -492,7 +497,7 @@ Prefix to apply for the list request to the S3 bucket. Default empty. [float] ==== `number_of_workers` -Number of workers that will process the S3 or SQS objects listed. Required when `bucket_arn` is set, otherwise (in the SQS case) defaults to 5. +Number of workers that will process the S3 or SQS objects listed. Required when `bucket_arn` or `access_point_arn` is set, otherwise (in the SQS case) defaults to 5. [float] diff --git a/x-pack/filebeat/docs/inputs/input-azure-eventhub.asciidoc b/x-pack/filebeat/docs/inputs/input-azure-eventhub.asciidoc index 81cfdc66d524..808c46b83331 100644 --- a/x-pack/filebeat/docs/inputs/input-azure-eventhub.asciidoc +++ b/x-pack/filebeat/docs/inputs/input-azure-eventhub.asciidoc @@ -13,7 +13,10 @@ Users can make use of the `azure-eventhub` input in order to read messages from The azure-eventhub input implementation is based on the the event processor host (EPH is intended to be run across multiple processes and machines while load balancing message consumers more on this here https://github.com/Azure/azure-event-hubs-go#event-processor-host, https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-event-processor-host). State such as leases on partitions and checkpoints in the event stream are shared between receivers using an Azure Storage container. For this reason, as a prerequisite to using this input, users will have to create or use an existing storage account. - +Users can enable internal logs tracing for this input by setting the environment +variable `BEATS_AZURE_EVENTHUB_INPUT_TRACING_ENABLED: true`. When enabled, +this input will log additional information to the logs. Additional information +includes partition ownership, blob lease information, and other internal state. Example configuration: diff --git a/x-pack/filebeat/docs/inputs/input-cel.asciidoc b/x-pack/filebeat/docs/inputs/input-cel.asciidoc index 058c7d56ec05..c18a687653c6 100644 --- a/x-pack/filebeat/docs/inputs/input-cel.asciidoc +++ b/x-pack/filebeat/docs/inputs/input-cel.asciidoc @@ -1,7 +1,7 @@ [role="xpack"] :type: cel -:mito_version: v1.15.0 +:mito_version: v1.16.0 :mito_docs: https://pkg.go.dev/github.com/elastic/mito@{mito_version} [id="{beatname_lc}-input-{type}"] @@ -226,6 +226,9 @@ As noted above the `cel` input provides functions, macros, and global variables ** {mito_docs}/lib#hdr-RE_Find_All_Submatch[RE Find All Submatch] ** {mito_docs}/lib#hdr-RE_Replace_All[RE Replace All] +* {mito_docs}/lib#Printf[Printf] +** {mito_docs}/lib#hdr-Sprintf-Printf[Sprintf] + * {mito_docs}/lib#Strings[Strings] ** {mito_docs}/lib#hdr-String_Methods[String Methods] ** {mito_docs}/lib#hdr-String_List_Methods[String List Methods] @@ -792,6 +795,33 @@ This specifies fields in the `state` to be redacted prior to debug logging. Fiel This specifies whether fields should be replaced with a `*` or deleted entirely from messages sent to debug logs. If delete is `true`, fields will be deleted rather than replaced. +[float] +==== `failure_dump.enabled` + +It is possible to log CEL program evaluation failures to a local file-system for debugging configurations. +This option is enabled by setting `failure_dump.enabled` to true and setting the `failure_dump.filename` value. +To delete existing failure dumps, set `failure_dump.enabled` to false without unsetting the filename option. + +Enabling this option compromises security and should only be used for debugging. + +[float] +==== `failure_dump.filename` + +This specifies a directory path to write failure dumps to. If it is not empty and a CEL program evaluation fails, +the complete set of states for the CEL program's evaluation will be written as a JSON file, along with the error +that was reported. This option should only be used when debugging a failure as it imposes a significant performance +impact on the input and may potentially use large quantities of memory to hold the full set of states. If a failure +dump is configured, it is recommended that data input sizes be reduced to avoid excessive memory consumption, and +making dumps that are intractable to analysis. To delete existing failure dumps, set `failure_dump.enabled` to +false without unsetting the filename option. + +[[cel-record-coverage]] +[float] +==== `record_coverage` + +This specifies that CEL code evaluation coverage should be recorded and logged in debug logs. This is a +developer-only option. + [float] === Metrics diff --git a/x-pack/filebeat/docs/inputs/input-entity-analytics.asciidoc b/x-pack/filebeat/docs/inputs/input-entity-analytics.asciidoc index b4b701d3919d..faa50cf732d9 100644 --- a/x-pack/filebeat/docs/inputs/input-entity-analytics.asciidoc +++ b/x-pack/filebeat/docs/inputs/input-entity-analytics.asciidoc @@ -1015,7 +1015,21 @@ shorter than the full synchronization interval (`sync_interval`). Expressed as a duration string (e.g., 1m, 3h, 24h). Defaults to `15m` (15 minutes). [float] -==== `tracer.enabled` +===== `limit_window` + +The time between Okta API rate limit resets. +Expressed as a duration string (e.g., 1m, 3h, 24h). Defaults to `1m` (1 minute). + +[float] +===== `limit_fixed` + +The number of requests to allow in each limit window, if set. +This parameter should only be set in exceptional cases. When it is set, rate +limit information in API responses will be ignored in favor of the fixed limit. +The limit is applied separately to each endopint. Defaults to unset. + +[float] +===== `tracer.enabled` It is possible to log HTTP requests and responses to the Okta API to a local file-system for debugging configurations. This option is enabled by setting `tracer.enabled` to true and setting the `tracer.filename` value. @@ -1025,7 +1039,7 @@ to false without unsetting the filename option. Enabling this option compromises security and should only be used for debugging. [float] -==== `tracer.filename` +===== `tracer.filename` To differentiate the trace files generated from different input instances, a placeholder `*` can be added to the filename and will be replaced with the input instance id. For Example, `http-request-trace-*.ndjson`. diff --git a/x-pack/filebeat/docs/inputs/input-gcs.asciidoc b/x-pack/filebeat/docs/inputs/input-gcs.asciidoc index eae7158c78df..a2de572bce03 100644 --- a/x-pack/filebeat/docs/inputs/input-gcs.asciidoc +++ b/x-pack/filebeat/docs/inputs/input-gcs.asciidoc @@ -10,9 +10,7 @@ ++++ Use the `google cloud storage input` to read content from files stored in buckets which reside on your Google Cloud. -The input can be configured to work with and without polling, though currently, if polling is disabled it will only -perform a one time passthrough, list the file contents and end the process. Polling is generally recommented for most cases -even though it can get expensive with dealing with a very large number of files. +The input can be configured to work with and without polling, though if polling is disabled it will only perform a single collection of data, list the file contents and end the process. *To mitigate errors and ensure a stable processing environment, this input employs the following features :* @@ -25,6 +23,8 @@ even though it can get expensive with dealing with a very large number of files. 3. If any major error occurs which stops the main thread, the logs will be appropriately generated, describing said error. +**Config Option Removal Notice** : The `bucket_timeout` config option has been removed from the google cloud storage input. The intention behind this removal is to simplify the configuration and to make it more user friendly. The `bucket_timeout` option was confusing and had the potential to let users malconfigure the input, which could lead to unexpected behavior. The input now uses a more robust and efficient way to handle the bucket timeout internally. + [id="supported-types-gcs"] NOTE: Currently only `JSON` and `NDJSON` are supported object/file formats. Objects/files may be also be gzip compressed. "JSON credential keys" and "credential files" are supported authentication types. @@ -48,33 +48,30 @@ filebeat.inputs: max_workers: 3 poll: true poll_interval: 15s - bucket_timeout: 60s - name: gcs-test-old max_workers: 3 poll: true poll_interval: 10s - bucket_timeout: 30s ---- *Explanation :* This `configuration` given above describes a basic gcs config having two buckets named `gcs-test-new` and `gcs-test-old`. -Each of these buckets have their own attributes such as `name`, `max_workers`, `poll`, `poll_interval` and `bucket_timeout`. These attributes have detailed explanations +Each of these buckets have their own attributes such as `name`, `max_workers`, `poll` and `poll_interval`. These attributes have detailed explanations given <>. For now lets try to understand how this config works. For google cloud storage input to identify the files it needs to read and process, it will require the bucket names to be specified. We can have as -many buckets as we deem fit. We are also able to configure the attributes `max_workers`, `poll`, `poll_interval` and `bucket_timeout` at the root level, which will +many buckets as we deem fit. We are also able to configure the attributes `max_workers`, `poll` and `poll_interval` at the root level, which will then be applied to all buckets which do not specify any of these attributes explicitly. -NOTE: If the attributes `max_workers`, `poll`, `poll_interval` and `bucket_timeout` are specified at the root level, these can still be overridden at the bucket level with -different values, thus offering extensive flexibility and customization. Examples <> show this behaviour. +NOTE: If the attributes `max_workers`, `poll` and `poll_interval` are specified at the root level, these can still be overridden at the bucket level with +different values, thus offering extensive flexibility and customization. Examples <> show this behavior. On receiving this config the google cloud storage input will connect to the service and retrieve a `Storage Client` using the given `bucket_name` and `auth.credentials_file`, then it will spawn two main go-routines, one for each bucket. After this each of these routines (threads) will initialize a scheduler -which will in turn use the `max_workers` value to initialize an in-memory worker pool (thread pool) with `3` `workers` available. Basically that equates to two instances of a worker pool, -one per bucket, each having 3 workers. These `workers` will be responsible for performing `jobs` that process a file (in this case read and output the contents of a file). +which will in turn use the `max_workers` value to initialize an in-memory worker pool (thread pool) with `3` `workers` available. Basically that equates to two instances of a worker pool, one per bucket, each having 3 workers. These `workers` will be responsible for performing `jobs` that process a file (in this case read and output the contents of a file). NOTE: The scheduler is responsible for scheduling jobs, and uses the `maximum available workers` in the pool, at each iteration, to decide the number of files to retrieve and -process. This keeps work distribution efficient. The scheduler uses `poll_interval` attribute value to decide how long to wait after each iteration. The `bucket_timeout` value is used to timeout calls to the bucket list api if it exceeds the given value. Each iteration consists of processing a certain number of files, decided by the `maximum available workers` value. +process. This keeps work distribution efficient. The scheduler uses `poll_interval` attribute value to decide how long to wait after each iteration. Each iteration consists of processing a certain number of files, decided by the `maximum available workers` value. *A Sample Response :-* ["source","json"] @@ -159,14 +156,14 @@ Now let's explore the configuration attributes a bit more elaborately. 3. <> 4. <> 5. <> - 6. <> - 7. <> - 8. <> - 9. <> - 10. <> - 11. <> - 12. <> - 13. <> + 6. <> + 7. <> + 8. <> + 9. <> + 10. <> + 11. <> + 12. <> + 13. <> [id="attrib-project-id"] @@ -197,9 +194,7 @@ specified, then the one that occurs first in the configuration will be used. [float] ==== `buckets` -This attribute contains the details about a specific bucket like `name`, `max_workers`, `poll`, `poll_interval` and `bucket_timeout`. The attribute `name` is specific to a -bucket as it describes the bucket name, while the fields `max_workers`, `poll`, `poll_interval` and `bucket_timeout` can exist both at the bucket level and the root level. -This attribute is internally represented as an array, so we can add as many buckets as we require. +This attribute contains the details about a specific bucket like `name`, `max_workers`, `poll` and `poll_interval`. The attribute `name` is specific to a bucket as it describes the bucket name, while the fields `max_workers`, `poll` and `poll_interval` can exist both at the bucket level and the root level. This attribute is internally represented as an array, so we can add as many buckets as we require. [id="attrib-bucket-name"] [float] @@ -207,14 +202,6 @@ This attribute is internally represented as an array, so we can add as many buck This is a specific subfield of a bucket. It specifies the bucket name. -[id="attrib-bucket-timeout"] -[float] -==== `bucket_timeout` - -This attribute defines the maximum amount of time after which a bucket operation will give and stop if no response is recieved (example: reading a file / listing a file). -It can be defined in the following formats : `{{x}}s`, `{{x}}m`, `{{x}}h`, here `s = seconds`, `m = minutes` and `h = hours`. The value `{{x}}` can be anything we wish. -If no value is specified for this, by default its initialized to `50 seconds`. This attribute can be specified both at the root level of the configuration as well at the bucket level. The bucket level values will always take priority and override the root level values if both are specified. The value of `bucket_timeout` that should be used depends on the size of the files and the network speed. If the timeout is too low, the input will not be able to read the file completely and `context_deadline_exceeded` errors will be seen in the logs. If the timeout is too high, the input will wait for a long time for the file to be read, which can cause the input to be slow. The ratio between the `bucket_timeout` and `poll_interval` should be considered while setting both the values. A low `poll_interval` and a very high `bucket_timeout` can cause resource utilization issues as schedule ops will be spawned every poll iteration. If previous poll ops are still running, this could result in concurrently running ops and so could cause a bottleneck over time. - [id="attrib-max_workers-gcs"] [float] ==== `max_workers` @@ -228,9 +215,8 @@ NOTE: The value of `max_workers` is tied to the `batch_size` currently to ensure [float] ==== `poll` -This attribute informs the scheduler whether to keep polling for new files or not. Default value of this is `false`, so it will not keep polling if not explicitly -specified. This attribute can be specified both at the root level of the configuration as well at the bucket level. The bucket level values will always -take priority and override the root level values if both are specified. +This attribute informs the scheduler whether to keep polling for new files or not. Default value of this is set to `true`. This attribute can be specified both at the +root level of the configuration as well at the bucket level. The bucket level values will always take priority and override the root level values if both are specified. [id="attrib-poll_interval-gcs"] [float] @@ -238,11 +224,9 @@ take priority and override the root level values if both are specified. This attribute defines the maximum amount of time after which the internal scheduler will make the polling call for the next set of objects/files. It can be defined in the following formats : `{{x}}s`, `{{x}}m`, `{{x}}h`, here `s = seconds`, `m = minutes` and `h = hours`. The value `{{x}}` can be anything we wish. -Example : `10s` would mean we would like the polling to occur every 10 seconds. If no value is specified for this, by default its initialized to `300 seconds`. +Example : `10s` would mean we would like the polling to occur every 10 seconds. If no value is specified for this, by default its initialized to `5 minutes`. This attribute can be specified both at the root level of the configuration as well at the bucket level. The bucket level values will always take priority -and override the root level values if both are specified. The `poll_interval` should be set to a value that is equal to the `bucket_timeout` value. This would ensure that another schedule operation is not started before the current buckets have all been processed. If the `poll_interval` is set to a value that is less than the `bucket_timeout`, then the input will start another schedule operation before the current one has finished, which can cause a bottleneck over time. Having a lower `poll_interval` can make the input faster at the cost of more resource utilization. - -NOTE: Some edge case scenarios could require different values for `poll_interval` and `bucket_timeout`. For example, if the files are very large and the network speed is slow, then the `bucket_timeout` value should be set to a higher value than the `poll_interval`. This would ensure that polling operation does not wait too long for the files to be read and moves to the next iteration while the current one is still being processed. This would ensure a higher throughput and better resource utilization. +and override the root level values if both are specified. Having a lower `poll_interval` can make the input faster at the cost of more resource utilization. [id="attrib-parse_json"] [float] @@ -325,7 +309,6 @@ filebeat.inputs: max_workers: 3 poll: true poll_interval: 15s - bucket_timeout: 60s file_selectors: - regex: '/Monitoring/' - regex: 'docs/' @@ -371,7 +354,6 @@ filebeat.inputs: max_workers: 3 poll: true poll_interval: 15s - bucket_timeout: 60s expand_event_list_from_field: Records ---- @@ -395,12 +377,47 @@ filebeat.inputs: max_workers: 3 poll: true poll_interval: 15s - bucket_timeout: 60s timestamp_epoch: 1630444800 ---- The GCS APIs don't provide a direct way to filter files based on the timestamp, so the input will download all the files and then filter them based on the timestamp. This can cause a bottleneck in processing if the number of files are very high. It is recommended to use this attribute only when the number of files are limited or ample resources are available. This option scales vertically and not horizontally. +[id="attrib-retry-gcs"] +[float] +==== `retry` + +This attribute can be used to configure a list of sub attributes that directly control how the input should behave when a download for a file/object fails or gets interrupted. + + - `max_attempts`: This attribute defines the maximum number of retry attempts(including the initial api call) that should be attempted for a retryable error. The default value for this is `3`. + - `initial_backoff_duration`: This attribute defines the initial backoff time. The default value for this is `1s`. + - `max_backoff_duration`: This attribute defines the maximum backoff time. The default value for this is `30s`. + - `backoff_multiplier`: This attribute defines the backoff multiplication factor. The default value for this is `2`. + +NOTE: The `initial_backoff_duration` and `max_backoff_duration` attributes must have time units. Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. + +By configuring these attributes, the user is given the flexibility to control how the input should behave when a download fails or gets interrupted. This attribute can only be +specified at the root level of the configuration and not at the bucket level. It applies uniformly to all the buckets. + +An example configuration is given below :- + +[source, yml] +---- +filebeat.inputs: +- type: gcs + project_id: my_project_id + auth.credentials_file.path: {{file_path}}/{{creds_file_name}}.json + retry: + max_attempts: 3 + initial_backoff_duration: 2s + max_backoff_duration: 60s + backoff_multiplier: 2 + buckets: + - name: obs-bucket + max_workers: 3 + poll: true + poll_interval: 11m +---- + [id="bucket-overrides"] *The sample configs below will explain the bucket level overriding of attributes a bit further :-* @@ -462,5 +479,38 @@ filebeat.inputs: In this configuration even though we have specified `max_workers = 10`, `poll = true` and `poll_interval = 15s` at the root level, both the buckets will override these values with their own respective values which are defined as part of their sub attibutes. +[float] +=== Metrics + +This input exposes metrics under the <>. +These metrics are exposed under the `/inputs` path. They can be used to +observe the activity of the input. + +[options="header"] +|======= +| Metric | Description +| `url` | URL of the input resource. +| `errors_total` | Total number of errors encountered by the input. +| `decode_errors_total` | Total number of decode errors encountered by the input. +| `gcs_objects_requested_total` | Total number of GCS objects downloaded. +| `gcs_objects_published_total` | Total number of GCS objects processed that were published. +| `gcs_objects_listed_total` | Total number of GCS objects returned by list operations. +| `gcs_bytes_processed_total` | Total number of GCS bytes processed. +| `gcs_events_created_total` | Total number of events created from processing GCS data. +| `gcs_failed_jobs_total` | Total number of failed jobs. +| `gcs_expired_failed_jobs_total` | Total number of expired failed jobs that could not be recovered. +| `gcs_objects_tracked_gauge` | Number of objects currently tracked in the state registry (gauge). +| `gcs_objects_inflight_gauge` | Number of GCS objects inflight (gauge). +| `gcs_jobs_scheduled_after_validation` | Histogram of the number of jobs scheduled after validation. +| `gcs_object_processing_time` | Histogram of the elapsed GCS object processing times in nanoseconds (start of download to completion of parsing). +| `gcs_object_size_in_bytes` | Histogram of processed GCS object size in bytes. +| `gcs_events_per_object` | Histogram of event count per GCS object. +| `source_lag_time` | Histogram of the time between the source (Updated) timestamp and the time the object was read, in nanoseconds. +|======= + +==== Common input options + +[id="{beatname_lc}-input-{type}-common-options"] +include::../../../../filebeat/docs/inputs/input-common-options.asciidoc[] NOTE: Any feedback is welcome which will help us further optimize this input. Please feel free to open a github issue for any bugs or feature requests. diff --git a/x-pack/filebeat/docs/inputs/input-http-endpoint.asciidoc b/x-pack/filebeat/docs/inputs/input-http-endpoint.asciidoc index afd39fec0f12..29054ef9341f 100644 --- a/x-pack/filebeat/docs/inputs/input-http-endpoint.asciidoc +++ b/x-pack/filebeat/docs/inputs/input-http-endpoint.asciidoc @@ -40,6 +40,7 @@ These are the possible response codes from the server. | 406 | Not Acceptable | Returned if the POST request does not contain a body. | 415 | Unsupported Media Type | Returned if the Content-Type is not application/json. Or if Content-Encoding is present and is not gzip. | 500 | Internal Server Error | Returned if an I/O error occurs reading the request. +| 503 | Service Unavailable | Returned if the length of the request body would take the total number of in-flight bytes above the configured `max_in_flight_bytes` value. | 504 | Gateway Timeout | Returned if a request publication cannot be ACKed within the required timeout. |========================================================================================================================================================= @@ -285,6 +286,16 @@ The prefix for the signature. Certain webhooks prefix the HMAC signature with a By default the input expects the incoming POST to include a Content-Type of `application/json` to try to enforce the incoming data to be valid JSON. In certain scenarios when the source of the request is not able to do that, it can be overwritten with another value or set to null. +[float] +==== `max_in_flight_bytes` + +The total sum of request body lengths that are allowed at any given time. If non-zero, the input will compare this value to the sum of in-flight request body lengths from requests that include a `wait_for_completion_timeout` request query and will return a 503 HTTP status code, along with a Retry-After header configured with the `retry_after` option. The default value for this option is zero, no limit. + +[float] +==== `retry_after` + +If a request has exceeded the `max_in_flight_bytes` limit, the response to the client will include a Retry-After header specifying how many seconds the client should wait to retry again. The default value for this option is 10 seconds. + [float] ==== `program` diff --git a/x-pack/filebeat/docs/inputs/input-streaming.asciidoc b/x-pack/filebeat/docs/inputs/input-streaming.asciidoc index b80deda9c778..7f07fb4954f6 100644 --- a/x-pack/filebeat/docs/inputs/input-streaming.asciidoc +++ b/x-pack/filebeat/docs/inputs/input-streaming.asciidoc @@ -337,17 +337,39 @@ filebeat.inputs: [float] ==== `retry.max_attempts` -The maximum number of times the input should attempt to reconnect to the streaming data source in the event of a connection failure. The default value is `nil` which means no retries will be attempted. +The maximum number of times the input should attempt to reconnect to the streaming data source in the event of a connection failure. The default value is `5` which means a maximum of 5 retries will be attempted. [float] ==== `retry.wait_min` -The minimum time to wait between retries. This ensures that retries are spaced out enough to give the system time to recover or resolve transient issues, rather than bombarding the system with rapid retries. For example, `wait_min` might be set to 1 second, meaning that even if the calculated backoff is less than this, the client will wait at least 1 second before retrying. +The minimum time to wait between retries. This ensures that retries are spaced out enough to give the system time to recover or resolve transient issues, rather than bombarding the system with rapid retries. For example, `wait_min` might be set to 1 second, meaning that even if the calculated backoff is less than this, the client will wait at least 1 second before retrying. The default value is `1` second. [float] ==== `retry.wait_max` -The maximum time to wait between retries. This prevents the retry mechanism from becoming too slow, ensuring that the client does not wait indefinitely between retries. This is crucial in systems where timeouts or user experience are critical. For example, `wait_max` might be set to 10 seconds, meaning that even if the calculated backoff is greater than this, the client will wait at most 10 seconds before retrying. +The maximum time to wait between retries. This prevents the retry mechanism from becoming too slow, ensuring that the client does not wait indefinitely between retries. This is crucial in systems where timeouts or user experience are critical. For example, `wait_max` might be set to 10 seconds, meaning that even if the calculated backoff is greater than this, the client will wait at most 10 seconds before retrying. The default value is `30` seconds. + +[float] +=== `timeout` +Timeout is the maximum amount of time the websocket dialer will wait for a connection to be established. The default value is `180` seconds. + +[float] +==== `proxy_url` +This specifies the forward proxy URL to use for the connection. The `proxy_url` configuration is optional and can be used to configure the proxy settings for the connection. The `proxy_url` default value is set by `http.ProxyFromEnvironment` which reads the `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` environment variables. + +[float] +==== `proxy_headers` +This specifies the headers to be sent to the proxy server. The `proxy_headers` configuration is optional and can be used to configure the headers to be sent to the proxy server. + +[float] +==== `ssl` +This specifies the SSL configuration for the connection. The `ssl` configuration is optional and can be used to configure the SSL settings for the connection. The `ssl` configuration has the following subfields: + + - `certificate_authorities`: A list of root certificates to use for verifying the server's certificate. + - `certificate`: The (PEM encoded) certificate to use for client authentication. + - `key`: The (PEM encoded) private key to use for client authentication. + +If this is a self-signed certificate, the `certificate_authorities` field should be set to the certificate itself. [float] === Metrics diff --git a/x-pack/filebeat/docs/inputs/input-unifiedlogs.asciidoc b/x-pack/filebeat/docs/inputs/input-unifiedlogs.asciidoc new file mode 100644 index 000000000000..37589f307fb3 --- /dev/null +++ b/x-pack/filebeat/docs/inputs/input-unifiedlogs.asciidoc @@ -0,0 +1,180 @@ +[role="xpack"] + +:type: unifiedlogs + +[id="{beatname_lc}-input-{type}"] +=== Unified Logs input + +++++ +Unified Logs +++++ + +NOTE: Only available for MacOS. + +The unified logging system provides a comprehensive and performant API to capture +telemetry across all levels of the system. This system centralizes the storage of +log data in memory and on disk, rather than writing that data to a text-based log file. + +The input interacts with the `log` command-line tool to provide access to the events. + +The input starts streaming events from the current point in time unless a start date or +the `backfill` options are set. When restarted it will continue where it left off. + +Alternatively, it can also do one off operations, such as: + +- Stream events contained in a `.logarchive` file. +- Stream events contained in a `.tracev3` file. +- Stream events in a specific time span, by providing a specific end date. + +After this one off operations complete, the input will stop. + +Other configuration options can be specified to filter what events to process. + +NOTE: The input can cause some duplicated events when backfilling and/or +restarting. This is caused by how the underlying fetching method works and +should be taken into account when using the input. + +Example configuration: + +Process all old and new logs: + +["source","yaml",subs="attributes"] +---- +{beatname_lc}.inputs: +- type: unifiedlogs + id: unifiedlogs-id + enabled: true + backfill: true +---- + +Process logs with predicate filters: + +["source","yaml",subs="attributes"] +---- +{beatname_lc}.inputs: +- type: unifiedlogs + id: unifiedlogs-id + enabled: true + predicate: + # Captures keychain.db unlock events + - 'process == "loginwindow" && sender == "Security"' + # Captures user login events + - 'process == "logind"' + # Captures command line activity run with elevated privileges + - 'process == "sudo"' +---- + +==== Configuration options + +The `unifiedlogs` input supports the following configuration options plus the +<<{beatname_lc}-input-{type}-common-options>> described later. + +[float] +==== `archive_file` + +Display events stored in the given archive. +The archive must be a valid log archive bundle with the suffix `.logarchive`. + +[float] +==== `trace_file` + +Display events stored in the given `.tracev3` file. +In order to be decoded, the file must be contained within a valid `.logarchive` + +[float] +==== `start` + +Shows content starting from the provided date. +The following date/time formats are accepted: +`YYYY-MM-DD`, `YYYY-MM-DD HH:MM:SS`, `YYYY-MM-DD HH:MM:SSZZZZZ`. + +[float] +==== `end` + +Shows content up to the provided date. +The following date/time formats are accepted: +`YYYY-MM-DD`, `YYYY-MM-DD HH:MM:SS`, `YYYY-MM-DD HH:MM:SSZZZZZ`. + +[float] +==== `predicate` + +Filters messages using the provided predicate based on NSPredicate. +A compound predicate or multiple predicates can be provided as a list. + +For detailed information on the use of predicate based filtering, +please refer to the https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html[Predicate Programming Guide]. + +[float] +==== `process` + +A list of the processes on which to operate. It accepts a PID or process name. + +[float] +==== `source` + +Include symbol names and source line numbers for messages, if available. +Default: `false`. + +[float] +==== `info` + +Disable or enable info level messages. +Default: `false`. + +[float] +==== `debug` + +Disable or enable debug level messages. +Default: `false`. + +[float] +==== `backtrace` + +Disable or enable display of backtraces. +Default: `false`. + +[float] +==== `signpost` + +Disable or enable display of signposts. +Default: `false`. + +[float] +==== `unreliable` + +Annotate events with whether the log was emitted unreliably. +Default: `false`. + +[float] +==== `mach_continuous_time` + +Use mach continuous time timestamps rather than walltime. +Default: `false`. + +[float] +==== `backfill` + +If set to true the input will process all available logs since the beginning +of time the first time it starts. +Default: `false`. + + +[id="{beatname_lc}-input-{type}-common-options"] +include::../../../../filebeat/docs/inputs/input-common-options.asciidoc[] + +[float] +=== Metrics + +This input exposes metrics under the <>. +These metrics are exposed under the `/inputs/` path. They can be used to +observe the activity of the input. + +You must assign a unique `id` to the input to expose metrics. + +[options="header"] +|======= +| Metric | Description +| `errors_total` | Total number of errors. +|======= + +:type!: diff --git a/x-pack/filebeat/fbreceiver/factory.go b/x-pack/filebeat/fbreceiver/factory.go index 8bc6f872df75..a08c4d575cbb 100644 --- a/x-pack/filebeat/fbreceiver/factory.go +++ b/x-pack/filebeat/fbreceiver/factory.go @@ -31,7 +31,10 @@ func createDefaultConfig() component.Config { } func createReceiver(_ context.Context, set receiver.Settings, baseCfg component.Config, consumer consumer.Logs) (receiver.Logs, error) { - cfg := baseCfg.(*Config) + cfg, ok := baseCfg.(*Config) + if !ok { + return nil, fmt.Errorf("could not convert otel config to filebeat config") + } settings := cmd.FilebeatSettings(Name) globalProcs, err := processors.NewPluginConfigFromList(defaultProcessors()) @@ -59,7 +62,7 @@ func createReceiver(_ context.Context, set receiver.Settings, baseCfg component. return nil, fmt.Errorf("error getting %s creator:%w", Name, err) } - return &filebeatReceiver{beat: &b.Beat, beater: fbBeater}, nil + return &filebeatReceiver{beat: &b.Beat, beater: fbBeater, logger: set.Logger}, nil } func defaultProcessors() []mapstr.M { diff --git a/x-pack/filebeat/fbreceiver/receiver.go b/x-pack/filebeat/fbreceiver/receiver.go index bb39dc57077b..eeba511dd1e7 100644 --- a/x-pack/filebeat/fbreceiver/receiver.go +++ b/x-pack/filebeat/fbreceiver/receiver.go @@ -10,21 +10,28 @@ import ( "github.com/elastic/beats/v7/libbeat/beat" "go.opentelemetry.io/collector/component" + "go.uber.org/zap" ) type filebeatReceiver struct { beat *beat.Beat beater beat.Beater + logger *zap.Logger } func (fb *filebeatReceiver) Start(ctx context.Context, host component.Host) error { go func() { - _ = fb.beater.Run(fb.beat) + fb.logger.Info("starting filebeat receiver") + err := fb.beater.Run(fb.beat) + if err != nil { + fb.logger.Error("filebeat receiver run error", zap.Error(err)) + } }() return nil } func (fb *filebeatReceiver) Shutdown(ctx context.Context) error { + fb.logger.Info("stopping filebeat receiver") fb.beater.Stop() return nil } diff --git a/x-pack/filebeat/filebeat.reference.yml b/x-pack/filebeat/filebeat.reference.yml index 5e6369015657..c5c04232cd3f 100644 --- a/x-pack/filebeat/filebeat.reference.yml +++ b/x-pack/filebeat/filebeat.reference.yml @@ -21,6 +21,9 @@ filebeat.modules: # Filebeat will choose the paths depending on your OS. #var.paths: + # Use journald to collect system logs + #var.use_journald: false + # Input configuration (advanced). Any input configuration option # can be added under this section. #input: @@ -33,6 +36,9 @@ filebeat.modules: # Filebeat will choose the paths depending on your OS. #var.paths: + # Use journald to collect auth logs + #var.use_journald: false + # Input configuration (advanced). Any input configuration option # can be added under this section. #input: @@ -2990,6 +2996,9 @@ filebeat.inputs: # Bucket ARN used for polling AWS S3 buckets #bucket_arn: arn:aws:s3:::test-s3-bucket + # Access Point ARN used for polling AWS S3 buckets + #access_point_arn: arn:aws:s3:us-east-1:123456789:accesspoint/my-accesspoint + # Bucket Name used for polling non-AWS S3 buckets #non_aws_bucket_name: test-s3-bucket diff --git a/x-pack/filebeat/input/awss3/config.go b/x-pack/filebeat/input/awss3/config.go index 6f485431ddf6..843061ae3c3e 100644 --- a/x-pack/filebeat/input/awss3/config.go +++ b/x-pack/filebeat/input/awss3/config.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "net/url" + "strings" "time" awssdk "github.com/aws/aws-sdk-go-v2/aws" @@ -33,6 +34,7 @@ type config struct { QueueURL string `config:"queue_url"` RegionName string `config:"region"` BucketARN string `config:"bucket_arn"` + AccessPointARN string `config:"access_point_arn"` NonAWSBucketName string `config:"non_aws_bucket_name"` BucketListInterval time.Duration `config:"bucket_list_interval"` BucketListPrefix string `config:"bucket_list_prefix"` @@ -61,7 +63,7 @@ func defaultConfig() config { } func (c *config) Validate() error { - configs := []bool{c.QueueURL != "", c.BucketARN != "", c.NonAWSBucketName != ""} + configs := []bool{c.QueueURL != "", c.BucketARN != "", c.AccessPointARN != "", c.NonAWSBucketName != ""} enabled := []bool{} for i := range configs { if configs[i] { @@ -69,20 +71,24 @@ func (c *config) Validate() error { } } if len(enabled) == 0 { - return errors.New("neither queue_url, bucket_arn nor non_aws_bucket_name were provided") + return errors.New("neither queue_url, bucket_arn, access_point_arn, nor non_aws_bucket_name were provided") } else if len(enabled) > 1 { - return fmt.Errorf("queue_url <%v>, bucket_arn <%v>, non_aws_bucket_name <%v> "+ - "cannot be set at the same time", c.QueueURL, c.BucketARN, c.NonAWSBucketName) + return fmt.Errorf("queue_url <%v>, bucket_arn <%v>, access_point_arn <%v>, non_aws_bucket_name <%v> "+ + "cannot be set at the same time", c.QueueURL, c.BucketARN, c.AccessPointARN, c.NonAWSBucketName) } - if (c.BucketARN != "" || c.NonAWSBucketName != "") && c.BucketListInterval <= 0 { + if (c.BucketARN != "" || c.AccessPointARN != "" || c.NonAWSBucketName != "") && c.BucketListInterval <= 0 { return fmt.Errorf("bucket_list_interval <%v> must be greater than 0", c.BucketListInterval) } - if (c.BucketARN != "" || c.NonAWSBucketName != "") && c.NumberOfWorkers <= 0 { + if (c.BucketARN != "" || c.AccessPointARN != "" || c.NonAWSBucketName != "") && c.NumberOfWorkers <= 0 { return fmt.Errorf("number_of_workers <%v> must be greater than 0", c.NumberOfWorkers) } + if c.AccessPointARN != "" && !isValidAccessPointARN(c.AccessPointARN) { + return fmt.Errorf("invalid format for access_point_arn <%v>", c.AccessPointARN) + } + if c.QueueURL != "" && (c.VisibilityTimeout <= 0 || c.VisibilityTimeout.Hours() > 12) { return fmt.Errorf("visibility_timeout <%v> must be greater than 0 and "+ "less than or equal to 12h", c.VisibilityTimeout) @@ -117,14 +123,15 @@ func (c *config) Validate() error { if c.BackupConfig.NonAWSBackupToBucketName != "" && c.NonAWSBucketName == "" { return errors.New("backup to non-AWS bucket can only be used for non-AWS sources") } - if c.BackupConfig.BackupToBucketArn != "" && c.BucketARN == "" { + if c.BackupConfig.BackupToBucketArn != "" && c.BucketARN == "" && c.AccessPointARN == "" { return errors.New("backup to AWS bucket can only be used for AWS sources") } if c.BackupConfig.BackupToBucketArn != "" && c.BackupConfig.NonAWSBackupToBucketName != "" { return errors.New("backup_to_bucket_arn and non_aws_backup_to_bucket_name cannot be used together") } if c.BackupConfig.GetBucketName() != "" && c.QueueURL == "" { - if (c.BackupConfig.BackupToBucketArn != "" && c.BackupConfig.BackupToBucketArn == c.BucketARN) || + if (c.BackupConfig.BackupToBucketArn != "" && + (c.BackupConfig.BackupToBucketArn == c.BucketARN || c.BackupConfig.BackupToBucketArn == c.AccessPointARN)) || (c.BackupConfig.NonAWSBackupToBucketName != "" && c.BackupConfig.NonAWSBackupToBucketName == c.NonAWSBucketName) { if c.BackupConfig.BackupToBucketPrefix == "" { return errors.New("backup_to_bucket_prefix is a required property when source and backup bucket are the same") @@ -233,6 +240,9 @@ func (c config) getBucketName() string { if c.NonAWSBucketName != "" { return c.NonAWSBucketName } + if c.AccessPointARN != "" { + return c.AccessPointARN + } if c.BucketARN != "" { return getBucketNameFromARN(c.BucketARN) } @@ -246,6 +256,9 @@ func (c config) getBucketARN() string { if c.BucketARN != "" { return c.BucketARN } + if c.AccessPointARN != "" { + return c.AccessPointARN + } return "" } @@ -292,3 +305,11 @@ func (c config) getFileSelectors() []fileSelectorConfig { } return []fileSelectorConfig{{ReaderConfig: c.ReaderConfig}} } + +// Helper function to detect if an ARN is an Access Point +func isValidAccessPointARN(arn string) bool { + parts := strings.Split(arn, ":") + return len(parts) >= 6 && + strings.HasPrefix(parts[5], "accesspoint/") && + len(strings.TrimPrefix(parts[5], "accesspoint/")) > 0 +} diff --git a/x-pack/filebeat/input/awss3/config_test.go b/x-pack/filebeat/input/awss3/config_test.go index 907a5854b284..d791271ba6ef 100644 --- a/x-pack/filebeat/input/awss3/config_test.go +++ b/x-pack/filebeat/input/awss3/config_test.go @@ -23,8 +23,9 @@ import ( func TestConfig(t *testing.T) { const queueURL = "https://example.com" const s3Bucket = "arn:aws:s3:::aBucket" + const s3AccessPoint = "arn:aws:s3:us-east-2:123456789:accesspoint/test-accesspoint" const nonAWSS3Bucket = "minio-bucket" - makeConfig := func(quequeURL, s3Bucket string, nonAWSS3Bucket string) config { + makeConfig := func(quequeURL, s3Bucket string, s3AccessPoint string, nonAWSS3Bucket string) config { // Have a separate copy of defaults in the test to make it clear when // anyone changes the defaults. parserConf := parser.Config{} @@ -32,6 +33,7 @@ func TestConfig(t *testing.T) { return config{ QueueURL: quequeURL, BucketARN: s3Bucket, + AccessPointARN: s3AccessPoint, NonAWSBucketName: nonAWSS3Bucket, APITimeout: 120 * time.Second, VisibilityTimeout: 300 * time.Second, @@ -54,15 +56,17 @@ func TestConfig(t *testing.T) { name string queueURL string s3Bucket string + s3AccessPoint string nonAWSS3Bucket string config mapstr.M expectedErr string - expectedCfg func(queueURL, s3Bucket, nonAWSS3Bucket string) config + expectedCfg func(queueURL, s3Bucket, s3AccessPoint, nonAWSS3Bucket string) config }{ { name: "input with defaults for queueURL", queueURL: queueURL, s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "queue_url": queueURL, @@ -74,14 +78,15 @@ func TestConfig(t *testing.T) { name: "input with defaults for s3Bucket", queueURL: "", s3Bucket: s3Bucket, + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "bucket_arn": s3Bucket, "number_of_workers": 5, }, expectedErr: "", - expectedCfg: func(queueURL, s3Bucket, nonAWSS3Bucket string) config { - c := makeConfig("", s3Bucket, "") + expectedCfg: func(queueURL, s3Bucket, s3AccessPoint, nonAWSS3Bucket string) config { + c := makeConfig("", s3Bucket, "", "") c.NumberOfWorkers = 5 return c }, @@ -90,6 +95,7 @@ func TestConfig(t *testing.T) { name: "input with file_selectors", queueURL: queueURL, s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "queue_url": queueURL, @@ -100,8 +106,8 @@ func TestConfig(t *testing.T) { }, }, expectedErr: "", - expectedCfg: func(queueURL, s3Bucket, nonAWSS3Bucket string) config { - c := makeConfig(queueURL, "", "") + expectedCfg: func(queueURL, s3Bucket, s3AccessPoint, nonAWSS3Bucket string) config { + c := makeConfig(queueURL, "", "", "") regex := match.MustCompile("/CloudTrail/") c.FileSelectors = []fileSelectorConfig{ { @@ -116,6 +122,7 @@ func TestConfig(t *testing.T) { name: "non-AWS_endpoint_with_explicit_region", queueURL: queueURL, s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "queue_url": queueURL, @@ -123,8 +130,8 @@ func TestConfig(t *testing.T) { "endpoint": "ep", }, expectedErr: "", - expectedCfg: func(queueURL, s3Bucket, nonAWSS3Bucket string) config { - c := makeConfig(queueURL, "", "") + expectedCfg: func(queueURL, s3Bucket, s3AccessPoint, nonAWSS3Bucket string) config { + c := makeConfig(queueURL, "", "", "") c.RegionName = "region" c.AWSConfig.Endpoint = "ep" return c @@ -134,6 +141,7 @@ func TestConfig(t *testing.T) { name: "explicit_AWS_endpoint_with_explicit_region", queueURL: queueURL, s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "queue_url": "https://sqs.us-east-1.amazonaws.com/627959692251/test-s3-logs", @@ -141,8 +149,8 @@ func TestConfig(t *testing.T) { "endpoint": "amazonaws.com", }, expectedErr: "", - expectedCfg: func(queueURL, s3Bucket, nonAWSS3Bucket string) config { - c := makeConfig(queueURL, "", "") + expectedCfg: func(queueURL, s3Bucket, s3AccessPoint, nonAWSS3Bucket string) config { + c := makeConfig(queueURL, "", "", "") c.QueueURL = "https://sqs.us-east-1.amazonaws.com/627959692251/test-s3-logs" c.AWSConfig.Endpoint = "amazonaws.com" c.RegionName = "region" @@ -153,14 +161,15 @@ func TestConfig(t *testing.T) { name: "inferred_AWS_endpoint_with_explicit_region", queueURL: queueURL, s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "queue_url": "https://sqs.us-east-1.amazonaws.com/627959692251/test-s3-logs", "region": "region", }, expectedErr: "", - expectedCfg: func(queueURL, s3Bucket, nonAWSS3Bucket string) config { - c := makeConfig(queueURL, "", "") + expectedCfg: func(queueURL, s3Bucket, s3AccessPoint, nonAWSS3Bucket string) config { + c := makeConfig(queueURL, "", "", "") c.QueueURL = "https://sqs.us-east-1.amazonaws.com/627959692251/test-s3-logs" c.RegionName = "region" return c @@ -170,84 +179,105 @@ func TestConfig(t *testing.T) { name: "localstack_with_region_name", queueURL: "http://localhost:4566/000000000000/sample-queue", s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "queue_url": "http://localhost:4566/000000000000/sample-queue", "region": "myregion", }, expectedErr: "", - expectedCfg: func(queueURL, s3Bucket, nonAWSS3Bucket string) config { - c := makeConfig(queueURL, "", "") + expectedCfg: func(queueURL, s3Bucket, s3AccessPoint, nonAWSS3Bucket string) config { + c := makeConfig(queueURL, "", "", "") c.RegionName = "myregion" return c }, }, { - name: "error on no queueURL and s3Bucket and nonAWSS3Bucket", + name: "error on no queueURL, s3Bucket, s3AccessPoint, and nonAWSS3Bucket", queueURL: "", s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "queue_url": "", "bucket_arn": "", + "access_point_arn": "", "non_aws_bucket_name": "", }, - expectedErr: "neither queue_url, bucket_arn nor non_aws_bucket_name were provided", + expectedErr: "neither queue_url, bucket_arn, access_point_arn, nor non_aws_bucket_name were provided", expectedCfg: nil, }, { name: "error on both queueURL and s3Bucket", queueURL: queueURL, s3Bucket: s3Bucket, + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "queue_url": queueURL, "bucket_arn": s3Bucket, }, - expectedErr: "queue_url , bucket_arn , non_aws_bucket_name <> cannot be set at the same time", + expectedErr: "queue_url , bucket_arn , access_point_arn <>, non_aws_bucket_name <> cannot be set at the same time", expectedCfg: nil, }, { name: "error on both queueURL and NonAWSS3Bucket", queueURL: queueURL, s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: nonAWSS3Bucket, config: mapstr.M{ "queue_url": queueURL, "non_aws_bucket_name": nonAWSS3Bucket, }, - expectedErr: "queue_url , bucket_arn <>, non_aws_bucket_name cannot be set at the same time", + expectedErr: "queue_url , bucket_arn <>, access_point_arn <>, non_aws_bucket_name cannot be set at the same time", expectedCfg: nil, }, { name: "error on both s3Bucket and NonAWSS3Bucket", queueURL: "", s3Bucket: s3Bucket, + s3AccessPoint: "", nonAWSS3Bucket: nonAWSS3Bucket, config: mapstr.M{ "bucket_arn": s3Bucket, "non_aws_bucket_name": nonAWSS3Bucket, }, - expectedErr: "queue_url <>, bucket_arn , non_aws_bucket_name cannot be set at the same time", + expectedErr: "queue_url <>, bucket_arn , access_point_arn <>, non_aws_bucket_name cannot be set at the same time", expectedCfg: nil, }, { name: "error on queueURL, s3Bucket, and NonAWSS3Bucket", queueURL: queueURL, s3Bucket: s3Bucket, + s3AccessPoint: "", nonAWSS3Bucket: nonAWSS3Bucket, config: mapstr.M{ "queue_url": queueURL, "bucket_arn": s3Bucket, "non_aws_bucket_name": nonAWSS3Bucket, }, - expectedErr: "queue_url , bucket_arn , non_aws_bucket_name cannot be set at the same time", + expectedErr: "queue_url , bucket_arn , access_point_arn <>, non_aws_bucket_name cannot be set at the same time", + expectedCfg: nil, + }, + { + name: "error on both s3Bucket and s3AccessPoint", + queueURL: "", + s3Bucket: s3Bucket, + s3AccessPoint: s3AccessPoint, + nonAWSS3Bucket: nonAWSS3Bucket, + config: mapstr.M{ + "bucket_arn": s3Bucket, + "access_point_arn": s3AccessPoint, + }, + expectedErr: "queue_url <>, bucket_arn , access_point_arn , non_aws_bucket_name <> cannot be set at the same time", expectedCfg: nil, }, { name: "error on api_timeout == 0", queueURL: queueURL, s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "queue_url": queueURL, @@ -260,6 +290,7 @@ func TestConfig(t *testing.T) { name: "error on visibility_timeout == 0", queueURL: queueURL, s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "queue_url": queueURL, @@ -272,6 +303,7 @@ func TestConfig(t *testing.T) { name: "error on visibility_timeout > 12h", queueURL: queueURL, s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "queue_url": queueURL, @@ -284,6 +316,7 @@ func TestConfig(t *testing.T) { name: "error on bucket_list_interval == 0", queueURL: "", s3Bucket: s3Bucket, + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "bucket_arn": s3Bucket, @@ -296,6 +329,7 @@ func TestConfig(t *testing.T) { name: "error on number_of_workers == 0", queueURL: "", s3Bucket: s3Bucket, + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "bucket_arn": s3Bucket, @@ -308,6 +342,7 @@ func TestConfig(t *testing.T) { name: "error on buffer_size == 0 ", queueURL: queueURL, s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "queue_url": queueURL, @@ -320,6 +355,7 @@ func TestConfig(t *testing.T) { name: "error on max_bytes == 0 ", queueURL: queueURL, s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "queue_url": queueURL, @@ -332,6 +368,7 @@ func TestConfig(t *testing.T) { name: "error on expand_event_list_from_field and content_type != application/json ", queueURL: queueURL, s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "queue_url": queueURL, @@ -345,6 +382,7 @@ func TestConfig(t *testing.T) { name: "error on expand_event_list_from_field and content_type != application/json ", queueURL: "", s3Bucket: s3Bucket, + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "bucket_arn": s3Bucket, @@ -358,14 +396,15 @@ func TestConfig(t *testing.T) { name: "input with defaults for non-AWS S3 Bucket", queueURL: "", s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: nonAWSS3Bucket, config: mapstr.M{ "non_aws_bucket_name": nonAWSS3Bucket, "number_of_workers": 5, }, expectedErr: "", - expectedCfg: func(queueURL, s3Bucket, nonAWSS3Bucket string) config { - c := makeConfig("", "", nonAWSS3Bucket) + expectedCfg: func(queueURL, s3Bucket, s3AccessPoint, nonAWSS3Bucket string) config { + c := makeConfig("", "", "", nonAWSS3Bucket) c.NumberOfWorkers = 5 return c }, @@ -374,6 +413,7 @@ func TestConfig(t *testing.T) { name: "error on FIPS with non-AWS S3 Bucket", queueURL: "", s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: nonAWSS3Bucket, config: mapstr.M{ "non_aws_bucket_name": nonAWSS3Bucket, @@ -387,6 +427,7 @@ func TestConfig(t *testing.T) { name: "error on path_style with AWS native S3 Bucket", queueURL: "", s3Bucket: s3Bucket, + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "bucket_arn": s3Bucket, @@ -400,6 +441,7 @@ func TestConfig(t *testing.T) { name: "error on provider with AWS native S3 Bucket", queueURL: "", s3Bucket: s3Bucket, + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "bucket_arn": s3Bucket, @@ -413,6 +455,7 @@ func TestConfig(t *testing.T) { name: "error on provider with AWS SQS Queue", queueURL: queueURL, s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "queue_url": queueURL, @@ -426,6 +469,7 @@ func TestConfig(t *testing.T) { name: "backup_to_bucket with AWS", queueURL: "", s3Bucket: s3Bucket, + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "bucket_arn": s3Bucket, @@ -434,8 +478,8 @@ func TestConfig(t *testing.T) { "number_of_workers": 5, }, expectedErr: "", - expectedCfg: func(queueURL, s3Bucket, nonAWSS3Bucket string) config { - c := makeConfig("", s3Bucket, "") + expectedCfg: func(queueURL, s3Bucket, s3AccessPoint, nonAWSS3Bucket string) config { + c := makeConfig("", s3Bucket, "", "") c.BackupConfig.BackupToBucketArn = "arn:aws:s3:::bBucket" c.BackupConfig.BackupToBucketPrefix = "backup" c.NumberOfWorkers = 5 @@ -446,6 +490,7 @@ func TestConfig(t *testing.T) { name: "backup_to_bucket with non-AWS", queueURL: "", s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: nonAWSS3Bucket, config: mapstr.M{ "non_aws_bucket_name": nonAWSS3Bucket, @@ -454,8 +499,8 @@ func TestConfig(t *testing.T) { "number_of_workers": 5, }, expectedErr: "", - expectedCfg: func(queueURL, s3Bucket, nonAWSS3Bucket string) config { - c := makeConfig("", "", nonAWSS3Bucket) + expectedCfg: func(queueURL, s3Bucket, s3AccessPoint, nonAWSS3Bucket string) config { + c := makeConfig("", "", "", nonAWSS3Bucket) c.NonAWSBucketName = nonAWSS3Bucket c.BackupConfig.NonAWSBackupToBucketName = "bBucket" c.BackupConfig.BackupToBucketPrefix = "backup" @@ -467,6 +512,7 @@ func TestConfig(t *testing.T) { name: "error with non-AWS backup and AWS source", queueURL: "", s3Bucket: s3Bucket, + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "bucket_arn": s3Bucket, @@ -480,6 +526,7 @@ func TestConfig(t *testing.T) { name: "error with AWS backup and non-AWS source", queueURL: "", s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: nonAWSS3Bucket, config: mapstr.M{ "non_aws_bucket_name": nonAWSS3Bucket, @@ -493,6 +540,7 @@ func TestConfig(t *testing.T) { name: "error with same bucket backup and empty backup prefix", queueURL: "", s3Bucket: s3Bucket, + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "bucket_arn": s3Bucket, @@ -506,6 +554,7 @@ func TestConfig(t *testing.T) { name: "error with same bucket backup (non-AWS) and empty backup prefix", queueURL: "", s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: nonAWSS3Bucket, config: mapstr.M{ "non_aws_bucket_name": nonAWSS3Bucket, @@ -519,6 +568,7 @@ func TestConfig(t *testing.T) { name: "error with same bucket backup and backup prefix equal to list prefix", queueURL: "", s3Bucket: s3Bucket, + s3AccessPoint: "", nonAWSS3Bucket: "", config: mapstr.M{ "bucket_arn": s3Bucket, @@ -534,6 +584,7 @@ func TestConfig(t *testing.T) { name: "error with same bucket backup (non-AWS) and backup prefix equal to list prefix", queueURL: "", s3Bucket: "", + s3AccessPoint: "", nonAWSS3Bucket: nonAWSS3Bucket, config: mapstr.M{ "non_aws_bucket_name": nonAWSS3Bucket, @@ -563,7 +614,67 @@ func TestConfig(t *testing.T) { if tc.expectedCfg == nil { t.Fatal("missing expected config in test case") } - assert.EqualValues(t, tc.expectedCfg(tc.queueURL, tc.s3Bucket, tc.nonAWSS3Bucket), c) + assert.EqualValues(t, tc.expectedCfg(tc.queueURL, tc.s3Bucket, tc.s3AccessPoint, tc.nonAWSS3Bucket), c) + }) + } +} + +// TestIsValidAccessPointARN tests the isValidAccessPointARN function +func TestIsValidAccessPointARN(t *testing.T) { + testCases := []struct { + name string + arn string + expected bool + }{ + { + name: "Valid Access Point ARN", + arn: "arn:aws:s3:us-east-1:123456789:accesspoint/my-access-point", + expected: true, + }, + { + name: "Valid Access Point ARN with another region", + arn: "arn:aws:s3:us-west-2:123456789:accesspoint/my-access-point", + expected: true, + }, + { + name: "Invalid ARN with missing parts", + arn: "arn:aws:s3:123456789:accesspoint", + expected: false, + }, + { + name: "Invalid ARN without accesspoint keyword", + arn: "arn:aws:s3:us-east-1:123456789:bucket/my-bucket", + expected: false, + }, + { + name: "Invalid ARN with wrong format", + arn: "arn:aws:s3:us-east-1:123456789:my-access-point", + expected: false, + }, + { + name: "Empty ARN", + arn: "", + expected: false, + }, + { + name: "ARN with extra parts but valid access point format", + arn: "arn:aws:s3:us-east-1:123456789:accesspoint/my-access-point/extra", + expected: true, + }, + { + name: "ARN with empty name", + arn: "arn:aws:s3:us-east-1:123456789:accesspoint/", + expected: false, + }, + } + + // Run test cases + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := isValidAccessPointARN(tc.arn) + if result != tc.expected { + t.Errorf("expected %v, got %v for ARN: %s", tc.expected, result, tc.arn) + } }) } } diff --git a/x-pack/filebeat/input/awss3/input.go b/x-pack/filebeat/input/awss3/input.go index 6d62f454c427..32f9f24be464 100644 --- a/x-pack/filebeat/input/awss3/input.go +++ b/x-pack/filebeat/input/awss3/input.go @@ -46,9 +46,9 @@ func (im *s3InputManager) Create(cfg *conf.C) (v2.Input, error) { return nil, fmt.Errorf("initializing AWS config: %w", err) } - // The awsConfig now contains the region from the credential profile or default region - // if the region is explicitly set in the config, then it wins if config.RegionName != "" { + // The awsConfig now contains the region from the credential profile or default region + // if the region is explicitly set in the config, then it wins awsConfig.Region = config.RegionName } @@ -56,7 +56,7 @@ func (im *s3InputManager) Create(cfg *conf.C) (v2.Input, error) { return newSQSReaderInput(config, awsConfig), nil } - if config.BucketARN != "" || config.NonAWSBucketName != "" { + if config.BucketARN != "" || config.AccessPointARN != "" || config.NonAWSBucketName != "" { return newS3PollerInput(config, awsConfig, im.store) } diff --git a/x-pack/filebeat/input/awss3/input_benchmark_test.go b/x-pack/filebeat/input/awss3/input_benchmark_test.go index 54e227736025..319d8c3b9aa3 100644 --- a/x-pack/filebeat/input/awss3/input_benchmark_test.go +++ b/x-pack/filebeat/input/awss3/input_benchmark_test.go @@ -339,7 +339,7 @@ func benchmarkInputS3(t *testing.T, numberOfWorkers int) testing.BenchmarkResult s3API.pagerConstant = newS3PagerConstant(curConfig.BucketListPrefix) store := openTestStatestore() - states, err := newStates(nil, store) + states, err := newStates(nil, store, "") assert.NoError(t, err, "states creation should succeed") s3EventHandlerFactory := newS3ObjectProcessorFactory(metrics, s3API, config.FileSelectors, backupConfig{}) diff --git a/x-pack/filebeat/input/awss3/input_integration_test.go b/x-pack/filebeat/input/awss3/input_integration_test.go index cf47f7b9230f..cea23270128c 100644 --- a/x-pack/filebeat/input/awss3/input_integration_test.go +++ b/x-pack/filebeat/input/awss3/input_integration_test.go @@ -608,9 +608,77 @@ func drainSQS(t *testing.T, region string, queueURL string, cfg aws.Config) { t.Logf("Drained %d SQS messages.", deletedCount) } +func TestGetRegionFromAccessPointARN(t *testing.T) { + // Define test cases + testCases := []struct { + name string + arn string + expected string + }{ + { + name: "Valid Access Point ARN", + arn: "arn:aws:s3:us-east-1:123456789:accesspoint/my-access-point", + expected: "us-east-1", + }, + { + name: "Invalid ARN with missing region", + arn: "arn:aws:s3::123456789:accesspoint/my-access-point", + expected: "", + }, + { + name: "Invalid ARN with too few parts", + arn: "arn:aws:s3", + expected: "", + }, + { + name: "Standard bucket ARN (not an Access Point)", + arn: "arn:aws:s3:::my_corporate_bucket", + expected: "", + }, + { + name: "Malformed ARN with extra colons", + arn: "arn:aws:s3:::us-west-2:123456789:accesspoint/my-access-point", + expected: "", + }, + { + name: "Access Point ARN with additional elements", + arn: "arn:aws:s3:us-east-1:123456789:accesspoint/my-access-point/extra", + expected: "us-east-1", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + region := getRegionFromAccessPointARN(tc.arn) + assert.Equal(t, tc.expected, region) + }) + } +} + func TestGetBucketNameFromARN(t *testing.T) { - bucketName := getBucketNameFromARN("arn:aws:s3:::my_corporate_bucket") - assert.Equal(t, "my_corporate_bucket", bucketName) + testCases := []struct { + name string + bucketARN string + expected string + }{ + { + name: "Standard bucket ARN", + bucketARN: "arn:aws:s3:::my_corporate_bucket", + expected: "my_corporate_bucket", + }, + { + name: "Access Point ARN", + bucketARN: "arn:aws:s3:us-east-1:123456789:accesspoint/my-access-point", + expected: "arn:aws:s3:us-east-1:123456789:accesspoint/my-access-point", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + bucketName := getBucketNameFromARN(tc.bucketARN) + assert.Equal(t, tc.expected, bucketName) + }) + } } func TestGetRegionForBucketARN(t *testing.T) { diff --git a/x-pack/filebeat/input/awss3/interfaces.go b/x-pack/filebeat/input/awss3/interfaces.go index 6a3b119303be..512e95893b40 100644 --- a/x-pack/filebeat/input/awss3/interfaces.go +++ b/x-pack/filebeat/input/awss3/interfaces.go @@ -27,11 +27,10 @@ import ( ) // Run 'go generate' to create mocks that are used in tests. -//go:generate go install github.com/golang/mock/mockgen@v1.6.0 -//go:generate mockgen -source=interfaces.go -destination=mock_interfaces_test.go -package awss3 -mock_names=sqsAPI=MockSQSAPI,sqsProcessor=MockSQSProcessor,s3API=MockS3API,s3Pager=MockS3Pager,s3ObjectHandlerFactory=MockS3ObjectHandlerFactory,s3ObjectHandler=MockS3ObjectHandler -//go:generate mockgen -destination=mock_publisher_test.go -package=awss3 -mock_names=Client=MockBeatClient,Pipeline=MockBeatPipeline github.com/elastic/beats/v7/libbeat/beat Client,Pipeline -//go:generate go-licenser -license Elastic . -//go:generate goimports -w -local github.com/elastic . +//go:generate go run go.uber.org/mock/mockgen -source=interfaces.go -destination=mock_interfaces_test.go -package awss3 -mock_names=sqsAPI=MockSQSAPI,sqsProcessor=MockSQSProcessor,s3API=MockS3API,s3Pager=MockS3Pager,s3ObjectHandlerFactory=MockS3ObjectHandlerFactory,s3ObjectHandler=MockS3ObjectHandler +//go:generate go run go.uber.org/mock/mockgen -destination=mock_publisher_test.go -package=awss3 -mock_names=Client=MockBeatClient,Pipeline=MockBeatPipeline github.com/elastic/beats/v7/libbeat/beat Client,Pipeline +//go:generate go run github.com/elastic/go-licenser -license Elastic . +//go:generate go run golang.org/x/tools/cmd/goimports -w -local github.com/elastic . // ------ // SQS interfaces diff --git a/x-pack/filebeat/input/awss3/metrics.go b/x-pack/filebeat/input/awss3/metrics.go index 3be07437a50e..0ebcaeb1a92c 100644 --- a/x-pack/filebeat/input/awss3/metrics.go +++ b/x-pack/filebeat/input/awss3/metrics.go @@ -36,7 +36,7 @@ func init() { // currentTime returns the current time. This exists to allow unit tests // simulate the passage of time. func currentTime() time.Time { - clock := clockValue.Load().(clock) + clock, _ := clockValue.Load().(clock) return clock.Now() } @@ -206,18 +206,26 @@ func newInputMetrics(id string, optionalParent *monitoring.Registry, maxWorkers return out } -// monitoredReader implements io.Reader and counts the number of bytes read. +// monitoredReader implements io.Reader and wraps byte read tracking fields for S3 bucket objects. +// Following are the tracked metrics, +// - totalBytesReadMetric - a total metric tracking bytes reads throughout the runtime from all processed objects +// - totalBytesReadCurrent - total bytes read from the currently tracked object +// +// See newMonitoredReader for initialization considerations. type monitoredReader struct { - reader io.Reader - totalBytesRead *monitoring.Uint + reader io.Reader + totalBytesReadMetric *monitoring.Uint + totalBytesReadCurrent int64 } +// newMonitoredReader initialize the monitoredReader with a shared monitor that tracks all bytes read. func newMonitoredReader(r io.Reader, metric *monitoring.Uint) *monitoredReader { - return &monitoredReader{reader: r, totalBytesRead: metric} + return &monitoredReader{reader: r, totalBytesReadMetric: metric} } func (m *monitoredReader) Read(p []byte) (int, error) { n, err := m.reader.Read(p) - m.totalBytesRead.Add(uint64(n)) + m.totalBytesReadMetric.Add(uint64(n)) + m.totalBytesReadCurrent += int64(n) return n, err } diff --git a/x-pack/filebeat/input/awss3/metrics_test.go b/x-pack/filebeat/input/awss3/metrics_test.go index e153d321e9f1..33d3b9a513b5 100644 --- a/x-pack/filebeat/input/awss3/metrics_test.go +++ b/x-pack/filebeat/input/awss3/metrics_test.go @@ -5,12 +5,12 @@ package awss3 import ( + "sync/atomic" "testing" "time" "github.com/stretchr/testify/assert" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/elastic-agent-libs/monitoring" ) diff --git a/x-pack/filebeat/input/awss3/mock_interfaces_test.go b/x-pack/filebeat/input/awss3/mock_interfaces_test.go index 086ca34136fd..b611802dbad7 100644 --- a/x-pack/filebeat/input/awss3/mock_interfaces_test.go +++ b/x-pack/filebeat/input/awss3/mock_interfaces_test.go @@ -4,6 +4,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: interfaces.go +// +// Generated by this command: +// +// mockgen -source=interfaces.go -destination=mock_interfaces_test.go -package awss3 -mock_names=sqsAPI=MockSQSAPI,sqsProcessor=MockSQSProcessor,s3API=MockS3API,s3Pager=MockS3Pager,s3ObjectHandlerFactory=MockS3ObjectHandlerFactory,s3ObjectHandler=MockS3ObjectHandler +// // Package awss3 is a generated GoMock package. package awss3 @@ -15,7 +20,7 @@ import ( s3 "github.com/aws/aws-sdk-go-v2/service/s3" types "github.com/aws/aws-sdk-go-v2/service/sqs/types" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" beat "github.com/elastic/beats/v7/libbeat/beat" logp "github.com/elastic/elastic-agent-libs/logp" @@ -25,6 +30,7 @@ import ( type MockSQSAPI struct { ctrl *gomock.Controller recorder *MockSQSAPIMockRecorder + isgomock struct{} } // MockSQSAPIMockRecorder is the mock recorder for MockSQSAPI. @@ -53,7 +59,7 @@ func (m *MockSQSAPI) ChangeMessageVisibility(ctx context.Context, msg *types.Mes } // ChangeMessageVisibility indicates an expected call of ChangeMessageVisibility. -func (mr *MockSQSAPIMockRecorder) ChangeMessageVisibility(ctx, msg, timeout interface{}) *gomock.Call { +func (mr *MockSQSAPIMockRecorder) ChangeMessageVisibility(ctx, msg, timeout any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeMessageVisibility", reflect.TypeOf((*MockSQSAPI)(nil).ChangeMessageVisibility), ctx, msg, timeout) } @@ -67,7 +73,7 @@ func (m *MockSQSAPI) DeleteMessage(ctx context.Context, msg *types.Message) erro } // DeleteMessage indicates an expected call of DeleteMessage. -func (mr *MockSQSAPIMockRecorder) DeleteMessage(ctx, msg interface{}) *gomock.Call { +func (mr *MockSQSAPIMockRecorder) DeleteMessage(ctx, msg any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteMessage", reflect.TypeOf((*MockSQSAPI)(nil).DeleteMessage), ctx, msg) } @@ -82,7 +88,7 @@ func (m *MockSQSAPI) GetQueueAttributes(ctx context.Context, attr []types.QueueA } // GetQueueAttributes indicates an expected call of GetQueueAttributes. -func (mr *MockSQSAPIMockRecorder) GetQueueAttributes(ctx, attr interface{}) *gomock.Call { +func (mr *MockSQSAPIMockRecorder) GetQueueAttributes(ctx, attr any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQueueAttributes", reflect.TypeOf((*MockSQSAPI)(nil).GetQueueAttributes), ctx, attr) } @@ -97,7 +103,7 @@ func (m *MockSQSAPI) ReceiveMessage(ctx context.Context, maxMessages int) ([]typ } // ReceiveMessage indicates an expected call of ReceiveMessage. -func (mr *MockSQSAPIMockRecorder) ReceiveMessage(ctx, maxMessages interface{}) *gomock.Call { +func (mr *MockSQSAPIMockRecorder) ReceiveMessage(ctx, maxMessages any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReceiveMessage", reflect.TypeOf((*MockSQSAPI)(nil).ReceiveMessage), ctx, maxMessages) } @@ -106,6 +112,7 @@ func (mr *MockSQSAPIMockRecorder) ReceiveMessage(ctx, maxMessages interface{}) * type MockSQSProcessor struct { ctrl *gomock.Controller recorder *MockSQSProcessorMockRecorder + isgomock struct{} } // MockSQSProcessorMockRecorder is the mock recorder for MockSQSProcessor. @@ -134,7 +141,7 @@ func (m *MockSQSProcessor) ProcessSQS(ctx context.Context, msg *types.Message, e } // ProcessSQS indicates an expected call of ProcessSQS. -func (mr *MockSQSProcessorMockRecorder) ProcessSQS(ctx, msg, eventCallback interface{}) *gomock.Call { +func (mr *MockSQSProcessorMockRecorder) ProcessSQS(ctx, msg, eventCallback any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProcessSQS", reflect.TypeOf((*MockSQSProcessor)(nil).ProcessSQS), ctx, msg, eventCallback) } @@ -143,6 +150,7 @@ func (mr *MockSQSProcessorMockRecorder) ProcessSQS(ctx, msg, eventCallback inter type MockS3API struct { ctrl *gomock.Controller recorder *MockS3APIMockRecorder + isgomock struct{} } // MockS3APIMockRecorder is the mock recorder for MockS3API. @@ -172,7 +180,7 @@ func (m *MockS3API) CopyObject(ctx context.Context, region, from_bucket, to_buck } // CopyObject indicates an expected call of CopyObject. -func (mr *MockS3APIMockRecorder) CopyObject(ctx, region, from_bucket, to_bucket, from_key, to_key interface{}) *gomock.Call { +func (mr *MockS3APIMockRecorder) CopyObject(ctx, region, from_bucket, to_bucket, from_key, to_key any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CopyObject", reflect.TypeOf((*MockS3API)(nil).CopyObject), ctx, region, from_bucket, to_bucket, from_key, to_key) } @@ -187,7 +195,7 @@ func (m *MockS3API) DeleteObject(ctx context.Context, region, bucket, key string } // DeleteObject indicates an expected call of DeleteObject. -func (mr *MockS3APIMockRecorder) DeleteObject(ctx, region, bucket, key interface{}) *gomock.Call { +func (mr *MockS3APIMockRecorder) DeleteObject(ctx, region, bucket, key any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteObject", reflect.TypeOf((*MockS3API)(nil).DeleteObject), ctx, region, bucket, key) } @@ -202,7 +210,7 @@ func (m *MockS3API) GetObject(ctx context.Context, region, bucket, key string) ( } // GetObject indicates an expected call of GetObject. -func (mr *MockS3APIMockRecorder) GetObject(ctx, region, bucket, key interface{}) *gomock.Call { +func (mr *MockS3APIMockRecorder) GetObject(ctx, region, bucket, key any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetObject", reflect.TypeOf((*MockS3API)(nil).GetObject), ctx, region, bucket, key) } @@ -216,7 +224,7 @@ func (m *MockS3API) ListObjectsPaginator(bucket, prefix string) s3Pager { } // ListObjectsPaginator indicates an expected call of ListObjectsPaginator. -func (mr *MockS3APIMockRecorder) ListObjectsPaginator(bucket, prefix interface{}) *gomock.Call { +func (mr *MockS3APIMockRecorder) ListObjectsPaginator(bucket, prefix any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListObjectsPaginator", reflect.TypeOf((*MockS3API)(nil).ListObjectsPaginator), bucket, prefix) } @@ -225,6 +233,7 @@ func (mr *MockS3APIMockRecorder) ListObjectsPaginator(bucket, prefix interface{} type Mocks3Getter struct { ctrl *gomock.Controller recorder *Mocks3GetterMockRecorder + isgomock struct{} } // Mocks3GetterMockRecorder is the mock recorder for Mocks3Getter. @@ -254,7 +263,7 @@ func (m *Mocks3Getter) GetObject(ctx context.Context, region, bucket, key string } // GetObject indicates an expected call of GetObject. -func (mr *Mocks3GetterMockRecorder) GetObject(ctx, region, bucket, key interface{}) *gomock.Call { +func (mr *Mocks3GetterMockRecorder) GetObject(ctx, region, bucket, key any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetObject", reflect.TypeOf((*Mocks3Getter)(nil).GetObject), ctx, region, bucket, key) } @@ -263,6 +272,7 @@ func (mr *Mocks3GetterMockRecorder) GetObject(ctx, region, bucket, key interface type Mocks3Mover struct { ctrl *gomock.Controller recorder *Mocks3MoverMockRecorder + isgomock struct{} } // Mocks3MoverMockRecorder is the mock recorder for Mocks3Mover. @@ -292,7 +302,7 @@ func (m *Mocks3Mover) CopyObject(ctx context.Context, region, from_bucket, to_bu } // CopyObject indicates an expected call of CopyObject. -func (mr *Mocks3MoverMockRecorder) CopyObject(ctx, region, from_bucket, to_bucket, from_key, to_key interface{}) *gomock.Call { +func (mr *Mocks3MoverMockRecorder) CopyObject(ctx, region, from_bucket, to_bucket, from_key, to_key any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CopyObject", reflect.TypeOf((*Mocks3Mover)(nil).CopyObject), ctx, region, from_bucket, to_bucket, from_key, to_key) } @@ -307,7 +317,7 @@ func (m *Mocks3Mover) DeleteObject(ctx context.Context, region, bucket, key stri } // DeleteObject indicates an expected call of DeleteObject. -func (mr *Mocks3MoverMockRecorder) DeleteObject(ctx, region, bucket, key interface{}) *gomock.Call { +func (mr *Mocks3MoverMockRecorder) DeleteObject(ctx, region, bucket, key any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteObject", reflect.TypeOf((*Mocks3Mover)(nil).DeleteObject), ctx, region, bucket, key) } @@ -316,6 +326,7 @@ func (mr *Mocks3MoverMockRecorder) DeleteObject(ctx, region, bucket, key interfa type Mocks3Lister struct { ctrl *gomock.Controller recorder *Mocks3ListerMockRecorder + isgomock struct{} } // Mocks3ListerMockRecorder is the mock recorder for Mocks3Lister. @@ -344,7 +355,7 @@ func (m *Mocks3Lister) ListObjectsPaginator(bucket, prefix string) s3Pager { } // ListObjectsPaginator indicates an expected call of ListObjectsPaginator. -func (mr *Mocks3ListerMockRecorder) ListObjectsPaginator(bucket, prefix interface{}) *gomock.Call { +func (mr *Mocks3ListerMockRecorder) ListObjectsPaginator(bucket, prefix any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListObjectsPaginator", reflect.TypeOf((*Mocks3Lister)(nil).ListObjectsPaginator), bucket, prefix) } @@ -353,6 +364,7 @@ func (mr *Mocks3ListerMockRecorder) ListObjectsPaginator(bucket, prefix interfac type MockS3Pager struct { ctrl *gomock.Controller recorder *MockS3PagerMockRecorder + isgomock struct{} } // MockS3PagerMockRecorder is the mock recorder for MockS3Pager. @@ -389,7 +401,7 @@ func (mr *MockS3PagerMockRecorder) HasMorePages() *gomock.Call { // NextPage mocks base method. func (m *MockS3Pager) NextPage(ctx context.Context, optFns ...func(*s3.Options)) (*s3.ListObjectsV2Output, error) { m.ctrl.T.Helper() - varargs := []interface{}{ctx} + varargs := []any{ctx} for _, a := range optFns { varargs = append(varargs, a) } @@ -400,9 +412,9 @@ func (m *MockS3Pager) NextPage(ctx context.Context, optFns ...func(*s3.Options)) } // NextPage indicates an expected call of NextPage. -func (mr *MockS3PagerMockRecorder) NextPage(ctx interface{}, optFns ...interface{}) *gomock.Call { +func (mr *MockS3PagerMockRecorder) NextPage(ctx any, optFns ...any) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx}, optFns...) + varargs := append([]any{ctx}, optFns...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NextPage", reflect.TypeOf((*MockS3Pager)(nil).NextPage), varargs...) } @@ -410,6 +422,7 @@ func (mr *MockS3PagerMockRecorder) NextPage(ctx interface{}, optFns ...interface type MockS3ObjectHandlerFactory struct { ctrl *gomock.Controller recorder *MockS3ObjectHandlerFactoryMockRecorder + isgomock struct{} } // MockS3ObjectHandlerFactoryMockRecorder is the mock recorder for MockS3ObjectHandlerFactory. @@ -438,7 +451,7 @@ func (m *MockS3ObjectHandlerFactory) Create(ctx context.Context, obj s3EventV2) } // Create indicates an expected call of Create. -func (mr *MockS3ObjectHandlerFactoryMockRecorder) Create(ctx, obj interface{}) *gomock.Call { +func (mr *MockS3ObjectHandlerFactoryMockRecorder) Create(ctx, obj any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockS3ObjectHandlerFactory)(nil).Create), ctx, obj) } @@ -447,6 +460,7 @@ func (mr *MockS3ObjectHandlerFactoryMockRecorder) Create(ctx, obj interface{}) * type MockS3ObjectHandler struct { ctrl *gomock.Controller recorder *MockS3ObjectHandlerMockRecorder + isgomock struct{} } // MockS3ObjectHandlerMockRecorder is the mock recorder for MockS3ObjectHandler. @@ -489,7 +503,7 @@ func (m *MockS3ObjectHandler) ProcessS3Object(log *logp.Logger, eventCallback fu } // ProcessS3Object indicates an expected call of ProcessS3Object. -func (mr *MockS3ObjectHandlerMockRecorder) ProcessS3Object(log, eventCallback interface{}) *gomock.Call { +func (mr *MockS3ObjectHandlerMockRecorder) ProcessS3Object(log, eventCallback any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProcessS3Object", reflect.TypeOf((*MockS3ObjectHandler)(nil).ProcessS3Object), log, eventCallback) } diff --git a/x-pack/filebeat/input/awss3/mock_publisher_test.go b/x-pack/filebeat/input/awss3/mock_publisher_test.go index efbd5bcef97b..3bffc9142b3f 100644 --- a/x-pack/filebeat/input/awss3/mock_publisher_test.go +++ b/x-pack/filebeat/input/awss3/mock_publisher_test.go @@ -4,6 +4,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/elastic/beats/v7/libbeat/beat (interfaces: Client,Pipeline) +// +// Generated by this command: +// +// mockgen -destination=mock_publisher_test.go -package=awss3 -mock_names=Client=MockBeatClient,Pipeline=MockBeatPipeline github.com/elastic/beats/v7/libbeat/beat Client,Pipeline +// // Package awss3 is a generated GoMock package. package awss3 @@ -11,7 +16,7 @@ package awss3 import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" beat "github.com/elastic/beats/v7/libbeat/beat" ) @@ -20,6 +25,7 @@ import ( type MockBeatClient struct { ctrl *gomock.Controller recorder *MockBeatClientMockRecorder + isgomock struct{} } // MockBeatClientMockRecorder is the mock recorder for MockBeatClient. @@ -60,7 +66,7 @@ func (m *MockBeatClient) Publish(arg0 beat.Event) { } // Publish indicates an expected call of Publish. -func (mr *MockBeatClientMockRecorder) Publish(arg0 interface{}) *gomock.Call { +func (mr *MockBeatClientMockRecorder) Publish(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Publish", reflect.TypeOf((*MockBeatClient)(nil).Publish), arg0) } @@ -72,7 +78,7 @@ func (m *MockBeatClient) PublishAll(arg0 []beat.Event) { } // PublishAll indicates an expected call of PublishAll. -func (mr *MockBeatClientMockRecorder) PublishAll(arg0 interface{}) *gomock.Call { +func (mr *MockBeatClientMockRecorder) PublishAll(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublishAll", reflect.TypeOf((*MockBeatClient)(nil).PublishAll), arg0) } @@ -81,6 +87,7 @@ func (mr *MockBeatClientMockRecorder) PublishAll(arg0 interface{}) *gomock.Call type MockBeatPipeline struct { ctrl *gomock.Controller recorder *MockBeatPipelineMockRecorder + isgomock struct{} } // MockBeatPipelineMockRecorder is the mock recorder for MockBeatPipeline. @@ -125,7 +132,7 @@ func (m *MockBeatPipeline) ConnectWith(arg0 beat.ClientConfig) (beat.Client, err } // ConnectWith indicates an expected call of ConnectWith. -func (mr *MockBeatPipelineMockRecorder) ConnectWith(arg0 interface{}) *gomock.Call { +func (mr *MockBeatPipelineMockRecorder) ConnectWith(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConnectWith", reflect.TypeOf((*MockBeatPipeline)(nil).ConnectWith), arg0) } diff --git a/x-pack/filebeat/input/awss3/s3.go b/x-pack/filebeat/input/awss3/s3.go index fabc1b2f1dd0..1fe4584b7db7 100644 --- a/x-pack/filebeat/input/awss3/s3.go +++ b/x-pack/filebeat/input/awss3/s3.go @@ -43,6 +43,12 @@ func createPipelineClient(pipeline beat.Pipeline, acks *awsACKHandler) (beat.Cli } func getRegionForBucket(ctx context.Context, s3Client *s3.Client, bucketName string) (string, error) { + // Skip region fetching if it's an Access Point ARN + if isValidAccessPointARN(bucketName) { + // Extract the region from the ARN (e.g., arn:aws:s3:us-west-2:123456789012:accesspoint/my-access-point) + return getRegionFromAccessPointARN(bucketName), nil + } + getBucketLocationOutput, err := s3Client.GetBucketLocation(ctx, &s3.GetBucketLocationInput{ Bucket: awssdk.String(bucketName), }) @@ -59,7 +65,19 @@ func getRegionForBucket(ctx context.Context, s3Client *s3.Client, bucketName str return string(getBucketLocationOutput.LocationConstraint), nil } +// Helper function to extract region from Access Point ARN +func getRegionFromAccessPointARN(arn string) string { + arnParts := strings.Split(arn, ":") + if len(arnParts) > 3 { + return arnParts[3] // The fourth part of ARN is region + } + return "" +} + func getBucketNameFromARN(bucketARN string) string { + if isValidAccessPointARN(bucketARN) { + return bucketARN // Return full ARN for Access Points + } bucketMetadata := strings.Split(bucketARN, ":") bucketName := bucketMetadata[len(bucketMetadata)-1] return bucketName diff --git a/x-pack/filebeat/input/awss3/s3_input.go b/x-pack/filebeat/input/awss3/s3_input.go index 6775a1be0336..88f28e39e83e 100644 --- a/x-pack/filebeat/input/awss3/s3_input.go +++ b/x-pack/filebeat/input/awss3/s3_input.go @@ -66,7 +66,7 @@ func (in *s3PollerInput) Run( var err error // Load the persistent S3 polling state. - in.states, err = newStates(in.log, in.store) + in.states, err = newStates(in.log, in.store, in.config.BucketListPrefix) if err != nil { return fmt.Errorf("can not start persistent store: %w", err) } @@ -115,8 +115,19 @@ func (in *s3PollerInput) runPoll(ctx context.Context) { } // Start reading data and wait for its processing to be done - in.readerLoop(ctx, workChan) + ids, ok := in.readerLoop(ctx, workChan) workerWg.Wait() + + if !ok { + in.log.Warn("skipping state registry cleanup as object reading ended with a non-ok return") + return + } + + // Perform state cleanup operation + err := in.states.CleanUp(ids) + if err != nil { + in.log.Errorf("failed to cleanup states: %v", err.Error()) + } } func (in *s3PollerInput) workerLoop(ctx context.Context, workChan <-chan state) { @@ -183,7 +194,10 @@ func (in *s3PollerInput) workerLoop(ctx context.Context, workChan <-chan state) } } -func (in *s3PollerInput) readerLoop(ctx context.Context, workChan chan<- state) { +// readerLoop performs the S3 object listing and emit state to work listeners if object needs to be processed. +// Returns all tracked state IDs correlates to all tracked S3 objects iff listing is successful. +// These IDs are intended to be used for state clean-up. +func (in *s3PollerInput) readerLoop(ctx context.Context, workChan chan<- state) (knownStateIDSlice []string, ok bool) { defer close(workChan) bucketName := getBucketNameFromARN(in.config.getBucketARN()) @@ -202,7 +216,7 @@ func (in *s3PollerInput) readerLoop(ctx context.Context, workChan chan<- state) circuitBreaker++ if circuitBreaker >= readerLoopMaxCircuitBreaker { in.log.Warnw(fmt.Sprintf("%d consecutive error when paginating listing, breaking the circuit.", circuitBreaker), "error", err) - break + return nil, false } } // add a backoff delay and try again @@ -219,6 +233,8 @@ func (in *s3PollerInput) readerLoop(ctx context.Context, workChan chan<- state) in.metrics.s3ObjectsListedTotal.Add(uint64(totListedObjects)) for _, object := range page.Contents { state := newState(bucketName, *object.Key, *object.ETag, *object.LastModified) + knownStateIDSlice = append(knownStateIDSlice, state.ID()) + if in.states.IsProcessed(state) { in.log.Debugw("skipping state.", "state", state) continue @@ -229,6 +245,8 @@ func (in *s3PollerInput) readerLoop(ctx context.Context, workChan chan<- state) in.metrics.s3ObjectsProcessedTotal.Inc() } } + + return knownStateIDSlice, true } func (in *s3PollerInput) s3EventForState(state state) s3EventV2 { diff --git a/x-pack/filebeat/input/awss3/s3_objects.go b/x-pack/filebeat/input/awss3/s3_objects.go index 93219d9a6408..acd4d173439d 100644 --- a/x-pack/filebeat/input/awss3/s3_objects.go +++ b/x-pack/filebeat/input/awss3/s3_objects.go @@ -51,7 +51,6 @@ type s3ObjectProcessor struct { type s3DownloadedObject struct { body io.ReadCloser - length int64 contentType string metadata map[string]interface{} } @@ -142,9 +141,9 @@ func (p *s3ObjectProcessor) ProcessS3Object(log *logp.Logger, eventCallback func defer s3Obj.body.Close() p.s3Metadata = s3Obj.metadata - p.metrics.s3ObjectSizeInBytes.Update(s3Obj.length) - reader, err := p.addGzipDecoderIfNeeded(newMonitoredReader(s3Obj.body, p.metrics.s3BytesProcessedTotal)) + mReader := newMonitoredReader(s3Obj.body, p.metrics.s3BytesProcessedTotal) + reader, err := p.addGzipDecoderIfNeeded(mReader) if err != nil { return fmt.Errorf("failed checking for gzip content: %w", err) } @@ -213,6 +212,9 @@ func (p *s3ObjectProcessor) ProcessS3Object(log *logp.Logger, eventCallback func time.Since(start).Nanoseconds(), err) } + // finally obtain total bytes of the object through metered reader + p.metrics.s3ObjectSizeInBytes.Update(mReader.totalBytesReadCurrent) + return nil } @@ -241,7 +243,6 @@ func (p *s3ObjectProcessor) download() (obj *s3DownloadedObject, err error) { s := &s3DownloadedObject{ body: getObjectOutput.Body, - length: *getObjectOutput.ContentLength, contentType: ctType, metadata: meta, } diff --git a/x-pack/filebeat/input/awss3/s3_objects_test.go b/x-pack/filebeat/input/awss3/s3_objects_test.go index d20d81ced6c8..e6178c33a87f 100644 --- a/x-pack/filebeat/input/awss3/s3_objects_test.go +++ b/x-pack/filebeat/input/awss3/s3_objects_test.go @@ -17,9 +17,9 @@ import ( awssdk "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go-v2/service/s3/types" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" "github.com/elastic/beats/v7/libbeat/beat" conf "github.com/elastic/elastic-agent-libs/config" @@ -289,6 +289,76 @@ func TestS3ObjectProcessor(t *testing.T) { }) } +func TestProcessObjectMetricCollection(t *testing.T) { + logger := logp.NewLogger("testing-s3-processor-metrics") + + tests := []struct { + name string + filename string + contentType string + objectSize int64 + }{ + { + name: "simple text - octet-stream", + filename: "testdata/log.txt", + contentType: "application/octet-stream", + objectSize: 18, + }, + { + name: "json text", + filename: "testdata/log.json", + contentType: "application/json", + objectSize: 199, + }, + { + name: "gzip with json text", + filename: "testdata/multiline.json.gz", + contentType: "application/x-gzip", + objectSize: 175, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + // given + ctx, cancel := context.WithTimeout(context.Background(), testTimeout) + defer cancel() + + ctrl, ctx := gomock.WithContext(ctx, t) + defer ctrl.Finish() + + s3Event, s3Resp := newS3Object(t, test.filename, test.contentType) + mockS3API := NewMockS3API(ctrl) + gomock.InOrder( + mockS3API.EXPECT(). + GetObject(gomock.Any(), gomock.Eq("us-east-1"), gomock.Eq(s3Event.S3.Bucket.Name), gomock.Eq(s3Event.S3.Object.Key)). + Return(s3Resp, nil), + ) + + // metric recorder with zero workers + metricRecorder := newInputMetrics(test.name, nil, 0) + objFactory := newS3ObjectProcessorFactory(metricRecorder, mockS3API, nil, backupConfig{}) + objHandler := objFactory.Create(ctx, s3Event) + + // when + err := objHandler.ProcessS3Object(logger, func(_ beat.Event) {}) + + // then + require.NoError(t, err) + + require.Equal(t, uint64(1), metricRecorder.s3ObjectsRequestedTotal.Get()) + require.Equal(t, uint64(0), metricRecorder.s3ObjectsInflight.Get()) + + values := metricRecorder.s3ObjectSizeInBytes.Values() + require.Equal(t, 1, len(values)) + + // since we processed a single object, total and current process size is same + require.Equal(t, test.objectSize, values[0]) + require.Equal(t, uint64(test.objectSize), metricRecorder.s3BytesProcessedTotal.Get()) + }) + } +} + func testProcessS3Object(t testing.TB, file, contentType string, numEvents int, selectors ...fileSelectorConfig) []beat.Event { return _testProcessS3Object(t, file, contentType, numEvents, false, selectors) } diff --git a/x-pack/filebeat/input/awss3/s3_test.go b/x-pack/filebeat/input/awss3/s3_test.go index b0b19d828318..2f79cb44a48c 100644 --- a/x-pack/filebeat/input/awss3/s3_test.go +++ b/x-pack/filebeat/input/awss3/s3_test.go @@ -12,8 +12,8 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go-v2/service/s3/types" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" "github.com/elastic/elastic-agent-libs/logp" ) @@ -22,6 +22,7 @@ func TestS3Poller(t *testing.T) { logp.TestingSetup() const bucket = "bucket" + const listPrefix = "key" const numberOfWorkers = 5 const pollInterval = 2 * time.Second const testTimeout = 1 * time.Second @@ -127,7 +128,7 @@ func TestS3Poller(t *testing.T) { Return(nil, errFakeConnectivityFailure) s3ObjProc := newS3ObjectProcessorFactory(nil, mockAPI, nil, backupConfig{}) - states, err := newStates(nil, store) + states, err := newStates(nil, store, listPrefix) require.NoError(t, err, "states creation must succeed") poller := &s3PollerInput{ log: logp.NewLogger(inputName), @@ -135,7 +136,7 @@ func TestS3Poller(t *testing.T) { NumberOfWorkers: numberOfWorkers, BucketListInterval: pollInterval, BucketARN: bucket, - BucketListPrefix: "key", + BucketListPrefix: listPrefix, RegionName: "region", }, s3: mockAPI, @@ -265,7 +266,7 @@ func TestS3Poller(t *testing.T) { Return(nil, errFakeConnectivityFailure) s3ObjProc := newS3ObjectProcessorFactory(nil, mockS3, nil, backupConfig{}) - states, err := newStates(nil, store) + states, err := newStates(nil, store, listPrefix) require.NoError(t, err, "states creation must succeed") poller := &s3PollerInput{ log: logp.NewLogger(inputName), @@ -273,7 +274,7 @@ func TestS3Poller(t *testing.T) { NumberOfWorkers: numberOfWorkers, BucketListInterval: pollInterval, BucketARN: bucket, - BucketListPrefix: "key", + BucketListPrefix: listPrefix, RegionName: "region", }, s3: mockS3, diff --git a/x-pack/filebeat/input/awss3/sqs_s3_event_test.go b/x-pack/filebeat/input/awss3/sqs_s3_event_test.go index c7962bb2f0f3..ae4400dc0f27 100644 --- a/x-pack/filebeat/input/awss3/sqs_s3_event_test.go +++ b/x-pack/filebeat/input/awss3/sqs_s3_event_test.go @@ -16,9 +16,9 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/sqs/types" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/elastic-agent-libs/logp" diff --git a/x-pack/filebeat/input/awss3/sqs_test.go b/x-pack/filebeat/input/awss3/sqs_test.go index 8bc25397eaeb..34575a47daff 100644 --- a/x-pack/filebeat/input/awss3/sqs_test.go +++ b/x-pack/filebeat/input/awss3/sqs_test.go @@ -15,9 +15,9 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/sqs/types" "github.com/gofrs/uuid/v5" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/elastic-agent-libs/logp" diff --git a/x-pack/filebeat/input/awss3/states.go b/x-pack/filebeat/input/awss3/states.go index cb40abbd41f0..2bfb9f29cd8b 100644 --- a/x-pack/filebeat/input/awss3/states.go +++ b/x-pack/filebeat/input/awss3/states.go @@ -21,30 +21,34 @@ const awsS3ObjectStatePrefix = "filebeat::aws-s3::state::" type states struct { // Completed S3 object states, indexed by state ID. // statesLock must be held to access states. - states map[string]state + states map[string]*state statesLock sync.Mutex // The store used to persist state changes to the registry. // storeLock must be held to access store. store *statestore.Store storeLock sync.Mutex + + // Accepted prefixes of state keys of this registry + keyPrefix string } // newStates generates a new states registry. -func newStates(log *logp.Logger, stateStore beater.StateStore) (*states, error) { +func newStates(log *logp.Logger, stateStore beater.StateStore, listPrefix string) (*states, error) { store, err := stateStore.Access() if err != nil { return nil, fmt.Errorf("can't access persistent store: %w", err) } - stateTable, err := loadS3StatesFromRegistry(log, store) + stateTable, err := loadS3StatesFromRegistry(log, store, listPrefix) if err != nil { return nil, fmt.Errorf("loading S3 input state: %w", err) } return &states{ - store: store, - states: stateTable, + store: store, + states: stateTable, + keyPrefix: listPrefix, }, nil } @@ -57,30 +61,70 @@ func (s *states) IsProcessed(state state) bool { } func (s *states) AddState(state state) error { + if !strings.HasPrefix(state.Key, s.keyPrefix) { + // Note - This failure should not happen since we create a dedicated state instance per input. + // Yet, this is here to avoid any wiring errors within the component. + return fmt.Errorf("expected prefix %s in key %s, skipping state registering", s.keyPrefix, state.Key) + } + id := state.ID() // Update in-memory copy s.statesLock.Lock() - s.states[id] = state + s.states[id] = &state s.statesLock.Unlock() // Persist to the registry s.storeLock.Lock() defer s.storeLock.Unlock() - key := awsS3ObjectStatePrefix + id - if err := s.store.Set(key, state); err != nil { + if err := s.store.Set(getStoreKey(id), state); err != nil { return err } return nil } +// CleanUp performs state and store cleanup based on provided knownIDs. +// knownIDs must contain valid currently tracked state IDs that must be known by this state registry. +// State and underlying storage will be cleaned if ID is no longer present in knownIDs set. +func (s *states) CleanUp(knownIDs []string) error { + knownIDHashSet := map[string]struct{}{} + for _, id := range knownIDs { + knownIDHashSet[id] = struct{}{} + } + + s.storeLock.Lock() + defer s.storeLock.Unlock() + s.statesLock.Lock() + defer s.statesLock.Unlock() + + for id := range s.states { + if _, contains := knownIDHashSet[id]; !contains { + // remove from sate & store as ID is no longer seen in known ID set + delete(s.states, id) + err := s.store.Remove(getStoreKey(id)) + if err != nil { + return fmt.Errorf("error while removing the state for ID %s: %w", id, err) + } + } + } + + return nil +} + func (s *states) Close() { s.storeLock.Lock() s.store.Close() s.storeLock.Unlock() } -func loadS3StatesFromRegistry(log *logp.Logger, store *statestore.Store) (map[string]state, error) { - stateTable := map[string]state{} +// getStoreKey is a helper to generate the key used by underlying persistent storage +func getStoreKey(stateID string) string { + return awsS3ObjectStatePrefix + stateID +} + +// loadS3StatesFromRegistry loads a copy of the registry states. +// If prefix is set, entries will match the provided prefix(including empty prefix) +func loadS3StatesFromRegistry(log *logp.Logger, store *statestore.Store, prefix string) (map[string]*state, error) { + stateTable := map[string]*state{} err := store.Each(func(key string, dec statestore.ValueDecoder) (bool, error) { if !strings.HasPrefix(key, awsS3ObjectStatePrefix) { return true, nil @@ -103,7 +147,10 @@ func loadS3StatesFromRegistry(log *logp.Logger, store *statestore.Store) (map[st return true, nil } - stateTable[st.ID()] = st + // filter based on prefix and add entry to local copy + if strings.HasPrefix(st.Key, prefix) { + stateTable[st.ID()] = &st + } return true, nil }) if err != nil { diff --git a/x-pack/filebeat/input/awss3/states_test.go b/x-pack/filebeat/input/awss3/states_test.go index dc345d5f88e8..fa604ed08d96 100644 --- a/x-pack/filebeat/input/awss3/states_test.go +++ b/x-pack/filebeat/input/awss3/states_test.go @@ -5,12 +5,14 @@ package awss3 import ( + "fmt" "testing" "time" "github.com/elastic/beats/v7/filebeat/beater" "github.com/elastic/beats/v7/libbeat/statestore" "github.com/elastic/beats/v7/libbeat/statestore/storetest" + "github.com/elastic/elastic-agent-libs/logp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -41,7 +43,7 @@ func (s *testInputStore) CleanupInterval() time.Duration { func TestStatesAddStateAndIsProcessed(t *testing.T) { type stateTestCase struct { // An initialization callback to invoke on the (initially empty) states. - statesEdit func(states *states) + statesEdit func(states *states) error // The state to call IsProcessed on and the expected result state state @@ -61,42 +63,42 @@ func TestStatesAddStateAndIsProcessed(t *testing.T) { expectedIsProcessed: false, }, "not existing state": { - statesEdit: func(states *states) { - states.AddState(testState2) + statesEdit: func(states *states) error { + return states.AddState(testState2) }, state: testState1, expectedIsProcessed: false, }, "existing state": { - statesEdit: func(states *states) { - states.AddState(testState1) + statesEdit: func(states *states) error { + return states.AddState(testState1) }, state: testState1, expectedIsProcessed: true, }, "existing stored state is persisted": { - statesEdit: func(states *states) { + statesEdit: func(states *states) error { state := testState1 state.Stored = true - states.AddState(state) + return states.AddState(state) }, state: testState1, shouldReload: true, expectedIsProcessed: true, }, "existing failed state is persisted": { - statesEdit: func(states *states) { + statesEdit: func(states *states) error { state := testState1 state.Failed = true - states.AddState(state) + return states.AddState(state) }, state: testState1, shouldReload: true, expectedIsProcessed: true, }, "existing unprocessed state is not persisted": { - statesEdit: func(states *states) { - states.AddState(testState1) + statesEdit: func(states *states) error { + return states.AddState(testState1) }, state: testState1, shouldReload: true, @@ -108,13 +110,14 @@ func TestStatesAddStateAndIsProcessed(t *testing.T) { test := test t.Run(name, func(t *testing.T) { store := openTestStatestore() - states, err := newStates(nil, store) + states, err := newStates(nil, store, "") require.NoError(t, err, "states creation must succeed") if test.statesEdit != nil { - test.statesEdit(states) + err = test.statesEdit(states) + require.NoError(t, err, "states edit must succeed") } if test.shouldReload { - states, err = newStates(nil, store) + states, err = newStates(nil, store, "") require.NoError(t, err, "states creation must succeed") } @@ -123,3 +126,147 @@ func TestStatesAddStateAndIsProcessed(t *testing.T) { }) } } + +func TestStatesCleanUp(t *testing.T) { + bucketName := "test-bucket" + lModifiedTime := time.Unix(0, 0) + stateA := newState(bucketName, "a", "a-etag", lModifiedTime) + stateB := newState(bucketName, "b", "b-etag", lModifiedTime) + stateC := newState(bucketName, "c", "c-etag", lModifiedTime) + + tests := []struct { + name string + initStates []state + knownIDs []string + expectIDs []string + }{ + { + name: "No cleanup if not missing from known list", + initStates: []state{stateA, stateB, stateC}, + knownIDs: []string{stateA.ID(), stateB.ID(), stateC.ID()}, + expectIDs: []string{stateA.ID(), stateB.ID(), stateC.ID()}, + }, + { + name: "Clean up if missing from known list", + initStates: []state{stateA, stateB, stateC}, + knownIDs: []string{stateA.ID()}, + expectIDs: []string{stateA.ID()}, + }, + { + name: "Clean up everything", + initStates: []state{stateA, stateC}, // given A, C + knownIDs: []string{stateB.ID()}, // but known B + expectIDs: []string{}, // empty state & store + }, + { + name: "Empty known IDs are valid", + initStates: []state{stateA}, // given A + knownIDs: []string{}, // Known nothing + expectIDs: []string{}, // empty state & store + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + store := openTestStatestore() + statesInstance, err := newStates(nil, store, "") + require.NoError(t, err, "states creation must succeed") + + for _, s := range test.initStates { + err := statesInstance.AddState(s) + require.NoError(t, err, "state initialization must succeed") + } + + // perform cleanup + err = statesInstance.CleanUp(test.knownIDs) + require.NoError(t, err, "state cleanup must succeed") + + // validate + for _, id := range test.expectIDs { + // must be in local state + _, ok := statesInstance.states[id] + require.True(t, ok, fmt.Errorf("expected id %s in state, but got missing", id)) + + // must be in store + ok, err := statesInstance.store.Has(getStoreKey(id)) + require.NoError(t, err, "state has must succeed") + require.True(t, ok, fmt.Errorf("expected id %s in store, but got missing", id)) + } + }) + } + +} + +func TestStatesPrefixHandling(t *testing.T) { + logger := logp.NewLogger("state-prefix-testing") + + t.Run("if prefix was set, accept only states with prefix", func(t *testing.T) { + // given + registry := openTestStatestore() + + // when - registry with prefix + st, err := newStates(logger, registry, "staging-") + require.NoError(t, err) + + // then - fail for non prefixed + err = st.AddState(newState("bucket", "production-logA", "etag", time.Now())) + require.Error(t, err) + + // then - pass for correctly prefixed + err = st.AddState(newState("bucket", "staging-logA", "etag", time.Now())) + require.NoError(t, err) + }) + + t.Run("states store only load entries matching the given prefix", func(t *testing.T) { + // given + registry := openTestStatestore() + + sA := newState("bucket", "A", "etag", time.Unix(1733221244, 0)) + sA.Stored = true + sStagingA := newState("bucket", "staging-A", "etag", time.Unix(1733224844, 0)) + sStagingA.Stored = true + sProdB := newState("bucket", "production/B", "etag", time.Unix(1733228444, 0)) + sProdB.Stored = true + sSpace := newState("bucket", " B", "etag", time.Unix(1733230444, 0)) + sSpace.Stored = true + + // add various states first with no prefix + st, err := newStates(logger, registry, "") + require.NoError(t, err) + + _ = st.AddState(sA) + _ = st.AddState(sStagingA) + _ = st.AddState(sProdB) + _ = st.AddState(sSpace) + + // Reload states and validate + + // when - no prefix reload + stNoPrefix, err := newStates(logger, registry, "") + require.NoError(t, err) + + require.True(t, stNoPrefix.IsProcessed(sA)) + require.True(t, stNoPrefix.IsProcessed(sStagingA)) + require.True(t, stNoPrefix.IsProcessed(sProdB)) + require.True(t, stNoPrefix.IsProcessed(sSpace)) + + // when - with prefix `staging-` + st, err = newStates(logger, registry, "staging-") + require.NoError(t, err) + + require.False(t, st.IsProcessed(sA)) + require.True(t, st.IsProcessed(sStagingA)) + require.False(t, st.IsProcessed(sProdB)) + require.False(t, st.IsProcessed(sSpace)) + + // when - with prefix `production/` + st, err = newStates(logger, registry, "production/") + require.NoError(t, err) + + require.False(t, st.IsProcessed(sA)) + require.False(t, st.IsProcessed(sStagingA)) + require.True(t, st.IsProcessed(sProdB)) + require.False(t, st.IsProcessed(sSpace)) + }) + +} diff --git a/x-pack/filebeat/input/azureeventhub/tracer.go b/x-pack/filebeat/input/azureeventhub/tracer.go index f998a548e373..8ba77af3b4d3 100644 --- a/x-pack/filebeat/input/azureeventhub/tracer.go +++ b/x-pack/filebeat/input/azureeventhub/tracer.go @@ -8,6 +8,7 @@ package azureeventhub import ( "context" + "os" "github.com/devigned/tab" @@ -15,7 +16,12 @@ import ( ) func init() { - tab.Register(new(logsOnlyTracer)) + // Register the logs tracer only if the environment variable is + // set to avoid the overhead of the tracer in environments where + // it's not needed. + if os.Getenv("BEATS_AZURE_EVENTHUB_INPUT_TRACING_ENABLED") == "true" { + tab.Register(new(logsOnlyTracer)) + } } // logsOnlyTracer manages the creation of the required diff --git a/x-pack/filebeat/input/benchmark/input.go b/x-pack/filebeat/input/benchmark/input.go index dd6d198cc409..e098d3e746bc 100644 --- a/x-pack/filebeat/input/benchmark/input.go +++ b/x-pack/filebeat/input/benchmark/input.go @@ -60,7 +60,7 @@ func (bi *benchmarkInput) Test(ctx v2.TestContext) error { // Run starts the data generation. func (bi *benchmarkInput) Run(ctx v2.Context, publisher stateless.Publisher) error { var wg sync.WaitGroup - metrics := newInputMetrics(ctx.ID) + metrics := newInputMetrics(ctx) for i := uint8(0); i < bi.cfg.Threads; i++ { wg.Add(1) @@ -103,8 +103,8 @@ func runThread(ctx v2.Context, publisher stateless.Publisher, thread uint8, cfg ticker.Stop() return case <-ticker.C: - //don't want to block on filling doPublish channel - //so only send as many as it can hold right now + // don't want to block on filling doPublish channel + // so only send as many as it can hold right now numToSend := cap(pubChan) - len(pubChan) for i := 0; i < numToSend; i++ { pubChan <- true @@ -157,8 +157,8 @@ type inputMetrics struct { } // newInputMetrics returns an input metric for the benchmark processor. -func newInputMetrics(id string) *inputMetrics { - reg, unreg := inputmon.NewInputRegistry(inputName, id, nil) +func newInputMetrics(ctx v2.Context) *inputMetrics { + reg, unreg := inputmon.NewInputRegistry(inputName, ctx.ID, ctx.Agent.Monitoring.Namespace.GetRegistry()) out := &inputMetrics{ unregister: unreg, eventsPublished: monitoring.NewUint(reg, "events_published_total"), diff --git a/x-pack/filebeat/input/cel/config.go b/x-pack/filebeat/input/cel/config.go index b04b78457198..1906a309bdb9 100644 --- a/x-pack/filebeat/input/cel/config.go +++ b/x-pack/filebeat/input/cel/config.go @@ -58,6 +58,13 @@ type config struct { // Resource is the configuration for establishing an // HTTP request or for locating a local resource. Resource *ResourceConfig `config:"resource" validate:"required"` + + // FailureDump configures failure dump behaviour. + FailureDump *dumpConfig `config:"failure_dump"` + + // RecordCoverage indicates whether a program should + // record and log execution coverage. + RecordCoverage bool `config:"record_coverage"` } type redact struct { @@ -69,10 +76,27 @@ type redact struct { Delete bool `config:"delete"` } +// dumpConfig configures the CEL program to retain +// the full evaluation state using the cel.OptTrackState +// option. The state is written to a file in the path if +// the evaluation fails. +type dumpConfig struct { + Enabled *bool `config:"enabled"` + Filename string `config:"filename"` +} + +func (t *dumpConfig) enabled() bool { + return t != nil && (t.Enabled == nil || *t.Enabled) +} + func (c config) Validate() error { + if c.RecordCoverage { + logp.L().Named("input.cel").Warn("execution coverage enabled: " + + "see documentation for details: https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-input-cel.html#cel-record-coverage") + } if c.Redact == nil { logp.L().Named("input.cel").Warn("missing recommended 'redact' configuration: " + - "see documentation for details: https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-input-cel.html#_redact") + "see documentation for details: https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-input-cel.html#cel-state-redact") } if c.Interval <= 0 { return errors.New("interval must be greater than 0") @@ -89,7 +113,8 @@ func (c config) Validate() error { if len(c.Regexps) != 0 { patterns = map[string]*regexp.Regexp{".": nil} } - _, _, err = newProgram(context.Background(), c.Program, root, nil, &http.Client{}, nil, nil, patterns, c.XSDs, logp.L().Named("input.cel"), nil) + wantDump := c.FailureDump.enabled() && c.FailureDump.Filename != "" + _, _, _, err = newProgram(context.Background(), c.Program, root, nil, &http.Client{}, nil, nil, patterns, c.XSDs, logp.L().Named("input.cel"), nil, wantDump, false) if err != nil { return fmt.Errorf("failed to check program: %w", err) } diff --git a/x-pack/filebeat/input/cel/input.go b/x-pack/filebeat/input/cel/input.go index e9b30a980e3d..4a04836bf596 100644 --- a/x-pack/filebeat/input/cel/input.go +++ b/x-pack/filebeat/input/cel/input.go @@ -10,6 +10,7 @@ package cel import ( "compress/gzip" "context" + "encoding/json" "errors" "fmt" "io" @@ -166,7 +167,9 @@ func (i input) run(env v2.Context, src *source, cursor map[string]interface{}, p Password: cfg.Auth.Basic.Password, } } - prg, ast, err := newProgram(ctx, cfg.Program, root, getEnv(cfg.AllowedEnvironment), client, limiter, auth, patterns, cfg.XSDs, log, trace) + wantDump := cfg.FailureDump.enabled() && cfg.FailureDump.Filename != "" + doCov := cfg.RecordCoverage && log.IsDebug() + prg, ast, cov, err := newProgram(ctx, cfg.Program, root, getEnv(cfg.AllowedEnvironment), client, limiter, auth, patterns, cfg.XSDs, log, trace, wantDump, doCov) if err != nil { return err } @@ -226,6 +229,14 @@ func (i input) run(env v2.Context, src *source, cursor map[string]interface{}, p ) // Keep track of whether CEL is degraded for this periodic run. var isDegraded bool + if doCov { + defer func() { + // If doCov is true, log the updated coverage details. + // Updates are a running aggregate for each call to run + // as cov is shared via the program compilation. + log.Debugw("coverage", "details", cov.Details()) + }() + } for { if wait := time.Until(waitUntil); wait > 0 { // We have a special-case wait for when we have a zero limit. @@ -251,12 +262,25 @@ func (i input) run(env v2.Context, src *source, cursor map[string]interface{}, p log.Debugw("request state", logp.Namespace("cel"), "state", redactor{state: state, cfg: cfg.Redact}) metrics.executions.Add(1) start := i.now().In(time.UTC) - state, err = evalWith(ctx, prg, ast, state, start) + state, err = evalWith(ctx, prg, ast, state, start, wantDump) log.Debugw("response state", logp.Namespace("cel"), "state", redactor{state: state, cfg: cfg.Redact}) if err != nil { + var dump dumpError switch { case errors.Is(err, context.Canceled), errors.Is(err, context.DeadlineExceeded): return err + case errors.As(err, &dump): + path := strings.ReplaceAll(cfg.FailureDump.Filename, "*", sanitizeFileName(env.IDWithoutName)) + dir := filepath.Dir(path) + base := filepath.Base(path) + ext := filepath.Ext(base) + prefix := strings.TrimSuffix(base, ext) + path = filepath.Join(dir, prefix+"-"+i.now().In(time.UTC).Format("2006-01-02T15-04-05.000")+ext) + log.Debugw("writing failure dump file", "path", path) + err := dump.writeToFile(path) + if err != nil { + log.Errorw("failed to write failure dump", "path", path, "error", err) + } } log.Errorw("failed evaluation", "error", err) env.UpdateStatus(status.Degraded, "failed evaluation: "+err.Error()) @@ -785,6 +809,26 @@ func newClient(ctx context.Context, cfg config, log *logp.Logger, reg *monitorin } } } + if !cfg.FailureDump.enabled() && cfg.FailureDump != nil && cfg.FailureDump.Filename != "" { + // We have a fail-dump name, but we are not enabled, + // so remove all dumps we own. + err = os.Remove(cfg.FailureDump.Filename) + if err != nil && !errors.Is(err, fs.ErrNotExist) { + log.Errorw("failed to remove request trace log", "path", cfg.FailureDump.Filename, "error", err) + } + ext := filepath.Ext(cfg.FailureDump.Filename) + base := strings.TrimSuffix(cfg.FailureDump.Filename, ext) + paths, err := filepath.Glob(base + "-" + lumberjackTimestamp + ext) + if err != nil { + log.Errorw("failed to collect request trace log path names", "error", err) + } + for _, p := range paths { + err = os.Remove(p) + if err != nil && !errors.Is(err, fs.ErrNotExist) { + log.Errorw("failed to remove request trace log", "path", p, "error", err) + } + } + } if reg != nil { c.Transport = httpmon.NewMetricsRoundTripper(c.Transport, reg) @@ -1004,10 +1048,10 @@ func getEnv(allowed []string) map[string]string { return env } -func newProgram(ctx context.Context, src, root string, vars map[string]string, client *http.Client, limiter *rate.Limiter, auth *lib.BasicAuth, patterns map[string]*regexp.Regexp, xsd map[string]string, log *logp.Logger, trace *httplog.LoggingRoundTripper) (cel.Program, *cel.Ast, error) { +func newProgram(ctx context.Context, src, root string, vars map[string]string, client *http.Client, limiter *rate.Limiter, auth *lib.BasicAuth, patterns map[string]*regexp.Regexp, xsd map[string]string, log *logp.Logger, trace *httplog.LoggingRoundTripper, details, coverage bool) (cel.Program, *cel.Ast, *lib.Coverage, error) { xml, err := lib.XML(nil, xsd) if err != nil { - return nil, nil, fmt.Errorf("failed to build xml type hints: %w", err) + return nil, nil, nil, fmt.Errorf("failed to build xml type hints: %w", err) } opts := []cel.EnvOption{ cel.Declarations(decls.NewVar(root, decls.Dyn)), @@ -1016,6 +1060,7 @@ func newProgram(ctx context.Context, src, root string, vars map[string]string, c lib.Crypto(), lib.JSON(nil), xml, + lib.Printf(), lib.Strings(), lib.Time(), lib.Try(), @@ -1034,19 +1079,30 @@ func newProgram(ctx context.Context, src, root string, vars map[string]string, c } env, err := cel.NewEnv(opts...) if err != nil { - return nil, nil, fmt.Errorf("failed to create env: %w", err) + return nil, nil, nil, fmt.Errorf("failed to create env: %w", err) } ast, iss := env.Compile(src) if iss.Err() != nil { - return nil, nil, fmt.Errorf("failed compilation: %w", iss.Err()) + return nil, nil, nil, fmt.Errorf("failed compilation: %w", iss.Err()) } - prg, err := env.Program(ast) + var ( + progOpts []cel.ProgramOption + cov *lib.Coverage + ) + if coverage { + cov = lib.NewCoverage(ast) + progOpts = []cel.ProgramOption{cov.ProgramOption()} + } + if details { + progOpts = []cel.ProgramOption{cel.EvalOptions(cel.OptTrackState)} + } + prg, err := env.Program(ast, progOpts...) if err != nil { - return nil, nil, fmt.Errorf("failed program instantiation: %w", err) + return nil, nil, nil, fmt.Errorf("failed program instantiation: %w", err) } - return prg, ast, nil + return prg, ast, cov, nil } func debug(log *logp.Logger, trace *httplog.LoggingRoundTripper) func(string, any) { @@ -1064,8 +1120,8 @@ func debug(log *logp.Logger, trace *httplog.LoggingRoundTripper) func(string, an } } -func evalWith(ctx context.Context, prg cel.Program, ast *cel.Ast, state map[string]interface{}, now time.Time) (map[string]interface{}, error) { - out, _, err := prg.ContextEval(ctx, map[string]interface{}{ +func evalWith(ctx context.Context, prg cel.Program, ast *cel.Ast, state map[string]interface{}, now time.Time, details bool) (map[string]interface{}, error) { + out, det, err := prg.ContextEval(ctx, map[string]interface{}{ // Replace global program "now" with current time. This is necessary // as the lib.Time now global is static at program instantiation time // which will persist over multiple evaluations. The lib.Time behaviour @@ -1080,6 +1136,9 @@ func evalWith(ctx context.Context, prg cel.Program, ast *cel.Ast, state map[stri }) if err != nil { err = lib.DecoratedError{AST: ast, Err: err} + if details { + err = dumpError{error: err, dump: lib.NewDump(ast, det)} + } } if e := ctx.Err(); e != nil { err = e @@ -1108,6 +1167,36 @@ func evalWith(ctx context.Context, prg cel.Program, ast *cel.Ast, state map[stri } } +// dumpError is an evaluation state dump associated with an error. +type dumpError struct { + error + dump *lib.Dump +} + +func (e dumpError) writeToFile(path string) (err error) { + err = os.MkdirAll(filepath.Dir(path), 0o700) + if err != nil { + return err + } + f, err := os.Create(path) + if err != nil { + return err + } + defer func() { + err = errors.Join(err, f.Sync(), f.Close()) + }() + enc := json.NewEncoder(f) + enc.SetEscapeHTML(false) + type dump struct { + Error string `json:"error"` + State []lib.NodeValue `json:"state"` + } + return enc.Encode(dump{ + Error: e.Error(), + State: e.dump.NodeValues(), + }) +} + // clearWantMore sets the state to not request additional work in a periodic evaluation. // It leaves state intact if there is no "want_more" element, and sets the element to false // if there is. This is necessary instead of just doing delete(state, "want_more") as diff --git a/x-pack/filebeat/input/cel/input_test.go b/x-pack/filebeat/input/cel/input_test.go index 9e4fe746d76c..7ccfb9ccbee2 100644 --- a/x-pack/filebeat/input/cel/input_test.go +++ b/x-pack/filebeat/input/cel/input_test.go @@ -45,6 +45,7 @@ var inputTests = []struct { want []map[string]interface{} wantCursor []map[string]interface{} wantErr error + prepare func() error wantFile string wantNoFile string }{ @@ -63,6 +64,20 @@ var inputTests = []struct { {"message": "Hello, World!"}, }, }, + { + name: "hello_world_sprintf", + config: map[string]interface{}{ + "interval": 1, + "program": `{"events":[{"message":sprintf("Hello, %s!", ["World"])}]}`, + "state": nil, + "resource": map[string]interface{}{ + "url": "", + }, + }, + want: []map[string]interface{}{ + {"message": "Hello, World!"}, + }, + }, { name: "hello_world_time", config: map[string]interface{}{ @@ -1671,6 +1686,131 @@ var inputTests = []struct { }, }}, }, + { + name: "dump_no_error", + config: map[string]interface{}{ + "interval": 1, + "program": `{"events":[{"message":{"value": try(debug("divide by zero", 0/0))}}]}`, + "state": nil, + "resource": map[string]interface{}{ + "url": "", + }, + "failure_dump": map[string]interface{}{ + "enabled": true, + "filename": "failure_dumps/dump.json", + }, + }, + time: func() time.Time { return time.Date(2010, 2, 8, 0, 0, 0, 0, time.UTC) }, + wantNoFile: filepath.Join("failure_dumps", "dump-2010-02-08T00-00-00.000.json"), + want: []map[string]interface{}{{ + "message": map[string]interface{}{ + "value": "division by zero", + }, + }}, + }, + { + name: "dump_error", + config: map[string]interface{}{ + "interval": 1, + "program": `{"events":[{"message":{"value": debug("divide by zero", 0/0)}}]}`, + "state": nil, + "resource": map[string]interface{}{ + "url": "", + }, + "failure_dump": map[string]interface{}{ + "enabled": true, + "filename": "failure_dumps/dump.json", + }, + }, + time: func() time.Time { return time.Date(2010, 2, 9, 0, 0, 0, 0, time.UTC) }, + wantFile: filepath.Join("failure_dumps", "dump-2010-02-09T00-00-00.000.json"), // One day after the no dump case. + want: []map[string]interface{}{ + { + "error": map[string]interface{}{ + "message": `failed eval: ERROR: :1:58: division by zero + | {"events":[{"message":{"value": debug("divide by zero", 0/0)}}]} + | .........................................................^`, + }, + }, + }, + }, + { + name: "dump_error_delete", + config: map[string]interface{}{ + "interval": 1, + "program": `{"events":[{"message":{"value": debug("divide by zero", 0/0)}}]}`, + "state": nil, + "resource": map[string]interface{}{ + "url": "", + }, + "failure_dump": map[string]interface{}{ + "enabled": false, // We have a name but are disabled, so delete. + "filename": "failure_dumps/dump.json", + }, + }, + time: func() time.Time { return time.Date(2010, 2, 9, 0, 0, 0, 0, time.UTC) }, + prepare: func() error { + // Make a file that the configuration should delete. + err := os.MkdirAll("failure_dumps", 0o700) + if err != nil { + return err + } + return os.WriteFile(filepath.Join("failure_dumps", "dump-2010-02-09T00-00-00.000.json"), nil, 0o600) + }, + wantNoFile: filepath.Join("failure_dumps", "dump-2010-02-09T00-00-00.000.json"), // One day after the no dump case. + want: []map[string]interface{}{ + { + "error": map[string]interface{}{ + "message": `failed eval: ERROR: :1:58: division by zero + | {"events":[{"message":{"value": debug("divide by zero", 0/0)}}]} + | .........................................................^`, + }, + }, + }, + }, + + // Coverage + { + name: "coverage", + config: map[string]interface{}{ + "interval": 1, + "program": `int(state.n).as(n, { + "events": [{"n": n+1}], + "n": n+1, + "want_more": n+1 < 5, + "probe": n < 2 ? + "little" + : + "big", + "fail_probe": n < 0 ? + "negative" + : + "non-negative", + })`, + "record_coverage": true, + "state": map[string]any{"n": 0}, + "resource": map[string]interface{}{ + "url": "", + }, + }, + time: func() time.Time { return time.Date(2010, 2, 9, 0, 0, 0, 0, time.UTC) }, + // The program will be evaluated five times in the first periodic + // run and then once for all subsequent runs. We depend here on + // the test construction that asks that we get at least as many + // results from the input as there are elements in the want slice + // and then stop. + want: []map[string]interface{}{ + // First periodic run. + {"n": float64(1)}, + {"n": float64(2)}, + {"n": float64(3)}, + {"n": float64(4)}, + {"n": float64(5)}, + // Second and subsequent periodic runs. + {"n": float64(6)}, + {"n": float64(7)}, + }, + }, // not yet done from httpjson (some are redundant since they are compositional products). // @@ -1694,6 +1834,11 @@ func TestInput(t *testing.T) { os.Setenv("CELTESTENVVAR", "TESTVALUE") os.Setenv("DISALLOWEDCELTESTENVVAR", "DISALLOWEDTESTVALUE") + err := os.RemoveAll("failure_dumps") + if err != nil { + t.Fatalf("failed to remove failure_dumps directory: %v", err) + } + logp.TestingSetup() for _, test := range inputTests { t.Run(test.name, func(t *testing.T) { @@ -1704,6 +1849,13 @@ func TestInput(t *testing.T) { t.Skip("skipping remote endpoint test") } + if test.prepare != nil { + err := test.prepare() + if err != nil { + t.Fatalf("unexpected from prepare(): %v", err) + } + } + if test.server != nil { test.server(t, test.handler, test.config) } @@ -1756,6 +1908,20 @@ func TestInput(t *testing.T) { if fmt.Sprint(err) != fmt.Sprint(test.wantErr) { t.Errorf("unexpected error from running input: got:%v want:%v", err, test.wantErr) } + if test.wantFile != "" { + if _, err := os.Stat(filepath.Join(tempDir, test.wantFile)); err != nil { + t.Errorf("expected log file not found: %v", err) + } + } + if test.wantNoFile != "" { + paths, err := filepath.Glob(filepath.Join(tempDir, test.wantNoFile)) + if err != nil { + t.Fatalf("unexpected error calling filepath.Glob(%q): %v", test.wantNoFile, err) + } + if len(paths) != 0 { + t.Errorf("unexpected files found: %v", paths) + } + } if test.wantErr != nil { return } @@ -1788,20 +1954,6 @@ func TestInput(t *testing.T) { t.Errorf("unexpected cursor for event %d: got:- want:+\n%s", i, cmp.Diff(got, test.wantCursor[i])) } } - if test.wantFile != "" { - if _, err := os.Stat(filepath.Join(tempDir, test.wantFile)); err != nil { - t.Errorf("expected log file not found: %v", err) - } - } - if test.wantNoFile != "" { - paths, err := filepath.Glob(filepath.Join(tempDir, test.wantNoFile)) - if err != nil { - t.Fatalf("unexpected error calling filepath.Glob(%q): %v", test.wantNoFile, err) - } - if len(paths) != 0 { - t.Errorf("unexpected files found: %v", paths) - } - } }) } } diff --git a/x-pack/filebeat/input/default-inputs/inputs_aix.go b/x-pack/filebeat/input/default-inputs/inputs_aix.go index 05e2cbe660d5..d3fa76b10890 100644 --- a/x-pack/filebeat/input/default-inputs/inputs_aix.go +++ b/x-pack/filebeat/input/default-inputs/inputs_aix.go @@ -14,6 +14,7 @@ import ( "github.com/elastic/beats/v7/x-pack/filebeat/input/httpjson" "github.com/elastic/beats/v7/x-pack/filebeat/input/lumberjack" "github.com/elastic/beats/v7/x-pack/filebeat/input/o365audit" + "github.com/elastic/beats/v7/x-pack/filebeat/input/salesforce" "github.com/elastic/elastic-agent-libs/logp" ) @@ -25,5 +26,6 @@ func xpackInputs(info beat.Info, log *logp.Logger, store beater.StateStore) []v2 o365audit.Plugin(log, store), awss3.Plugin(store), lumberjack.Plugin(), + salesforce.Plugin(log, store), } } diff --git a/x-pack/filebeat/input/default-inputs/inputs_darwin.go b/x-pack/filebeat/input/default-inputs/inputs_darwin.go new file mode 100644 index 000000000000..b43d75258b35 --- /dev/null +++ b/x-pack/filebeat/input/default-inputs/inputs_darwin.go @@ -0,0 +1,54 @@ +// 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. + +//go:build darwin + +package inputs + +import ( + "github.com/elastic/beats/v7/filebeat/beater" + v2 "github.com/elastic/beats/v7/filebeat/input/v2" + "github.com/elastic/beats/v7/libbeat/beat" + "github.com/elastic/beats/v7/x-pack/filebeat/input/awscloudwatch" + "github.com/elastic/beats/v7/x-pack/filebeat/input/awss3" + "github.com/elastic/beats/v7/x-pack/filebeat/input/azureblobstorage" + "github.com/elastic/beats/v7/x-pack/filebeat/input/azureeventhub" + "github.com/elastic/beats/v7/x-pack/filebeat/input/benchmark" + "github.com/elastic/beats/v7/x-pack/filebeat/input/cel" + "github.com/elastic/beats/v7/x-pack/filebeat/input/cloudfoundry" + "github.com/elastic/beats/v7/x-pack/filebeat/input/entityanalytics" + "github.com/elastic/beats/v7/x-pack/filebeat/input/gcs" + "github.com/elastic/beats/v7/x-pack/filebeat/input/http_endpoint" + "github.com/elastic/beats/v7/x-pack/filebeat/input/httpjson" + "github.com/elastic/beats/v7/x-pack/filebeat/input/lumberjack" + "github.com/elastic/beats/v7/x-pack/filebeat/input/netflow" + "github.com/elastic/beats/v7/x-pack/filebeat/input/o365audit" + "github.com/elastic/beats/v7/x-pack/filebeat/input/salesforce" + "github.com/elastic/beats/v7/x-pack/filebeat/input/streaming" + "github.com/elastic/beats/v7/x-pack/filebeat/input/unifiedlogs" + "github.com/elastic/elastic-agent-libs/logp" +) + +func xpackInputs(info beat.Info, log *logp.Logger, store beater.StateStore) []v2.Plugin { + return []v2.Plugin{ + azureblobstorage.Plugin(log, store), + azureeventhub.Plugin(log), + cel.Plugin(log, store), + cloudfoundry.Plugin(), + entityanalytics.Plugin(log), + gcs.Plugin(log, store), + http_endpoint.Plugin(), + httpjson.Plugin(log, store), + o365audit.Plugin(log, store), + awss3.Plugin(store), + awscloudwatch.Plugin(), + lumberjack.Plugin(), + salesforce.Plugin(log, store), + streaming.Plugin(log, store), + streaming.PluginWebsocketAlias(log, store), + netflow.Plugin(log), + benchmark.Plugin(), + unifiedlogs.Plugin(log, store), + } +} diff --git a/x-pack/filebeat/input/default-inputs/inputs_other.go b/x-pack/filebeat/input/default-inputs/inputs_other.go index 731f8979766e..a14145a5265f 100644 --- a/x-pack/filebeat/input/default-inputs/inputs_other.go +++ b/x-pack/filebeat/input/default-inputs/inputs_other.go @@ -2,7 +2,7 @@ // or more contributor license agreements. Licensed under the Elastic License; // you may not use this file except in compliance with the Elastic License. -//go:build !aix && !windows +//go:build !aix && !darwin && !windows package inputs diff --git a/x-pack/filebeat/input/default-inputs/inputs_windows.go b/x-pack/filebeat/input/default-inputs/inputs_windows.go index e88e45ff2e7c..4b27c3b35c2f 100644 --- a/x-pack/filebeat/input/default-inputs/inputs_windows.go +++ b/x-pack/filebeat/input/default-inputs/inputs_windows.go @@ -25,6 +25,7 @@ import ( "github.com/elastic/beats/v7/x-pack/filebeat/input/lumberjack" "github.com/elastic/beats/v7/x-pack/filebeat/input/netflow" "github.com/elastic/beats/v7/x-pack/filebeat/input/o365audit" + "github.com/elastic/beats/v7/x-pack/filebeat/input/salesforce" "github.com/elastic/elastic-agent-libs/logp" ) @@ -44,6 +45,7 @@ func xpackInputs(info beat.Info, log *logp.Logger, store beater.StateStore) []v2 lumberjack.Plugin(), etw.Plugin(), netflow.Plugin(log), + salesforce.Plugin(log, store), benchmark.Plugin(), } } diff --git a/x-pack/filebeat/input/entityanalytics/internal/kvstore/tracker.go b/x-pack/filebeat/input/entityanalytics/internal/kvstore/tracker.go index b18229b77954..71abb10d137f 100644 --- a/x-pack/filebeat/input/entityanalytics/internal/kvstore/tracker.go +++ b/x-pack/filebeat/input/entityanalytics/internal/kvstore/tracker.go @@ -6,10 +6,10 @@ package kvstore import ( "context" + "sync/atomic" "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/beats/v7/libbeat/common/acker" - "github.com/elastic/beats/v7/libbeat/common/atomic" ) // TxTracker implements a transaction tracker. Individual beat events which @@ -17,20 +17,20 @@ import ( // ACK-ed, the pending count is decremented (see NewTxACKHandler). Calling Wait // will block until all events are ACK-ed or the parent context is cancelled. type TxTracker struct { - pending atomic.Int + pending atomic.Int64 ctx context.Context cancel context.CancelFunc } // Add increments the pending count. func (t *TxTracker) Add() { - t.pending.Inc() + t.pending.Add(1) } // Ack decrements the pending count. If pending goes to zero, then the // context on TxTracker is cancelled. func (t *TxTracker) Ack() { - if t.pending.Dec() == 0 { + if t.pending.Add(-1) == 0 { t.cancel() } } diff --git a/x-pack/filebeat/input/entityanalytics/internal/kvstore/tracker_test.go b/x-pack/filebeat/input/entityanalytics/internal/kvstore/tracker_test.go index 7b452e21ae89..7741fa1e595e 100644 --- a/x-pack/filebeat/input/entityanalytics/internal/kvstore/tracker_test.go +++ b/x-pack/filebeat/input/entityanalytics/internal/kvstore/tracker_test.go @@ -15,7 +15,7 @@ import ( func TestTxTracker_Ack(t *testing.T) { txTracker := NewTxTracker(context.Background()) - txTracker.pending.Inc() + txTracker.pending.Add(1) txTracker.Ack() @@ -25,9 +25,9 @@ func TestTxTracker_Ack(t *testing.T) { func TestTxTracker_Add(t *testing.T) { txTracker := NewTxTracker(context.Background()) - require.Equal(t, 0, txTracker.pending.Load()) + require.Equal(t, int64(0), txTracker.pending.Load()) txTracker.Add() - require.Equal(t, 1, txTracker.pending.Load()) + require.Equal(t, int64(1), txTracker.pending.Load()) } func TestTxTracker_Wait(t *testing.T) { @@ -43,7 +43,7 @@ func TestTxACKHandler(t *testing.T) { handler := NewTxACKHandler() txTracker.Add() - require.Equal(t, 1, txTracker.pending.Load()) + require.Equal(t, int64(1), txTracker.pending.Load()) handler.AddEvent(beat.Event{ Private: txTracker, @@ -63,7 +63,7 @@ func TestTxACKHandler(t *testing.T) { handler := NewTxACKHandler() txTracker.Add() - require.Equal(t, 1, txTracker.pending.Load()) + require.Equal(t, int64(1), txTracker.pending.Load()) handler.AddEvent(beat.Event{ Private: txTracker, @@ -71,6 +71,6 @@ func TestTxACKHandler(t *testing.T) { txTracker.Wait() - require.Equal(t, 1, txTracker.pending.Load()) + require.Equal(t, int64(1), txTracker.pending.Load()) }) } diff --git a/x-pack/filebeat/input/entityanalytics/internal/kvstore/transaction.go b/x-pack/filebeat/input/entityanalytics/internal/kvstore/transaction.go index 7f32429a4e96..c62155d27fbc 100644 --- a/x-pack/filebeat/input/entityanalytics/internal/kvstore/transaction.go +++ b/x-pack/filebeat/input/entityanalytics/internal/kvstore/transaction.go @@ -8,10 +8,9 @@ import ( "encoding/json" "errors" "fmt" + "sync/atomic" "go.etcd.io/bbolt" - - "github.com/elastic/beats/v7/libbeat/common/atomic" ) var ( @@ -126,7 +125,7 @@ func (t *Transaction) Delete(bucket, key []byte) error { // Commit will write any changes to disk. For read-only transactions, calling // Commit will route to Rollback. func (t *Transaction) Commit() error { - if !t.closed.CAS(false, true) { + if !t.closed.CompareAndSwap(false, true) { return nil } if !t.writeable { @@ -138,7 +137,7 @@ func (t *Transaction) Commit() error { // Rollback closes the transaction. For write transactions, all updates made // within the transaction will be discarded. func (t *Transaction) Rollback() error { - if !t.closed.CAS(false, true) { + if !t.closed.CompareAndSwap(false, true) { return nil } return t.tx.Rollback() diff --git a/x-pack/filebeat/input/entityanalytics/provider/okta/conf.go b/x-pack/filebeat/input/entityanalytics/provider/okta/conf.go index 41a3895a70d2..61a61aed25e1 100644 --- a/x-pack/filebeat/input/entityanalytics/provider/okta/conf.go +++ b/x-pack/filebeat/input/entityanalytics/provider/okta/conf.go @@ -68,6 +68,10 @@ type conf struct { // API limit resets. LimitWindow time.Duration `config:"limit_window"` + // LimitFixed is a number of requests to allow in each LimitWindow, + // overriding the guidance in API responses. + LimitFixed *int `config:"limit_fixed"` + // Request is the configuration for establishing // HTTP requests to the API. Request *requestConfig `config:"request"` diff --git a/x-pack/filebeat/input/entityanalytics/provider/okta/internal/okta/okta.go b/x-pack/filebeat/input/entityanalytics/provider/okta/internal/okta/okta.go index 3d8bdae11c97..b2bacba89a8c 100644 --- a/x-pack/filebeat/input/entityanalytics/provider/okta/internal/okta/okta.go +++ b/x-pack/filebeat/input/entityanalytics/provider/okta/internal/okta/okta.go @@ -14,13 +14,9 @@ import ( "io" "net/http" "net/url" - "path" - "strconv" "strings" "time" - "golang.org/x/time/rate" - "github.com/elastic/elastic-agent-libs/logp" ) @@ -189,22 +185,29 @@ func (o Response) String() string { // Parts of the response may be omitted using the omit parameter. // // The provided rate limiter must allow at least request and will be updated with the -// response's X-Rate-Limit headers considering the rate limit window time. Details -// for rate limits are available at https://help.okta.com/en-us/Content/Topics/Security/API-rate-limits.htm +// response's X-Rate-Limit headers. Details for rate limits are available at +// https://help.okta.com/en-us/Content/Topics/Security/API-rate-limits.htm // and account rate limits and windows can be seen on the Okta admin dashboard at // https://${yourOktaDomain}/reports/rate-limit. // // See https://developer.okta.com/docs/reference/api/users/#list-users for details. -func GetUserDetails(ctx context.Context, cli *http.Client, host, key, user string, query url.Values, omit Response, lim *rate.Limiter, window time.Duration, log *logp.Logger) ([]User, http.Header, error) { - const endpoint = "/api/v1/users" +func GetUserDetails(ctx context.Context, cli *http.Client, host, key, user string, query url.Values, omit Response, lim *RateLimiter, log *logp.Logger) ([]User, http.Header, error) { + var endpoint, path string + if user == "" { + endpoint = "/api/v1/users" + path = endpoint + } else { + endpoint = "/api/v1/users/{user}" + path = strings.Replace(endpoint, "{user}", user, 1) + } u := &url.URL{ Scheme: "https", Host: host, - Path: path.Join(endpoint, user), + Path: path, RawQuery: query.Encode(), } - return getDetails[User](ctx, cli, u, key, user == "", omit, lim, window, log) + return getDetails[User](ctx, cli, u, endpoint, key, user == "", omit, lim, log) } // GetUserFactors returns Okta group roles using the groups API endpoint. host is the @@ -213,19 +216,20 @@ func GetUserDetails(ctx context.Context, cli *http.Client, host, key, user strin // See GetUserDetails for details of the query and rate limit parameters. // // See https://developer.okta.com/docs/api/openapi/okta-management/management/tag/UserFactor/#tag/UserFactor/operation/listFactors. -func GetUserFactors(ctx context.Context, cli *http.Client, host, key, user string, lim *rate.Limiter, window time.Duration, log *logp.Logger) ([]Factor, http.Header, error) { - const endpoint = "/api/v1/users" - +func GetUserFactors(ctx context.Context, cli *http.Client, host, key, user string, lim *RateLimiter, log *logp.Logger) ([]Factor, http.Header, error) { if user == "" { return nil, nil, errors.New("no user specified") } + const endpoint = "/api/v1/users/{user}/factors" + path := strings.Replace(endpoint, "{user}", user, 1) + u := &url.URL{ Scheme: "https", Host: host, - Path: path.Join(endpoint, user, "factors"), + Path: path, } - return getDetails[Factor](ctx, cli, u, key, true, OmitNone, lim, window, log) + return getDetails[Factor](ctx, cli, u, endpoint, key, true, OmitNone, lim, log) } // GetUserRoles returns Okta group roles using the groups API endpoint. host is the @@ -234,19 +238,20 @@ func GetUserFactors(ctx context.Context, cli *http.Client, host, key, user strin // See GetUserDetails for details of the query and rate limit parameters. // // See https://developer.okta.com/docs/api/openapi/okta-management/management/tag/RoleAssignmentBGroup/#tag/RoleAssignmentBGroup/operation/listGroupAssignedRoles. -func GetUserRoles(ctx context.Context, cli *http.Client, host, key, user string, lim *rate.Limiter, window time.Duration, log *logp.Logger) ([]Role, http.Header, error) { - const endpoint = "/api/v1/users" - +func GetUserRoles(ctx context.Context, cli *http.Client, host, key, user string, lim *RateLimiter, log *logp.Logger) ([]Role, http.Header, error) { if user == "" { return nil, nil, errors.New("no user specified") } + const endpoint = "/api/v1/users/{user}/roles" + path := strings.Replace(endpoint, "{user}", user, 1) + u := &url.URL{ Scheme: "https", Host: host, - Path: path.Join(endpoint, user, "roles"), + Path: path, } - return getDetails[Role](ctx, cli, u, key, true, OmitNone, lim, window, log) + return getDetails[Role](ctx, cli, u, endpoint, key, true, OmitNone, lim, log) } // GetUserGroupDetails returns Okta group details using the users API endpoint. host is the @@ -255,19 +260,20 @@ func GetUserRoles(ctx context.Context, cli *http.Client, host, key, user string, // See GetUserDetails for details of the query and rate limit parameters. // // See https://developer.okta.com/docs/reference/api/users/#request-parameters-8 (no anchor exists on the page for this endpoint) for details. -func GetUserGroupDetails(ctx context.Context, cli *http.Client, host, key, user string, lim *rate.Limiter, window time.Duration, log *logp.Logger) ([]Group, http.Header, error) { - const endpoint = "/api/v1/users" - +func GetUserGroupDetails(ctx context.Context, cli *http.Client, host, key, user string, lim *RateLimiter, log *logp.Logger) ([]Group, http.Header, error) { if user == "" { return nil, nil, errors.New("no user specified") } + const endpoint = "/api/v1/users/{user}/groups" + path := strings.Replace(endpoint, "{user}", user, 1) + u := &url.URL{ Scheme: "https", Host: host, - Path: path.Join(endpoint, user, "groups"), + Path: path, } - return getDetails[Group](ctx, cli, u, key, true, OmitNone, lim, window, log) + return getDetails[Group](ctx, cli, u, endpoint, key, true, OmitNone, lim, log) } // GetGroupRoles returns Okta group roles using the groups API endpoint. host is the @@ -276,19 +282,20 @@ func GetUserGroupDetails(ctx context.Context, cli *http.Client, host, key, user // See GetUserDetails for details of the query and rate limit parameters. // // See https://developer.okta.com/docs/api/openapi/okta-management/management/tag/RoleAssignmentBGroup/#tag/RoleAssignmentBGroup/operation/listGroupAssignedRoles. -func GetGroupRoles(ctx context.Context, cli *http.Client, host, key, group string, lim *rate.Limiter, window time.Duration, log *logp.Logger) ([]Role, http.Header, error) { - const endpoint = "/api/v1/groups" - +func GetGroupRoles(ctx context.Context, cli *http.Client, host, key, group string, lim *RateLimiter, log *logp.Logger) ([]Role, http.Header, error) { if group == "" { return nil, nil, errors.New("no group specified") } + const endpoint = "/api/v1/groups/{group}/rules" + path := strings.Replace(endpoint, "{group}", group, 1) + u := &url.URL{ Scheme: "https", Host: host, - Path: path.Join(endpoint, group, "roles"), + Path: path, } - return getDetails[Role](ctx, cli, u, key, true, OmitNone, lim, window, log) + return getDetails[Role](ctx, cli, u, endpoint, key, true, OmitNone, lim, log) } // GetDeviceDetails returns Okta device details using the list devices API endpoint. host is the @@ -298,16 +305,24 @@ func GetGroupRoles(ctx context.Context, cli *http.Client, host, key, group strin // See GetUserDetails for details of the query and rate limit parameters. // // See https://developer.okta.com/docs/api/openapi/okta-management/management/tag/Device/#tag/Device/operation/listDevices for details. -func GetDeviceDetails(ctx context.Context, cli *http.Client, host, key, device string, query url.Values, lim *rate.Limiter, window time.Duration, log *logp.Logger) ([]Device, http.Header, error) { - const endpoint = "/api/v1/devices" +func GetDeviceDetails(ctx context.Context, cli *http.Client, host, key, device string, query url.Values, lim *RateLimiter, log *logp.Logger) ([]Device, http.Header, error) { + var endpoint string + var path string + if device == "" { + endpoint = "/api/v1/devices" + path = endpoint + } else { + endpoint = "/api/v1/devices/{device}" + path = strings.Replace(endpoint, "{device}", device, 1) + } u := &url.URL{ Scheme: "https", Host: host, - Path: path.Join(endpoint, device), + Path: path, RawQuery: query.Encode(), } - return getDetails[Device](ctx, cli, u, key, device == "", OmitNone, lim, window, log) + return getDetails[Device](ctx, cli, u, endpoint, key, device == "", OmitNone, lim, log) } // GetDeviceUsers returns Okta user details for users associated with the provided device identifier @@ -317,21 +332,22 @@ func GetDeviceDetails(ctx context.Context, cli *http.Client, host, key, device s // See GetUserDetails for details of the query and rate limit parameters. // // See https://developer.okta.com/docs/api/openapi/okta-management/management/tag/Device/#tag/Device/operation/listDeviceUsers for details. -func GetDeviceUsers(ctx context.Context, cli *http.Client, host, key, device string, query url.Values, omit Response, lim *rate.Limiter, window time.Duration, log *logp.Logger) ([]User, http.Header, error) { +func GetDeviceUsers(ctx context.Context, cli *http.Client, host, key, device string, query url.Values, omit Response, lim *RateLimiter, log *logp.Logger) ([]User, http.Header, error) { if device == "" { // No user associated with a null device. Not an error. return nil, nil, nil } - const endpoint = "/api/v1/devices" + const endpoint = "/api/v1/devices/{device}/users" + path := strings.Replace(endpoint, "{device}", device, 1) u := &url.URL{ Scheme: "https", Host: host, - Path: path.Join(endpoint, device, "users"), + Path: path, RawQuery: query.Encode(), } - du, h, err := getDetails[devUser](ctx, cli, u, key, true, omit, lim, window, log) + du, h, err := getDetails[devUser](ctx, cli, u, endpoint, key, true, omit, lim, log) if err != nil { return nil, h, err } @@ -356,7 +372,7 @@ type devUser struct { // for the specific user are returned, otherwise a list of all users is returned. // // See GetUserDetails for details of the query and rate limit parameters. -func getDetails[E entity](ctx context.Context, cli *http.Client, u *url.URL, key string, all bool, omit Response, lim *rate.Limiter, window time.Duration, log *logp.Logger) ([]E, http.Header, error) { +func getDetails[E entity](ctx context.Context, cli *http.Client, u *url.URL, endpoint string, key string, all bool, omit Response, lim *RateLimiter, log *logp.Logger) ([]E, http.Header, error) { url := u.String() req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { @@ -370,8 +386,7 @@ func getDetails[E entity](ctx context.Context, cli *http.Client, u *url.URL, key req.Header.Set("Content-Type", contentType) req.Header.Set("Authorization", fmt.Sprintf("SSWS %s", key)) - log.Debugw("rate limit", "limit", lim.Limit(), "burst", lim.Burst(), "url", url) - err = lim.Wait(ctx) + err = lim.Wait(ctx, endpoint, u, log) if err != nil { return nil, nil, err } @@ -380,7 +395,7 @@ func getDetails[E entity](ctx context.Context, cli *http.Client, u *url.URL, key return nil, nil, err } defer resp.Body.Close() - err = oktaRateLimit(resp.Header, window, lim, log) + err = lim.Update(endpoint, resp.Header, log) if err != nil { io.Copy(io.Discard, resp.Body) return nil, nil, err @@ -443,59 +458,6 @@ func (e *Error) Error() string { return fmt.Sprintf("%s: %s", summary, strings.Join(causes, ",")) } -// oktaRateLimit implements the Okta rate limit policy translation. -// -// See https://developer.okta.com/docs/reference/rl-best-practices/ for details. -func oktaRateLimit(h http.Header, window time.Duration, limiter *rate.Limiter, log *logp.Logger) error { - limit := h.Get("X-Rate-Limit-Limit") - remaining := h.Get("X-Rate-Limit-Remaining") - reset := h.Get("X-Rate-Limit-Reset") - log.Debugw("rate limit header", "X-Rate-Limit-Limit", limit, "X-Rate-Limit-Remaining", remaining, "X-Rate-Limit-Reset", reset) - if limit == "" || remaining == "" || reset == "" { - return nil - } - - lim, err := strconv.ParseFloat(limit, 64) - if err != nil { - return err - } - rem, err := strconv.ParseFloat(remaining, 64) - if err != nil { - return err - } - rst, err := strconv.ParseInt(reset, 10, 64) - if err != nil { - return err - } - resetTime := time.Unix(rst, 0) - per := time.Until(resetTime).Seconds() - - // Be conservative here; the docs don't exactly specify burst rates. - // Make sure we can make at least one new request, even if we fail - // to get a non-zero rate.Limit. We could set to zero for the case - // that limit=rate.Inf, but that detail is not important. - burst := 1 - - rateLimit := rate.Limit(rem / per) - - // Process reset if we need to wait until reset to avoid a request against a zero quota. - if rateLimit <= 0 { - waitUntil := resetTime.UTC() - // next gives us a sane next window estimate, but the - // estimate will be overwritten when we make the next - // permissible API request. - next := rate.Limit(lim / window.Seconds()) - limiter.SetLimitAt(waitUntil, next) - limiter.SetBurstAt(waitUntil, burst) - log.Debugw("rate limit adjust", "reset_time", waitUntil, "next_rate", next, "next_burst", burst) - return nil - } - limiter.SetLimit(rateLimit) - limiter.SetBurst(burst) - log.Debugw("rate limit adjust", "set_rate", rateLimit, "set_burst", burst) - return nil -} - // Next returns the next URL query for a pagination sequence. If no further // page is available, Next returns io.EOF. func Next(h http.Header) (query url.Values, err error) { diff --git a/x-pack/filebeat/input/entityanalytics/provider/okta/internal/okta/okta_test.go b/x-pack/filebeat/input/entityanalytics/provider/okta/internal/okta/okta_test.go index 9b04d3996bf9..d362d72f3910 100644 --- a/x-pack/filebeat/input/entityanalytics/provider/okta/internal/okta/okta_test.go +++ b/x-pack/filebeat/input/entityanalytics/provider/okta/internal/okta/okta_test.go @@ -44,14 +44,14 @@ func Test(t *testing.T) { t.Skip("okta tests require ${OKTA_TOKEN} to be set") } - // Make a global limiter with the capacity to proceed once. - limiter := rate.NewLimiter(1, 1) - // There are a variety of windows, the most conservative is one minute. // The rate limit will be adjusted on the second call to the API if // window is actually used to rate limit calculations. const window = time.Minute + // Make a global limiter + limiter := NewRateLimiter(window, nil) + for _, omit := range []Response{ OmitNone, OmitCredentials, @@ -65,7 +65,7 @@ func Test(t *testing.T) { t.Run("me", func(t *testing.T) { query := make(url.Values) query.Set("limit", "200") - users, _, err := GetUserDetails(context.Background(), http.DefaultClient, host, key, "me", query, omit, limiter, window, logger) + users, _, err := GetUserDetails(context.Background(), http.DefaultClient, host, key, "me", query, omit, limiter, logger) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -94,7 +94,7 @@ func Test(t *testing.T) { t.Run("my_groups", func(t *testing.T) { query := make(url.Values) query.Set("limit", "200") - groups, _, err := GetUserGroupDetails(context.Background(), http.DefaultClient, host, key, me.ID, limiter, window, logger) + groups, _, err := GetUserGroupDetails(context.Background(), http.DefaultClient, host, key, me.ID, limiter, logger) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -119,7 +119,7 @@ func Test(t *testing.T) { t.Run("my_roles", func(t *testing.T) { query := make(url.Values) query.Set("limit", "200") - roles, _, err := GetUserRoles(context.Background(), http.DefaultClient, host, key, me.ID, limiter, window, logger) + roles, _, err := GetUserRoles(context.Background(), http.DefaultClient, host, key, me.ID, limiter, logger) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -144,7 +144,7 @@ func Test(t *testing.T) { t.Run("my_factors", func(t *testing.T) { query := make(url.Values) query.Set("limit", "200") - factors, _, err := GetUserFactors(context.Background(), http.DefaultClient, host, key, me.ID, limiter, window, logger) + factors, _, err := GetUserFactors(context.Background(), http.DefaultClient, host, key, me.ID, limiter, logger) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -175,7 +175,7 @@ func Test(t *testing.T) { query := make(url.Values) query.Set("limit", "200") - users, _, err := GetUserDetails(context.Background(), http.DefaultClient, host, key, login, query, omit, limiter, window, logger) + users, _, err := GetUserDetails(context.Background(), http.DefaultClient, host, key, login, query, omit, limiter, logger) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -190,7 +190,7 @@ func Test(t *testing.T) { t.Run("all", func(t *testing.T) { query := make(url.Values) query.Set("limit", "200") - users, _, err := GetUserDetails(context.Background(), http.DefaultClient, host, key, "", query, omit, limiter, window, logger) + users, _, err := GetUserDetails(context.Background(), http.DefaultClient, host, key, "", query, omit, limiter, logger) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -218,7 +218,7 @@ func Test(t *testing.T) { query := make(url.Values) query.Set("limit", "200") query.Add("search", `not (status pr)`) // This cannot ever be true. - _, _, err := GetUserDetails(context.Background(), http.DefaultClient, host, key, "", query, omit, limiter, window, logger) + _, _, err := GetUserDetails(context.Background(), http.DefaultClient, host, key, "", query, omit, limiter, logger) oktaErr := &Error{} if !errors.As(err, &oktaErr) { // Don't test the value of the error since it was @@ -234,7 +234,7 @@ func Test(t *testing.T) { t.Run("device", func(t *testing.T) { query := make(url.Values) query.Set("limit", "200") - devices, _, err := GetDeviceDetails(context.Background(), http.DefaultClient, host, key, "", query, limiter, window, logger) + devices, _, err := GetDeviceDetails(context.Background(), http.DefaultClient, host, key, "", query, limiter, logger) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -246,7 +246,7 @@ func Test(t *testing.T) { t.Logf("devices: %s", b) } for _, d := range devices { - users, _, err := GetDeviceUsers(context.Background(), http.DefaultClient, host, key, d.ID, query, OmitCredentials, limiter, window, logger) + users, _, err := GetDeviceUsers(context.Background(), http.DefaultClient, host, key, d.ID, query, OmitCredentials, limiter, logger) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -263,15 +263,15 @@ var localTests = []struct { name string msg string id string - fn func(ctx context.Context, cli *http.Client, host, key, user string, query url.Values, lim *rate.Limiter, window time.Duration, log *logp.Logger) (any, http.Header, error) + fn func(ctx context.Context, cli *http.Client, host, key, user string, query url.Values, lim *RateLimiter, log *logp.Logger) (any, http.Header, error) mkWant func(string) (any, error) }{ { // Test case constructed from API-returned value with details anonymised. name: "users", msg: `[{"id":"userid","status":"STATUS","created":"2023-05-14T13:37:20.000Z","activated":null,"statusChanged":"2023-05-15T01:50:30.000Z","lastLogin":"2023-05-15T01:59:20.000Z","lastUpdated":"2023-05-15T01:50:32.000Z","passwordChanged":"2023-05-15T01:50:32.000Z","recovery_question":{"question":"Who's a major player in the cowboy scene?","answer":"Annie Oakley"},"type":{"id":"typeid"},"profile":{"firstName":"name","lastName":"surname","mobilePhone":null,"secondEmail":null,"login":"name.surname@example.com","email":"name.surname@example.com"},"credentials":{"password":{"value":"secret"},"emails":[{"value":"name.surname@example.com","status":"VERIFIED","type":"PRIMARY"}],"provider":{"type":"OKTA","name":"OKTA"}},"_links":{"self":{"href":"https://localhost/api/v1/users/userid"}}}]`, - fn: func(ctx context.Context, cli *http.Client, host, key, user string, query url.Values, lim *rate.Limiter, window time.Duration, log *logp.Logger) (any, http.Header, error) { - return GetUserDetails(context.Background(), cli, host, key, user, query, OmitNone, lim, window, log) + fn: func(ctx context.Context, cli *http.Client, host, key, user string, query url.Values, lim *RateLimiter, log *logp.Logger) (any, http.Header, error) { + return GetUserDetails(context.Background(), cli, host, key, user, query, OmitNone, lim, log) }, mkWant: mkWant[User], }, @@ -279,8 +279,8 @@ var localTests = []struct { // Test case from https://developer.okta.com/docs/api/openapi/okta-management/management/tag/Device/#tag/Device/operation/listDevices name: "devices", msg: `[{"id":"devid","status":"CREATED","created":"2019-10-02T18:03:07.000Z","lastUpdated":"2019-10-02T18:03:07.000Z","profile":{"displayName":"Example Device name 1","platform":"WINDOWS","serialNumber":"XXDDRFCFRGF3M8MD6D","sid":"S-1-11-111","registered":true,"secureHardwarePresent":false,"diskEncryptionType":"ALL_INTERNAL_VOLUMES"},"resourceType":"UDDevice","resourceDisplayName":{"value":"Example Device name 1","sensitive":false},"resourceAlternateId":null,"resourceId":"guo4a5u7YAHhjXrMK0g4","_links":{"activate":{"href":"https://{yourOktaDomain}/api/v1/devices/guo4a5u7YAHhjXrMK0g4/lifecycle/activate","hints":{"allow":["POST"]}},"self":{"href":"https://{yourOktaDomain}/api/v1/devices/guo4a5u7YAHhjXrMK0g4","hints":{"allow":["GET","PATCH","PUT"]}},"users":{"href":"https://{yourOktaDomain}/api/v1/devices/guo4a5u7YAHhjXrMK0g4/users","hints":{"allow":["GET"]}}}},{"id":"guo4a5u7YAHhjXrMK0g5","status":"ACTIVE","created":"2023-06-21T23:24:02.000Z","lastUpdated":"2023-06-21T23:24:02.000Z","profile":{"displayName":"Example Device name 2","platform":"ANDROID","manufacturer":"Google","model":"Pixel 6","osVersion":"13:2023-05-05","registered":true,"secureHardwarePresent":true,"diskEncryptionType":"USER"},"resourceType":"UDDevice","resourceDisplayName":{"value":"Example Device name 2","sensitive":false},"resourceAlternateId":null,"resourceId":"guo4a5u7YAHhjXrMK0g5","_links":{"activate":{"href":"https://{yourOktaDomain}/api/v1/devices/guo4a5u7YAHhjXrMK0g5/lifecycle/activate","hints":{"allow":["POST"]}},"self":{"href":"https://{yourOktaDomain}/api/v1/devices/guo4a5u7YAHhjXrMK0g5","hints":{"allow":["GET","PATCH","PUT"]}},"users":{"href":"https://{yourOktaDomain}/api/v1/devices/guo4a5u7YAHhjXrMK0g5/users","hints":{"allow":["GET"]}}}}]`, - fn: func(ctx context.Context, cli *http.Client, host, key, device string, query url.Values, lim *rate.Limiter, window time.Duration, log *logp.Logger) (any, http.Header, error) { - return GetDeviceDetails(context.Background(), cli, host, key, device, query, lim, window, log) + fn: func(ctx context.Context, cli *http.Client, host, key, device string, query url.Values, lim *RateLimiter, log *logp.Logger) (any, http.Header, error) { + return GetDeviceDetails(context.Background(), cli, host, key, device, query, lim, log) }, mkWant: mkWant[Device], }, @@ -289,8 +289,8 @@ var localTests = []struct { name: "devices_users", msg: `[{"created":"2023-08-07T21:48:27.000Z","managementStatus":"NOT_MANAGED","user":{"id":"userid","status":"STATUS","created":"2023-05-14T13:37:20.000Z","activated":null,"statusChanged":"2023-05-15T01:50:30.000Z","lastLogin":"2023-05-15T01:59:20.000Z","lastUpdated":"2023-05-15T01:50:32.000Z","passwordChanged":"2023-05-15T01:50:32.000Z","type":{"id":"typeid"},"profile":{"firstName":"name","lastName":"surname","mobilePhone":null,"secondEmail":null,"login":"name.surname@example.com","email":"name.surname@example.com"},"credentials":{"password":{"value":"secret"},"recovery_question":{"question":"Who's a major player in the cowboy scene?","answer":"Annie Oakley"},"emails":[{"value":"name.surname@example.com","status":"VERIFIED","type":"PRIMARY"}],"provider":{"type":"OKTA","name":"OKTA"}},"_links":{"self":{"href":"https://localhost/api/v1/users/userid"}}}}]`, id: "devid", - fn: func(ctx context.Context, cli *http.Client, host, key, device string, query url.Values, lim *rate.Limiter, window time.Duration, log *logp.Logger) (any, http.Header, error) { - return GetDeviceUsers(context.Background(), cli, host, key, device, query, OmitNone, lim, window, log) + fn: func(ctx context.Context, cli *http.Client, host, key, device string, query url.Values, lim *RateLimiter, log *logp.Logger) (any, http.Header, error) { + return GetDeviceUsers(context.Background(), cli, host, key, device, query, OmitNone, lim, log) }, mkWant: mkWant[devUser], }, @@ -315,14 +315,12 @@ func TestLocal(t *testing.T) { for _, test := range localTests { t.Run(test.name, func(t *testing.T) { - // Make a global limiter with more capacity than will be set by the mock API. - // This will show the burst drop. - limiter := rate.NewLimiter(10, 10) - // There are a variety of windows, the most conservative is one minute. // The rate limit will be adjusted on the second call to the API if // window is actually used to rate limit calculations. const window = time.Minute + var fixedLimit *int = nil + limiter := NewRateLimiter(window, fixedLimit) const key = "token" want, err := test.mkWant(test.msg) @@ -368,7 +366,7 @@ func TestLocal(t *testing.T) { query := make(url.Values) query.Set("limit", "200") - got, h, err := test.fn(context.Background(), ts.Client(), host, key, test.id, query, limiter, window, logger) + got, h, err := test.fn(context.Background(), ts.Client(), host, key, test.id, query, limiter, logger) if err != nil { t.Fatalf("unexpected error from Get_Details: %v", err) } @@ -377,12 +375,23 @@ func TestLocal(t *testing.T) { t.Errorf("unexpected result:\n- want\n+ got\n%s", cmp.Diff(want, got)) } - lim := limiter.Limit() - if lim < 49.0/60.0 || 50.0/60.0 < lim { - t.Errorf("unexpected rate limit (outside [49/60, 50/60]: %f", lim) + if len(limiter.byEndpoint) != 1 { + t.Errorf("unexpected number endpoints track by rate limiter: %d", len(limiter.byEndpoint)) + } + // retrieve the rate.Limiter parameters for the one endpoint + var limit rate.Limit + var burst int + for _, e := range limiter.byEndpoint { + limit = e.limiter.Limit() + burst = e.limiter.Burst() + break + } + + if limit < 49.0/60.0 || 50.0/60.0 < limit { + t.Errorf("unexpected rate limit (outside [49/60, 50/60]: %f", limit) } - if limiter.Burst() != 1 { // Set in GetUserDetails. - t.Errorf("unexpected burst: got:%d want:1", limiter.Burst()) + if burst != 1 { + t.Errorf("unexpected burst: got:%d want:1", burst) } next, err := Next(h) diff --git a/x-pack/filebeat/input/entityanalytics/provider/okta/internal/okta/ratelimiter.go b/x-pack/filebeat/input/entityanalytics/provider/okta/internal/okta/ratelimiter.go new file mode 100644 index 000000000000..2dfd8ae923bc --- /dev/null +++ b/x-pack/filebeat/input/entityanalytics/provider/okta/internal/okta/ratelimiter.go @@ -0,0 +1,167 @@ +// 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 okta + +import ( + "context" + "net/http" + "net/url" + "strconv" + "time" + + "golang.org/x/time/rate" + + "github.com/elastic/elastic-agent-libs/logp" +) + +// RateLimiter holds rate limiting information for an API. +// +// Each API endpoint has its own rate limit, which can be dynamically updated +// using response headers. If a fixed limit is set, it takes precedence over any +// information from response headers. +type RateLimiter struct { + window time.Duration + fixedLimit *int + byEndpoint map[string]endpointRateLimiter +} + +// endpointRateLimiter represents rate limiting information for a single API endpoint. +type endpointRateLimiter struct { + limiter *rate.Limiter + ready chan struct{} +} + +// maxWait defines the maximum wait duration allowed for rate limiting. +// Longer waits are considered errors. +const maxWait = 30 * time.Minute + +// NewRateLimiter constructs a new RateLimiter. +// +// Parameters: +// - `window`: The time between API limit resets. Used for setting an initial +// target rate. +// - `fixedLimit`: A fixed number of requests to allow in each `window`, +// overriding the guidance in API responses. +// +// Returns: +// - A pointer to a new RateLimiter instance. +func NewRateLimiter(window time.Duration, fixedLimit *int) *RateLimiter { + endpoints := make(map[string]endpointRateLimiter) + r := RateLimiter{ + window: window, + fixedLimit: fixedLimit, + byEndpoint: endpoints, + } + r.fixedLimit = fixedLimit + return &r +} + +var immediatelyReady = make(chan struct{}) + +func init() { close(immediatelyReady) } + +func (r RateLimiter) endpoint(path string) endpointRateLimiter { + if existing, ok := r.byEndpoint[path]; ok { + return existing + } + limit := rate.Limit(1) + if r.fixedLimit != nil { + limit = rate.Limit(float64(*r.fixedLimit) / r.window.Seconds()) + } + limiter := rate.NewLimiter(limit, 1) // Allow a single fetch operation to obtain limits from the API + newEndpointRateLimiter := endpointRateLimiter{ + limiter: limiter, + ready: immediatelyReady, + } + r.byEndpoint[path] = newEndpointRateLimiter + return newEndpointRateLimiter +} + +func (r RateLimiter) Wait(ctx context.Context, endpoint string, url *url.URL, log *logp.Logger) (err error) { + e := r.endpoint(endpoint) + log.Debugw("rate limit", "limit", e.limiter.Limit(), "burst", e.limiter.Burst(), "url", url.String()) + ctxWithDeadline, cancel := context.WithDeadline(ctx, time.Now().Add(maxWait)) + defer cancel() + select { + case <-e.ready: + case <-ctxWithDeadline.Done(): + return ctxWithDeadline.Err() + } + return e.limiter.Wait(ctxWithDeadline) +} + +// Update implements the Okta rate limit policy translation. +// +// See https://developer.okta.com/docs/reference/rl-best-practices/ for details. +func (r RateLimiter) Update(endpoint string, h http.Header, log *logp.Logger) error { + if r.fixedLimit != nil { + return nil + } + e := r.endpoint(endpoint) + limit := h.Get("X-Rate-Limit-Limit") + remaining := h.Get("X-Rate-Limit-Remaining") + reset := h.Get("X-Rate-Limit-Reset") + log.Debugw("rate limit header", "X-Rate-Limit-Limit", limit, "X-Rate-Limit-Remaining", remaining, "X-Rate-Limit-Reset", reset) + if limit == "" || remaining == "" || reset == "" { + return nil + } + + lim, err := strconv.ParseFloat(limit, 64) + if err != nil { + return err + } + rem, err := strconv.ParseFloat(remaining, 64) + if err != nil { + return err + } + rst, err := strconv.ParseInt(reset, 10, 64) + if err != nil { + return err + } + resetTime := time.Unix(rst, 0) + per := time.Until(resetTime).Seconds() + + // Be conservative here; the docs don't exactly specify burst rates. + // Make sure we can make at least one new request, even if we fail + // to get a non-zero rate.Limit. We could set to zero for the case + // that limit=rate.Inf, but that detail is not important. + burst := 1 + + rateLimit := rate.Limit(rem / per) + + // Process reset if we need to wait until reset to avoid a request against a zero quota. + if rateLimit <= 0 { + // Reset limiter to block requests until reset + limiter := rate.NewLimiter(0, 0) + ready := make(chan struct{}) + newEndpointRateLimiter := endpointRateLimiter{ + limiter: limiter, + ready: ready, + } + r.byEndpoint[endpoint] = newEndpointRateLimiter + + resetTimeUTC := resetTime.UTC() + log.Debugw("rate limit block until reset", "reset_time", resetTimeUTC) + + // next gives us a sane next window estimate, but the + // estimate will be overwritten when we make the next + // permissible API request. + next := rate.Limit(lim / r.window.Seconds()) + waitFor := time.Until(resetTimeUTC) + + time.AfterFunc(waitFor, func() { + limiter.SetLimit(next) + limiter.SetBurst(burst) + close(ready) + log.Debugw("rate limit reset", "reset_time", resetTimeUTC, "reset_rate", next, "reset_burst", burst) + }) + + return nil + } + e.limiter.SetLimit(rateLimit) + e.limiter.SetBurst(burst) + log.Debugw("rate limit adjust", "set_rate", rateLimit, "set_burst", burst) + return nil +} diff --git a/x-pack/filebeat/input/entityanalytics/provider/okta/internal/okta/ratelimiter_test.go b/x-pack/filebeat/input/entityanalytics/provider/okta/internal/okta/ratelimiter_test.go new file mode 100644 index 000000000000..cc8a832bee2e --- /dev/null +++ b/x-pack/filebeat/input/entityanalytics/provider/okta/internal/okta/ratelimiter_test.go @@ -0,0 +1,169 @@ +// 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 okta + +import ( + "context" + "net/http" + "net/url" + "strconv" + "testing" + "time" + + "github.com/elastic/elastic-agent-libs/logp" +) + +func TestRateLimiter(t *testing.T) { + logp.TestingSetup() + + t.Run("separation by endpoint", func(t *testing.T) { + const window = time.Minute + var fixedLimit *int = nil + r := NewRateLimiter(window, fixedLimit) + e1 := r.endpoint("/foo") + e2 := r.endpoint("/bar") + + e1.limiter.SetBurst(1000) + + if e2.limiter.Burst() == 1000 { + t.Errorf("changes to one endpoint's limits affected another") + } + }) + + t.Run("Update stops requests when none are remaining", func(t *testing.T) { + const window = time.Minute + var fixedLimit *int = nil + r := NewRateLimiter(window, fixedLimit) + const endpoint = "/foo" + url, err := url.Parse(endpoint) + if err != nil { + t.Errorf("unexpected error from url.Parse(): %v", err) + } + ctx := context.Background() + log := logp.L() + e := r.endpoint(endpoint) + + if !e.limiter.Allow() { + t.Errorf("doesn't allow an initial request") + } + + // update to none remaining, reset soon + now := time.Now().Unix() + resetSoon := now + 30 + headers := http.Header{ + "X-Rate-Limit-Limit": []string{"60"}, + "X-Rate-Limit-Remaining": []string{"0"}, + "X-Rate-Limit-Reset": []string{strconv.FormatInt(resetSoon, 10)}, + } + err = r.Update(endpoint, headers, logp.L()) + if err != nil { + t.Errorf("unexpected error from Update(): %v", err) + } + e = r.endpoint(endpoint) + + if e.limiter.Allow() { + t.Errorf("allowed a request when none are remaining") + } + if e.limiter.AllowN(time.Unix(resetSoon-1, 999999999), 1) { + t.Errorf("allowed a request before reset, when none are remaining") + } + + // update to none remaining, reset now + headers = http.Header{ + "X-Rate-Limit-Limit": []string{"60"}, + "X-Rate-Limit-Remaining": []string{"0"}, + "X-Rate-Limit-Reset": []string{strconv.FormatInt(now, 10)}, + } + err = r.Update(endpoint, headers, logp.L()) + if err != nil { + t.Errorf("unexpected error from Update(): %v", err) + } + e = r.endpoint(endpoint) + + start := time.Now() + r.Wait(ctx, endpoint, url, log) + wait := time.Since(start) + + if wait > 1010*time.Millisecond { + t.Errorf("doesn't allow requests to resume after reset. had to wait %s", wait) + } + if e.limiter.Limit() != 1.0 { + t.Errorf("unexpected rate following reset (not 60 requests / 60 seconds): %f", e.limiter.Limit()) + } + if e.limiter.Burst() != 1 { + t.Errorf("unexpected burst following reset (not 1): %d", e.limiter.Burst()) + } + + e.limiter.SetBurst(100) // increase bucket size to check token accumulation + tokens := e.limiter.TokensAt(time.Unix(0, time.Now().Add(30*time.Second).UnixNano())) + target := 30.0 + buffer := 0.01 + + if tokens < target-buffer || target+buffer < tokens { + t.Errorf("tokens don't accumulate at the expected rate over 30s: %f", tokens) + } + }) + + t.Run("Very long waits are considered errors", func(t *testing.T) { + const window = time.Minute + var fixedLimit *int = nil + r := NewRateLimiter(window, fixedLimit) + + const endpoint = "/foo" + + url, err := url.Parse(endpoint) + if err != nil { + t.Errorf("unexpected error from url.Parse(): %v", err) + } + reset := time.Now().Add(31 * time.Minute).Unix() + headers := http.Header{ + "X-Rate-Limit-Limit": []string{"60"}, + "X-Rate-Limit-Remaining": []string{"1"}, + "X-Rate-Limit-Reset": []string{strconv.FormatInt(reset, 10)}, + } + log := logp.L() + ctx := context.Background() + + r.Wait(ctx, endpoint, url, log) // consume the initial request + r.Update(endpoint, headers, log) // update to a slow rate + + err = r.Wait(ctx, endpoint, url, log) + + const expectedErr = "rate: Wait(n=1) would exceed context deadline" + if err == nil { + t.Errorf("expected error message %q, but got no error", expectedErr) + } else if err.Error() != expectedErr { + t.Errorf("expected error message %q, but got %q", expectedErr, err.Error()) + } + }) + + t.Run("A fixed limit overrides response information", func(t *testing.T) { + const window = time.Minute + var fixedLimit int = 120 + r := NewRateLimiter(window, &fixedLimit) + const endpoint = "/foo" + e := r.endpoint(endpoint) + + if e.limiter.Limit() != 120/60 { + t.Errorf("unexpected rate (for fixed 120 reqs / 60 secs): %f", e.limiter.Limit()) + } + + // update to 15 requests remaining, reset in 30s + headers := http.Header{ + "X-Rate-Limit-Limit": []string{"60"}, + "X-Rate-Limit-Remaining": []string{"15"}, + "X-Rate-Limit-Reset": []string{strconv.FormatInt(time.Now().Unix()+30, 10)}, + } + err := r.Update(endpoint, headers, logp.L()) + if err != nil { + t.Errorf("unexpected error from Update(): %v", err) + } + e = r.endpoint(endpoint) + + if e.limiter.Limit() != 120/60 { + t.Errorf("unexpected rate following Update() (for fixed 120 reqs / 60 secs): %f", e.limiter.Limit()) + } + }) +} diff --git a/x-pack/filebeat/input/entityanalytics/provider/okta/okta.go b/x-pack/filebeat/input/entityanalytics/provider/okta/okta.go index 5d68cf3f5c4a..0e33e93cc9b9 100644 --- a/x-pack/filebeat/input/entityanalytics/provider/okta/okta.go +++ b/x-pack/filebeat/input/entityanalytics/provider/okta/okta.go @@ -23,7 +23,6 @@ import ( "go.elastic.co/ecszap" "go.uber.org/zap" "go.uber.org/zap/zapcore" - "golang.org/x/time/rate" v2 "github.com/elastic/beats/v7/filebeat/input/v2" "github.com/elastic/beats/v7/libbeat/beat" @@ -60,7 +59,7 @@ type oktaInput struct { cfg conf client *http.Client - lim *rate.Limiter + lim *okta.RateLimiter metrics *inputMetrics logger *logp.Logger @@ -111,7 +110,7 @@ func (p *oktaInput) Run(inputCtx v2.Context, store *kvstore.Store, client beat.C updateTimer := time.NewTimer(updateWaitTime) // Allow a single fetch operation to obtain limits from the API. - p.lim = rate.NewLimiter(1, 1) + p.lim = okta.NewRateLimiter(p.cfg.LimitWindow, p.cfg.LimitFixed) if p.cfg.Tracer != nil { id := sanitizeFileName(inputCtx.IDWithoutName) @@ -452,7 +451,7 @@ func (p *oktaInput) doFetchUsers(ctx context.Context, state *stateStore, fullSyn lastUpdated time.Time ) for { - batch, h, err := okta.GetUserDetails(ctx, p.client, p.cfg.OktaDomain, p.cfg.OktaToken, "", query, omit, p.lim, p.cfg.LimitWindow, p.logger) + batch, h, err := okta.GetUserDetails(ctx, p.client, p.cfg.OktaDomain, p.cfg.OktaToken, "", query, omit, p.lim, p.logger) if err != nil { p.logger.Debugf("received %d users from API", len(users)) return nil, err @@ -513,7 +512,7 @@ func (p *oktaInput) addUserMetadata(ctx context.Context, u okta.User, state *sta return su } if slices.Contains(p.cfg.EnrichWith, "groups") { - groups, _, err := okta.GetUserGroupDetails(ctx, p.client, p.cfg.OktaDomain, p.cfg.OktaToken, u.ID, p.lim, p.cfg.LimitWindow, p.logger) + groups, _, err := okta.GetUserGroupDetails(ctx, p.client, p.cfg.OktaDomain, p.cfg.OktaToken, u.ID, p.lim, p.logger) if err != nil { p.logger.Warnf("failed to get user group membership for %s: %v", u.ID, err) } else { @@ -521,7 +520,7 @@ func (p *oktaInput) addUserMetadata(ctx context.Context, u okta.User, state *sta } } if slices.Contains(p.cfg.EnrichWith, "factors") { - factors, _, err := okta.GetUserFactors(ctx, p.client, p.cfg.OktaDomain, p.cfg.OktaToken, u.ID, p.lim, p.cfg.LimitWindow, p.logger) + factors, _, err := okta.GetUserFactors(ctx, p.client, p.cfg.OktaDomain, p.cfg.OktaToken, u.ID, p.lim, p.logger) if err != nil { p.logger.Warnf("failed to get user factors for %s: %v", u.ID, err) } else { @@ -529,7 +528,7 @@ func (p *oktaInput) addUserMetadata(ctx context.Context, u okta.User, state *sta } } if slices.Contains(p.cfg.EnrichWith, "roles") { - roles, _, err := okta.GetUserRoles(ctx, p.client, p.cfg.OktaDomain, p.cfg.OktaToken, u.ID, p.lim, p.cfg.LimitWindow, p.logger) + roles, _, err := okta.GetUserRoles(ctx, p.client, p.cfg.OktaDomain, p.cfg.OktaToken, u.ID, p.lim, p.logger) if err != nil { p.logger.Warnf("failed to get user roles for %s: %v", u.ID, err) } else { @@ -581,7 +580,7 @@ func (p *oktaInput) doFetchDevices(ctx context.Context, state *stateStore, fullS lastUpdated time.Time ) for { - batch, h, err := okta.GetDeviceDetails(ctx, p.client, p.cfg.OktaDomain, p.cfg.OktaToken, "", deviceQuery, p.lim, p.cfg.LimitWindow, p.logger) + batch, h, err := okta.GetDeviceDetails(ctx, p.client, p.cfg.OktaDomain, p.cfg.OktaToken, "", deviceQuery, p.lim, p.logger) if err != nil { p.logger.Debugf("received %d devices from API", len(devices)) return nil, err @@ -600,7 +599,7 @@ func (p *oktaInput) doFetchDevices(ctx context.Context, state *stateStore, fullS const omit = okta.OmitCredentials | okta.OmitCredentialsLinks | okta.OmitTransitioningToStatus - users, h, err := okta.GetDeviceUsers(ctx, p.client, p.cfg.OktaDomain, p.cfg.OktaToken, d.ID, userQuery, omit, p.lim, p.cfg.LimitWindow, p.logger) + users, h, err := okta.GetDeviceUsers(ctx, p.client, p.cfg.OktaDomain, p.cfg.OktaToken, d.ID, userQuery, omit, p.lim, p.logger) if err != nil { p.logger.Debugf("received %d device users from API", len(users)) return nil, err diff --git a/x-pack/filebeat/input/entityanalytics/provider/okta/okta_test.go b/x-pack/filebeat/input/entityanalytics/provider/okta/okta_test.go index 5752370c4ce2..ea2a710d8c51 100644 --- a/x-pack/filebeat/input/entityanalytics/provider/okta/okta_test.go +++ b/x-pack/filebeat/input/entityanalytics/provider/okta/okta_test.go @@ -18,7 +18,6 @@ import ( "testing" "time" - "golang.org/x/time/rate" "gopkg.in/natefinch/lumberjack.v2" "github.com/elastic/beats/v7/x-pack/filebeat/input/entityanalytics/provider/okta/internal/okta" @@ -177,6 +176,7 @@ func TestOktaDoFetch(t *testing.T) { if err != nil { t.Errorf("failed to parse server URL: %v", err) } + rateLimiter := okta.NewRateLimiter(window, nil) a := oktaInput{ cfg: conf{ OktaDomain: u.Host, @@ -185,7 +185,7 @@ func TestOktaDoFetch(t *testing.T) { EnrichWith: test.enrichWith, }, client: ts.Client(), - lim: rate.NewLimiter(1, 1), + lim: rateLimiter, logger: logp.L(), } if *trace { diff --git a/x-pack/filebeat/input/gcppubsub/pubsub_test.go b/x-pack/filebeat/input/gcppubsub/pubsub_test.go index 7981a3ee7724..16fdbf1ebbd1 100644 --- a/x-pack/filebeat/input/gcppubsub/pubsub_test.go +++ b/x-pack/filebeat/input/gcppubsub/pubsub_test.go @@ -12,6 +12,7 @@ import ( "os" "strconv" "sync" + "sync/atomic" "testing" "time" @@ -23,7 +24,6 @@ import ( "github.com/elastic/beats/v7/filebeat/channel" "github.com/elastic/beats/v7/filebeat/input" "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/common/atomic" "github.com/elastic/beats/v7/libbeat/tests/compose" "github.com/elastic/beats/v7/libbeat/tests/resources" conf "github.com/elastic/elastic-agent-libs/config" @@ -247,6 +247,7 @@ func runTestWithACKer(t *testing.T, cfg *conf.C, onEvent eventHandler, run func( if err != nil { t.Fatal(err) } + //nolint:errcheck // ignore pubsubInput := in.(*pubsubInput) defer pubsubInput.Stop() @@ -421,13 +422,14 @@ func TestRunStop(t *testing.T) { func TestEndToEndACK(t *testing.T) { cfg := defaultTestConfig() - var count atomic.Int + var count atomic.Int64 seen := make(map[string]struct{}) // ACK every other message halfAcker := func(ev beat.Event, clientConfig beat.ClientConfig) bool { + //nolint:errcheck // ignore msg := ev.Private.(*pubsub.Message) seen[msg.ID] = struct{}{} - if count.Inc()&1 != 0 { + if count.Add(1)&1 != 0 { // Nack will result in the Message being redelivered more quickly than if it were allowed to expire. msg.Nack() return false @@ -453,6 +455,7 @@ func TestEndToEndACK(t *testing.T) { assert.Len(t, events, len(seen)) got := make(map[string]struct{}) for _, ev := range events { + //nolint:errcheck // ignore msg := ev.Private.(*pubsub.Message) got[msg.ID] = struct{}{} } diff --git a/x-pack/filebeat/input/gcs/client.go b/x-pack/filebeat/input/gcs/client.go index 7fd45d2d0a9c..1846e08c5ab0 100644 --- a/x-pack/filebeat/input/gcs/client.go +++ b/x-pack/filebeat/input/gcs/client.go @@ -12,11 +12,9 @@ import ( "cloud.google.com/go/storage" "golang.org/x/oauth2/google" "google.golang.org/api/option" - - "github.com/elastic/elastic-agent-libs/logp" ) -func fetchStorageClient(ctx context.Context, cfg config, log *logp.Logger) (*storage.Client, error) { +func fetchStorageClient(ctx context.Context, cfg config) (*storage.Client, error) { if cfg.AlternativeHost != "" { var h *url.URL h, err := url.Parse(cfg.AlternativeHost) diff --git a/x-pack/filebeat/input/gcs/config.go b/x-pack/filebeat/input/gcs/config.go index 6a7b93d5e479..3c8f2d02a7c7 100644 --- a/x-pack/filebeat/input/gcs/config.go +++ b/x-pack/filebeat/input/gcs/config.go @@ -28,16 +28,14 @@ type config struct { // Auth - Defines the authentication mechanism to be used for accessing the gcs bucket. Auth authConfig `config:"auth"` // MaxWorkers - Defines the maximum number of go routines that will be spawned. - MaxWorkers *int `config:"max_workers,omitempty" validate:"max=5000"` + MaxWorkers int `config:"max_workers" validate:"max=5000"` // Poll - Defines if polling should be performed on the input bucket source. - Poll *bool `config:"poll,omitempty"` + Poll bool `config:"poll"` // PollInterval - Defines the maximum amount of time to wait before polling for the next batch of objects from the bucket. - PollInterval *time.Duration `config:"poll_interval,omitempty"` + PollInterval time.Duration `config:"poll_interval"` // ParseJSON - Informs the publisher whether to parse & objectify json data or not. By default this is set to // false, since it can get expensive dealing with highly nested json data. - ParseJSON *bool `config:"parse_json,omitempty"` - // BucketTimeOut - Defines the maximum time that the sdk will wait for a bucket api response before timing out. - BucketTimeOut *time.Duration `config:"bucket_timeout,omitempty"` + ParseJSON bool `config:"parse_json"` // Buckets - Defines a list of buckets that will be polled for objects. Buckets []bucket `config:"buckets" validate:"required"` // FileSelectors - Defines a list of regex patterns that can be used to filter out objects from the bucket. @@ -49,17 +47,18 @@ type config struct { // ExpandEventListFromField - Defines the field name that will be used to expand the event into separate events. ExpandEventListFromField string `config:"expand_event_list_from_field"` // This field is only used for system test purposes, to override the HTTP endpoint. - AlternativeHost string `config:"alternative_host,omitempty"` + AlternativeHost string `config:"alternative_host"` + // Retry - Defines the retry configuration for the input. + Retry retryConfig `config:"retry"` } // bucket contains the config for each specific object storage bucket in the root account type bucket struct { Name string `config:"name" validate:"required"` - MaxWorkers *int `config:"max_workers,omitempty" validate:"max=5000"` - BucketTimeOut *time.Duration `config:"bucket_timeout,omitempty"` - Poll *bool `config:"poll,omitempty"` - PollInterval *time.Duration `config:"poll_interval,omitempty"` - ParseJSON *bool `config:"parse_json,omitempty"` + MaxWorkers *int `config:"max_workers" validate:"max=5000"` + Poll *bool `config:"poll"` + PollInterval *time.Duration `config:"poll_interval"` + ParseJSON *bool `config:"parse_json"` FileSelectors []fileSelectorConfig `config:"file_selectors"` ReaderConfig readerConfig `config:",inline"` TimeStampEpoch *int64 `config:"timestamp_epoch"` @@ -78,18 +77,33 @@ type readerConfig struct { Decoding decoderConfig `config:"decoding"` } +// authConfig defines the authentication mechanism to be used for accessing the gcs bucket. +// If either is configured the 'omitempty' tag will prevent the other option from being serialized in the config. type authConfig struct { CredentialsJSON *jsonCredentialsConfig `config:"credentials_json,omitempty"` CredentialsFile *fileCredentialsConfig `config:"credentials_file,omitempty"` } type fileCredentialsConfig struct { - Path string `config:"path,omitempty"` + Path string `config:"path"` } type jsonCredentialsConfig struct { AccountKey string `config:"account_key"` } +type retryConfig struct { + // MaxAttempts configures the maximum number of times an API call can be made in the case of retryable errors. + // For example, if you set MaxAttempts(5), the operation will be attempted up to 5 times total (initial call plus 4 retries). + // If you set MaxAttempts(1), the operation will be attempted only once and there will be no retries. This setting defaults to 3. + MaxAttempts int `config:"max_attempts" validate:"min=1"` + // InitialBackOffDuration is the initial value of the retry period, defaults to 1 second. + InitialBackOffDuration time.Duration `config:"initial_backoff_duration" validate:"min=1"` + // MaxBackOffDuration is the maximum value of the retry period, defaults to 30 seconds. + MaxBackOffDuration time.Duration `config:"max_backoff_duration" validate:"min=2"` + // BackOffMultiplier is the factor by which the retry period increases. It should be greater than 1 and defaults to 2. + BackOffMultiplier float64 `config:"backoff_multiplier" validate:"min=1.1"` +} + func (c authConfig) Validate() error { // credentials_file if c.CredentialsFile != nil { @@ -115,3 +129,19 @@ func (c authConfig) Validate() error { return fmt.Errorf("no authentication credentials were configured or detected " + "(credentials_file, credentials_json, and application default credentials (ADC))") } + +// defaultConfig returns the default configuration for the input +func defaultConfig() config { + return config{ + MaxWorkers: 1, + Poll: true, + PollInterval: 5 * time.Minute, + ParseJSON: false, + Retry: retryConfig{ + MaxAttempts: 3, + InitialBackOffDuration: time.Second, + MaxBackOffDuration: 30 * time.Second, + BackOffMultiplier: 2, + }, + } +} diff --git a/x-pack/filebeat/input/gcs/decoding_test.go b/x-pack/filebeat/input/gcs/decoding_test.go index 0a2ee5e3f0d7..a57fe62a5ed6 100644 --- a/x-pack/filebeat/input/gcs/decoding_test.go +++ b/x-pack/filebeat/input/gcs/decoding_test.go @@ -79,7 +79,7 @@ func TestDecoding(t *testing.T) { } defer f.Close() p := &pub{t: t} - j := newJob(&storage.BucketHandle{}, &storage.ObjectAttrs{Name: "test_object"}, "gs://test_uri", newState(), &Source{}, p, log, false) + j := newJob(&storage.BucketHandle{}, &storage.ObjectAttrs{Name: "test_object"}, "gs://test_uri", newState(), &Source{}, p, nil, log, false) j.src.ReaderConfig.Decoding = tc.config err = j.decode(context.Background(), f, "test") if err != nil { diff --git a/x-pack/filebeat/input/gcs/input.go b/x-pack/filebeat/input/gcs/input.go index a2ecf2c28afc..77580f70e401 100644 --- a/x-pack/filebeat/input/gcs/input.go +++ b/x-pack/filebeat/input/gcs/input.go @@ -50,7 +50,7 @@ func Plugin(log *logp.Logger, store cursor.StateStore) v2.Plugin { } func configure(cfg *conf.C) ([]cursor.Source, cursor.Input, error) { - config := config{} + config := defaultConfig() if err := cfg.Unpack(&config); err != nil { return nil, nil, err } @@ -63,7 +63,6 @@ func configure(cfg *conf.C) ([]cursor.Source, cursor.Input, error) { sources = append(sources, &Source{ ProjectId: config.ProjectId, BucketName: bucket.Name, - BucketTimeOut: *bucket.BucketTimeOut, MaxWorkers: *bucket.MaxWorkers, Poll: *bucket.Poll, PollInterval: *bucket.PollInterval, @@ -72,50 +71,26 @@ func configure(cfg *conf.C) ([]cursor.Source, cursor.Input, error) { ExpandEventListFromField: bucket.ExpandEventListFromField, FileSelectors: bucket.FileSelectors, ReaderConfig: bucket.ReaderConfig, + Retry: config.Retry, }) } return sources, &gcsInput{config: config}, nil } -// tryOverrideOrDefault, overrides global values with local -// bucket level values if present. If both global & local values -// are absent, assigns default values +// tryOverrideOrDefault, overrides the bucket level values with global values if the bucket fields are not set func tryOverrideOrDefault(cfg config, b bucket) bucket { if b.MaxWorkers == nil { - maxWorkers := 1 - if cfg.MaxWorkers != nil { - maxWorkers = *cfg.MaxWorkers - } - b.MaxWorkers = &maxWorkers + b.MaxWorkers = &cfg.MaxWorkers } if b.Poll == nil { - var poll bool - if cfg.Poll != nil { - poll = *cfg.Poll - } - b.Poll = &poll + b.Poll = &cfg.Poll } if b.PollInterval == nil { - interval := time.Second * 300 - if cfg.PollInterval != nil { - interval = *cfg.PollInterval - } - b.PollInterval = &interval + b.PollInterval = &cfg.PollInterval } if b.ParseJSON == nil { - parse := false - if cfg.ParseJSON != nil { - parse = *cfg.ParseJSON - } - b.ParseJSON = &parse - } - if b.BucketTimeOut == nil { - timeOut := time.Second * 50 - if cfg.BucketTimeOut != nil { - timeOut = *cfg.BucketTimeOut - } - b.BucketTimeOut = &timeOut + b.ParseJSON = &cfg.ParseJSON } if b.TimeStampEpoch == nil { b.TimeStampEpoch = cfg.TimeStampEpoch @@ -152,9 +127,15 @@ func (input *gcsInput) Run(inputCtx v2.Context, src cursor.Source, log := inputCtx.Logger.With("project_id", currentSource.ProjectId).With("bucket", currentSource.BucketName) log.Infof("Running google cloud storage for project: %s", input.config.ProjectId) + // create a new inputMetrics instance + metrics := newInputMetrics(inputCtx.ID+":"+currentSource.BucketName, nil) + metrics.url.Set("gs://" + currentSource.BucketName) + defer metrics.Close() + var cp *Checkpoint if !cursor.IsNew() { if err := cursor.Unpack(&cp); err != nil { + metrics.errorsTotal.Inc() return err } @@ -167,20 +148,26 @@ func (input *gcsInput) Run(inputCtx v2.Context, src cursor.Source, cancel() }() - client, err := fetchStorageClient(ctx, input.config, log) + client, err := fetchStorageClient(ctx, input.config) if err != nil { + metrics.errorsTotal.Inc() return err } + bucket := client.Bucket(currentSource.BucketName).Retryer( + // Use WithMaxAttempts to change the maximum number of attempts. + storage.WithMaxAttempts(currentSource.Retry.MaxAttempts), // Use WithBackoff to change the timing of the exponential backoff. storage.WithBackoff(gax.Backoff{ - Initial: 2 * time.Second, + Initial: currentSource.Retry.InitialBackOffDuration, + Max: currentSource.Retry.MaxBackOffDuration, + Multiplier: currentSource.Retry.BackOffMultiplier, }), // RetryAlways will retry the operation even if it is non-idempotent. // Since we are only reading, the operation is always idempotent storage.WithPolicy(storage.RetryAlways), ) - scheduler := newScheduler(publisher, bucket, currentSource, &input.config, st, log) + scheduler := newScheduler(publisher, bucket, currentSource, &input.config, st, metrics, log) return scheduler.schedule(ctx) } diff --git a/x-pack/filebeat/input/gcs/input_stateless.go b/x-pack/filebeat/input/gcs/input_stateless.go index 3cdeb3794739..bceb7dffb54d 100644 --- a/x-pack/filebeat/input/gcs/input_stateless.go +++ b/x-pack/filebeat/input/gcs/input_stateless.go @@ -6,7 +6,6 @@ package gcs import ( "context" - "time" "cloud.google.com/go/storage" gax "github.com/googleapis/gax-go/v2" @@ -49,12 +48,12 @@ func (in *statelessInput) Run(inputCtx v2.Context, publisher stateless.Publisher pub := statelessPublisher{wrapped: publisher} var source cursor.Source var g errgroup.Group + for _, b := range in.config.Buckets { bucket := tryOverrideOrDefault(in.config, b) source = &Source{ ProjectId: in.config.ProjectId, BucketName: bucket.Name, - BucketTimeOut: *bucket.BucketTimeOut, MaxWorkers: *bucket.MaxWorkers, Poll: *bucket.Poll, PollInterval: *bucket.PollInterval, @@ -63,11 +62,15 @@ func (in *statelessInput) Run(inputCtx v2.Context, publisher stateless.Publisher ExpandEventListFromField: bucket.ExpandEventListFromField, FileSelectors: bucket.FileSelectors, ReaderConfig: bucket.ReaderConfig, + Retry: in.config.Retry, } st := newState() currentSource := source.(*Source) log := inputCtx.Logger.With("project_id", currentSource.ProjectId).With("bucket", currentSource.BucketName) + metrics := newInputMetrics(inputCtx.ID+":"+currentSource.BucketName, nil) + defer metrics.Close() + metrics.url.Set("gs://" + currentSource.BucketName) ctx, cancel := context.WithCancel(context.Background()) go func() { @@ -76,16 +79,19 @@ func (in *statelessInput) Run(inputCtx v2.Context, publisher stateless.Publisher }() bkt := client.Bucket(currentSource.BucketName).Retryer( + // Use WithMaxAttempts to change the maximum number of attempts. + storage.WithMaxAttempts(currentSource.Retry.MaxAttempts), // Use WithBackoff to change the timing of the exponential backoff. storage.WithBackoff(gax.Backoff{ - Initial: 2 * time.Second, + Initial: currentSource.Retry.InitialBackOffDuration, + Max: currentSource.Retry.MaxBackOffDuration, + Multiplier: currentSource.Retry.BackOffMultiplier, }), // RetryAlways will retry the operation even if it is non-idempotent. // Since we are only reading, the operation is always idempotent storage.WithPolicy(storage.RetryAlways), ) - - scheduler := newScheduler(pub, bkt, currentSource, &in.config, st, log) + scheduler := newScheduler(pub, bkt, currentSource, &in.config, st, metrics, log) // allows multiple containers to be scheduled concurrently while testing // the stateless input is triggered only while testing and till now it did not mimic // the real world concurrent execution of multiple containers. This fix allows it to do so. diff --git a/x-pack/filebeat/input/gcs/input_test.go b/x-pack/filebeat/input/gcs/input_test.go index 64a548afd8c3..8ff0576bdf5e 100644 --- a/x-pack/filebeat/input/gcs/input_test.go +++ b/x-pack/filebeat/input/gcs/input_test.go @@ -6,7 +6,9 @@ package gcs import ( "context" + "crypto/rand" "crypto/tls" + "encoding/hex" "errors" "fmt" "net/http" @@ -518,6 +520,78 @@ func Test_StorageClient(t *testing.T) { mock.Gcs_test_new_object_docs_ata_json: true, }, }, + { + name: "RetryWithDefaultValues", + baseConfig: map[string]interface{}{ + "project_id": "elastic-sa", + "auth.credentials_file.path": "testdata/gcs_creds.json", + "max_workers": 1, + "poll": true, + "poll_interval": "1m", + "buckets": []map[string]interface{}{ + { + "name": "gcs-test-new", + }, + }, + }, + mockHandler: mock.GCSRetryServer, + expected: map[string]bool{ + mock.Gcs_test_new_object_ata_json: true, + mock.Gcs_test_new_object_data3_json: true, + mock.Gcs_test_new_object_docs_ata_json: true, + }, + }, + { + name: "RetryWithCustomValues", + baseConfig: map[string]interface{}{ + "project_id": "elastic-sa", + "auth.credentials_file.path": "testdata/gcs_creds.json", + "max_workers": 1, + "poll": true, + "poll_interval": "10s", + "retry": map[string]interface{}{ + "max_attempts": 5, + "initial_backoff_duration": "1s", + "max_backoff_duration": "3s", + "backoff_multiplier": 1.4, + }, + "buckets": []map[string]interface{}{ + { + "name": "gcs-test-new", + }, + }, + }, + mockHandler: mock.GCSRetryServer, + expected: map[string]bool{ + mock.Gcs_test_new_object_ata_json: true, + mock.Gcs_test_new_object_data3_json: true, + mock.Gcs_test_new_object_docs_ata_json: true, + }, + }, + { + name: "RetryMinimumValueCheck", + baseConfig: map[string]interface{}{ + "project_id": "elastic-sa", + "auth.credentials_file.path": "testdata/gcs_creds.json", + "max_workers": 1, + "poll": true, + "poll_interval": "10s", + "retry": map[string]interface{}{ + "max_attempts": 5, + "initial_backoff_duration": "1s", + "max_backoff_duration": "3s", + "backoff_multiplier": 1, + }, + "buckets": []map[string]interface{}{ + { + "name": "gcs-test-new", + }, + }, + }, + mockHandler: mock.GCSRetryServer, + expected: map[string]bool{}, + isError: errors.New("requires value >= 1.1 accessing 'retry.backoff_multiplier'"), + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -533,7 +607,7 @@ func Test_StorageClient(t *testing.T) { client, _ := storage.NewClient(context.Background(), option.WithEndpoint(serv.URL), option.WithoutAuthentication(), option.WithHTTPClient(&httpclient)) cfg := conf.MustNewConfigFrom(tt.baseConfig) - conf := config{} + conf := defaultConfig() err := cfg.Unpack(&conf) if err != nil { assert.EqualError(t, err, fmt.Sprint(tt.isError)) @@ -547,7 +621,7 @@ func Test_StorageClient(t *testing.T) { chanClient := beattest.NewChanClient(len(tt.expected)) t.Cleanup(func() { _ = chanClient.Close() }) - ctx, cancel := newV2Context() + ctx, cancel := newV2Context(t) t.Cleanup(cancel) var g errgroup.Group @@ -556,8 +630,8 @@ func Test_StorageClient(t *testing.T) { }) var timeout *time.Timer - if conf.PollInterval != nil { - timeout = time.NewTimer(1*time.Second + *conf.PollInterval) + if conf.PollInterval != 0 { + timeout = time.NewTimer(1*time.Second + conf.PollInterval) } else { timeout = time.NewTimer(5 * time.Second) } @@ -607,11 +681,23 @@ func Test_StorageClient(t *testing.T) { } } -func newV2Context() (v2.Context, func()) { +func newV2Context(t *testing.T) (v2.Context, func()) { ctx, cancel := context.WithCancel(context.Background()) + id, err := generateRandomID(8) + if err != nil { + t.Fatalf("failed to generate random id: %v", err) + } return v2.Context{ Logger: logp.NewLogger("gcs_test"), - ID: "test_id", + ID: "gcs_test-" + id, Cancelation: ctx, }, cancel } + +func generateRandomID(length int) (string, error) { + bytes := make([]byte, length) + if _, err := rand.Read(bytes); err != nil { + return "", err + } + return hex.EncodeToString(bytes), nil +} diff --git a/x-pack/filebeat/input/gcs/job.go b/x-pack/filebeat/input/gcs/job.go index 403555311e9d..6de97561b3c0 100644 --- a/x-pack/filebeat/input/gcs/job.go +++ b/x-pack/filebeat/input/gcs/job.go @@ -45,6 +45,8 @@ type job struct { src *Source // publisher is used to publish a beat event to the output stream publisher cursor.Publisher + // metrics used to track the errors and success of jobs + metrics *inputMetrics // custom logger log *logp.Logger // flag used to denote if this object has previously failed without being processed at all. @@ -53,8 +55,12 @@ type job struct { // newJob, returns an instance of a job, which is a unit of work that can be assigned to a go routine func newJob(bucket *storage.BucketHandle, object *storage.ObjectAttrs, objectURI string, - state *state, src *Source, publisher cursor.Publisher, log *logp.Logger, isFailed bool, + state *state, src *Source, publisher cursor.Publisher, metrics *inputMetrics, log *logp.Logger, isFailed bool, ) *job { + if metrics == nil { + // metrics are optional, initialize a stub if not provided + metrics = newInputMetrics("", nil) + } return &job{ bucket: bucket, object: object, @@ -63,6 +69,7 @@ func newJob(bucket *storage.BucketHandle, object *storage.ObjectAttrs, objectURI state: state, src: src, publisher: publisher, + metrics: metrics, log: log, isFailed: isFailed, } @@ -78,6 +85,17 @@ func gcsObjectHash(src *Source, object *storage.ObjectAttrs) string { func (j *job) do(ctx context.Context, id string) { var fields mapstr.M + // metrics & logging + j.log.Debug("begin gcs object processing.") + j.metrics.gcsObjectsRequestedTotal.Inc() + j.metrics.gcsObjectsInflight.Inc() + start := time.Now() + defer func() { + elapsed := time.Since(start) + j.metrics.gcsObjectsInflight.Dec() + j.metrics.gcsObjectProcessingTime.Update(elapsed.Nanoseconds()) + j.log.Debugw("end gcs object processing.", "elapsed_time_ns", elapsed) + }() if allowedContentTypes[j.object.ContentType] { if j.object.ContentType == gzType || j.object.ContentEncoding == encodingGzip { @@ -85,10 +103,15 @@ func (j *job) do(ctx context.Context, id string) { } err := j.processAndPublishData(ctx, id) if err != nil { - j.state.updateFailedJobs(j.object.Name) + j.state.updateFailedJobs(j.object.Name, j.metrics) j.log.Errorw("job encountered an error while publishing data and has been added to a failed jobs list", "gcs.jobId", id, "error", err) + j.metrics.gcsFailedJobsTotal.Inc() + j.metrics.errorsTotal.Inc() return } + j.metrics.gcsObjectsPublishedTotal.Inc() + //nolint:gosec // object size cannot be negative hence this conversion is safe + j.metrics.gcsBytesProcessedTotal.Add(uint64(j.object.Size)) } else { err := fmt.Errorf("job with jobId %s encountered an error: content-type %s not supported", id, j.object.ContentType) @@ -101,9 +124,10 @@ func (j *job) do(ctx context.Context, id string) { } event.SetID(objectID(j.hash, 0)) // locks while data is being saved and published to avoid concurrent map read/writes - cp, done := j.state.saveForTx(j.object.Name, j.object.Updated) + cp, done := j.state.saveForTx(j.object.Name, j.object.Updated, j.metrics) if err := j.publisher.Publish(event, cp); err != nil { j.log.Errorw("job encountered an error while publishing event", "gcs.jobId", id, "error", err) + j.metrics.errorsTotal.Inc() } // unlocks after data is saved and published done() @@ -123,21 +147,29 @@ func (j *job) Timestamp() time.Time { } func (j *job) processAndPublishData(ctx context.Context, id string) error { - ctxWithTimeout, cancel := context.WithTimeout(ctx, j.src.BucketTimeOut) - defer cancel() obj := j.bucket.Object(j.object.Name) - reader, err := obj.NewReader(ctxWithTimeout) + reader, err := obj.NewReader(ctx) if err != nil { return fmt.Errorf("failed to open reader for object: %s, with error: %w", j.object.Name, err) } defer func() { err = reader.Close() if err != nil { + j.metrics.errorsTotal.Inc() j.log.Errorw("failed to close reader for object", "objectName", j.object.Name, "error", err) } }() - return j.decode(ctx, reader, id) + // update the source lag time metric + j.metrics.sourceLagTime.Update(time.Since(j.object.Updated).Nanoseconds()) + + // calculate number of decode errors + if err := j.decode(ctx, reader, id); err != nil { + j.metrics.decodeErrorsTotal.Inc() + return fmt.Errorf("failed to decode object: %s, with error: %w", j.object.Name, err) + } + + return nil } func (j *job) decode(ctx context.Context, r io.Reader, id string) error { @@ -241,17 +273,24 @@ func (j *job) readJsonAndPublish(ctx context.Context, r io.Reader, id string) er // if expand_event_list_from_field is set, then split the event list if j.src.ExpandEventListFromField != "" { - if err := j.splitEventList(j.src.ExpandEventListFromField, item, offset, j.hash, id); err != nil { + if numEvents, err := j.splitEventList(j.src.ExpandEventListFromField, item, offset, id); err != nil { return err + } else { + j.metrics.gcsEventsPerObject.Update(int64(numEvents)) } continue + } else { + j.metrics.gcsEventsPerObject.Update(1) } var parsedData []mapstr.M if j.src.ParseJSON { parsedData, err = decodeJSON(bytes.NewReader(item)) if err != nil { - j.log.Errorw("job encountered an error", "gcs.jobId", id, "error", err) + // since we do not want to stop processing the job here as this is purely cosmetic and optional, we log the error and continue + j.metrics.errorsTotal.Inc() + j.metrics.decodeErrorsTotal.Inc() + j.log.Errorw("job encountered an error during 'ParseJSON' op", "gcs.jobId", id, "error", err) } } evt := j.createEvent(item, parsedData, offset) @@ -263,8 +302,9 @@ func (j *job) readJsonAndPublish(ctx context.Context, r io.Reader, id string) er func (j *job) publish(evt beat.Event, last bool, id string) { if last { // if this is the last object, then perform a complete state save - cp, done := j.state.saveForTx(j.object.Name, j.object.Updated) + cp, done := j.state.saveForTx(j.object.Name, j.object.Updated, j.metrics) if err := j.publisher.Publish(evt, cp); err != nil { + j.metrics.errorsTotal.Inc() j.log.Errorw("job encountered an error while publishing event", "gcs.jobId", id, "error", err) } done() @@ -272,20 +312,22 @@ func (j *job) publish(evt beat.Event, last bool, id string) { } // since we don't update the cursor checkpoint, lack of a lock here is not a problem if err := j.publisher.Publish(evt, nil); err != nil { + j.metrics.errorsTotal.Inc() j.log.Errorw("job encountered an error while publishing event", "gcs.jobId", id, "error", err) } } // splitEventList splits the event list into individual events and publishes them -func (j *job) splitEventList(key string, raw json.RawMessage, offset int64, objHash string, id string) error { +func (j *job) splitEventList(key string, raw json.RawMessage, offset int64, id string) (int, error) { var jsonObject map[string]json.RawMessage + var eventsPerObject int if err := json.Unmarshal(raw, &jsonObject); err != nil { - return fmt.Errorf("job with job id %s encountered an unmarshaling error: %w", id, err) + return eventsPerObject, fmt.Errorf("job with job id %s encountered an unmarshaling error: %w", id, err) } raw, found := jsonObject[key] if !found { - return fmt.Errorf("expand_event_list_from_field key <%v> is not in event", key) + return eventsPerObject, fmt.Errorf("expand_event_list_from_field key <%v> is not in event", key) } dec := json.NewDecoder(bytes.NewReader(raw)) @@ -294,11 +336,11 @@ func (j *job) splitEventList(key string, raw json.RawMessage, offset int64, objH tok, err := dec.Token() if err != nil { - return fmt.Errorf("failed to read JSON token for object: %s, with error: %w", j.object.Name, err) + return eventsPerObject, fmt.Errorf("failed to read JSON token for object: %s, with error: %w", j.object.Name, err) } delim, ok := tok.(json.Delim) if !ok || delim != '[' { - return fmt.Errorf("expand_event_list_from_field <%v> is not an array", key) + return eventsPerObject, fmt.Errorf("expand_event_list_from_field <%v> is not an array", key) } for dec.More() { @@ -306,31 +348,34 @@ func (j *job) splitEventList(key string, raw json.RawMessage, offset int64, objH var item json.RawMessage if err := dec.Decode(&item); err != nil { - return fmt.Errorf("failed to decode array item at offset %d: %w", offset+arrayOffset, err) + return eventsPerObject, fmt.Errorf("failed to decode array item at offset %d: %w", offset+arrayOffset, err) } data, err := item.MarshalJSON() if err != nil { - return fmt.Errorf("job with job id %s encountered a marshaling error: %w", id, err) + return eventsPerObject, fmt.Errorf("job with job id %s encountered a marshaling error: %w", id, err) } evt := j.createEvent(data, nil, offset+arrayOffset) if !dec.More() { // if this is the last object, then perform a complete state save - cp, done := j.state.saveForTx(j.object.Name, j.object.Updated) + cp, done := j.state.saveForTx(j.object.Name, j.object.Updated, j.metrics) if err := j.publisher.Publish(evt, cp); err != nil { + j.metrics.errorsTotal.Inc() j.log.Errorw("job encountered an error while publishing event", "gcs.jobId", id, "error", err) } done() } else { // since we don't update the cursor checkpoint, lack of a lock here is not a problem if err := j.publisher.Publish(evt, nil); err != nil { + j.metrics.errorsTotal.Inc() j.log.Errorw("job encountered an error while publishing event", "gcs.jobId", id, "error", err) } } + eventsPerObject++ } - return nil + return eventsPerObject, nil } // addGzipDecoderIfNeeded determines whether the given stream of bytes (encapsulated in a buffered reader) @@ -426,7 +471,7 @@ func (j *job) createEvent(message []byte, data []mapstr.M, offset int64) beat.Ev }, } event.SetID(objectID(j.hash, offset)) - + j.metrics.gcsEventsCreatedTotal.Inc() return event } diff --git a/x-pack/filebeat/input/gcs/metrics.go b/x-pack/filebeat/input/gcs/metrics.go new file mode 100644 index 000000000000..58b5e3c02570 --- /dev/null +++ b/x-pack/filebeat/input/gcs/metrics.go @@ -0,0 +1,78 @@ +// 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 gcs + +import ( + "github.com/rcrowley/go-metrics" + + "github.com/elastic/beats/v7/libbeat/monitoring/inputmon" + "github.com/elastic/elastic-agent-libs/monitoring" + "github.com/elastic/elastic-agent-libs/monitoring/adapter" +) + +// inputMetrics handles the input's metric reporting. +type inputMetrics struct { + unregister func() + url *monitoring.String // URL of the input resource. + errorsTotal *monitoring.Uint // Number of errors encountered. + decodeErrorsTotal *monitoring.Uint // Number of decode errors encountered. + + gcsObjectsTracked *monitoring.Uint // Number of objects currently tracked in the state registry (gauge). + gcsObjectsRequestedTotal *monitoring.Uint // Number of GCS objects downloaded. + gcsObjectsPublishedTotal *monitoring.Uint // Number of GCS objects processed that were published. + gcsObjectsListedTotal *monitoring.Uint // Number of GCS objects returned by list operations. + gcsBytesProcessedTotal *monitoring.Uint // Number of GCS bytes processed. + gcsEventsCreatedTotal *monitoring.Uint // Number of events created from processing GCS data. + gcsFailedJobsTotal *monitoring.Uint // Number of failed jobs. + gcsExpiredFailedJobsTotal *monitoring.Uint // Number of expired failed jobs that could not be recovered. + gcsObjectsInflight *monitoring.Uint // Number of GCS objects inflight (gauge). + gcsObjectProcessingTime metrics.Sample // Histogram of the elapsed GCS object processing times in nanoseconds (start of download to completion of parsing). + gcsObjectSizeInBytes metrics.Sample // Histogram of processed GCS object size in bytes. + gcsEventsPerObject metrics.Sample // Histogram of event count per GCS object. + gcsJobsScheduledAfterValidation metrics.Sample // Histogram of number of jobs scheduled after validation. + sourceLagTime metrics.Sample // Histogram of the time between the source (Updated) timestamp and the time the object was read. +} + +func newInputMetrics(id string, optionalParent *monitoring.Registry) *inputMetrics { + reg, unreg := inputmon.NewInputRegistry(inputName, id, optionalParent) + out := &inputMetrics{ + unregister: unreg, + url: monitoring.NewString(reg, "url"), + errorsTotal: monitoring.NewUint(reg, "errors_total"), + decodeErrorsTotal: monitoring.NewUint(reg, "decode_errors_total"), + + gcsObjectsTracked: monitoring.NewUint(reg, "gcs_objects_tracked_gauge"), + gcsObjectsRequestedTotal: monitoring.NewUint(reg, "gcs_objects_requested_total"), + gcsObjectsPublishedTotal: monitoring.NewUint(reg, "gcs_objects_published_total"), + gcsObjectsListedTotal: monitoring.NewUint(reg, "gcs_objects_listed_total"), + gcsBytesProcessedTotal: monitoring.NewUint(reg, "gcs_bytes_processed_total"), + gcsEventsCreatedTotal: monitoring.NewUint(reg, "gcs_events_created_total"), + gcsFailedJobsTotal: monitoring.NewUint(reg, "gcs_failed_jobs_total"), + gcsExpiredFailedJobsTotal: monitoring.NewUint(reg, "gcs_expired_failed_jobs_total"), + gcsObjectsInflight: monitoring.NewUint(reg, "gcs_objects_inflight_gauge"), + gcsObjectProcessingTime: metrics.NewUniformSample(1024), + gcsObjectSizeInBytes: metrics.NewUniformSample(1024), + gcsEventsPerObject: metrics.NewUniformSample(1024), + gcsJobsScheduledAfterValidation: metrics.NewUniformSample(1024), + sourceLagTime: metrics.NewUniformSample(1024), + } + + adapter.NewGoMetrics(reg, "gcs_object_processing_time", adapter.Accept). + Register("histogram", metrics.NewHistogram(out.gcsObjectProcessingTime)) //nolint:errcheck // A unique namespace is used so name collisions are impossible. + adapter.NewGoMetrics(reg, "gcs_object_size_in_bytes", adapter.Accept). + Register("histogram", metrics.NewHistogram(out.gcsObjectSizeInBytes)) //nolint:errcheck // A unique namespace is used so name collisions are impossible. + adapter.NewGoMetrics(reg, "gcs_events_per_object", adapter.Accept). + Register("histogram", metrics.NewHistogram(out.gcsEventsPerObject)) //nolint:errcheck // A unique namespace is used so name collisions are impossible. + adapter.NewGoMetrics(reg, "gcs_jobs_scheduled_after_validation", adapter.Accept). + Register("histogram", metrics.NewHistogram(out.gcsJobsScheduledAfterValidation)) //nolint:errcheck // A unique namespace is used so name collisions are impossible. + adapter.NewGoMetrics(reg, "source_lag_time", adapter.Accept). + Register("histogram", metrics.NewHistogram(out.sourceLagTime)) //nolint:errcheck // A unique namespace is used so name collisions are impossible. + + return out +} + +func (m *inputMetrics) Close() { + m.unregister() +} diff --git a/x-pack/filebeat/input/gcs/metrics_test.go b/x-pack/filebeat/input/gcs/metrics_test.go new file mode 100644 index 000000000000..3398a1a8daa5 --- /dev/null +++ b/x-pack/filebeat/input/gcs/metrics_test.go @@ -0,0 +1,67 @@ +// 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 gcs + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/elastic/elastic-agent-libs/monitoring" +) + +// TestInputMetricsClose asserts that metrics registered by this input are +// removed after Close() is called. This is important because an input with +// the same ID could be re-registered, and that ID cannot exist in the +// monitoring registry. +func TestInputMetricsClose(t *testing.T) { + reg := monitoring.NewRegistry() + + metrics := newInputMetrics("gcs-cl-bucket.cloudflare_logs-8b312b5f-9f99-492c-b035-3dff354a1f01", reg) + metrics.Close() + + reg.Do(monitoring.Full, func(s string, _ interface{}) { + t.Errorf("registry should be empty, but found %v", s) + }) +} + +// TestNewInputMetricsInstance asserts that all the metrics are initialized +// when a newInputMetrics method is invoked. This avoids nil hit panics when +// a getter is invoked on any uninitialized metric. +func TestNewInputMetricsInstance(t *testing.T) { + reg := monitoring.NewRegistry() + metrics := newInputMetrics("gcs-new-metric-test", reg) + + assert.NotNil(t, metrics.errorsTotal, + metrics.decodeErrorsTotal, + metrics.gcsObjectsTracked, + metrics.gcsObjectsRequestedTotal, + metrics.gcsObjectsPublishedTotal, + metrics.gcsObjectsListedTotal, + metrics.gcsBytesProcessedTotal, + metrics.gcsEventsCreatedTotal, + metrics.gcsFailedJobsTotal, + metrics.gcsExpiredFailedJobsTotal, + metrics.gcsObjectsInflight, + metrics.gcsObjectProcessingTime, + metrics.gcsObjectSizeInBytes, + metrics.gcsEventsPerObject, + metrics.gcsJobsScheduledAfterValidation, + metrics.sourceLagTime, + ) + + assert.Equal(t, uint64(0x0), metrics.errorsTotal.Get()) + assert.Equal(t, uint64(0x0), metrics.decodeErrorsTotal.Get()) + assert.Equal(t, uint64(0x0), metrics.gcsObjectsTracked.Get()) + assert.Equal(t, uint64(0x0), metrics.gcsObjectsRequestedTotal.Get()) + assert.Equal(t, uint64(0x0), metrics.gcsObjectsPublishedTotal.Get()) + assert.Equal(t, uint64(0x0), metrics.gcsObjectsListedTotal.Get()) + assert.Equal(t, uint64(0x0), metrics.gcsBytesProcessedTotal.Get()) + assert.Equal(t, uint64(0x0), metrics.gcsEventsCreatedTotal.Get()) + assert.Equal(t, uint64(0x0), metrics.gcsFailedJobsTotal.Get()) + assert.Equal(t, uint64(0x0), metrics.gcsExpiredFailedJobsTotal.Get()) + assert.Equal(t, uint64(0x0), metrics.gcsObjectsInflight.Get()) + +} diff --git a/x-pack/filebeat/input/gcs/mock/mock.go b/x-pack/filebeat/input/gcs/mock/mock.go index 50d2a431e018..1def436511a2 100644 --- a/x-pack/filebeat/input/gcs/mock/mock.go +++ b/x-pack/filebeat/input/gcs/mock/mock.go @@ -98,3 +98,43 @@ func GCSFileServer() http.Handler { w.Write([]byte("resource not found")) }) } + +//nolint:errcheck // We can ignore errors here, as this is just for testing +func GCSRetryServer() http.Handler { + retries := 0 + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + retries++ + path := strings.Split(strings.TrimLeft(r.URL.Path, "/"), "/") + if r.Method == http.MethodGet && retries >= 3 { + switch len(path) { + case 2: + if path[0] == "b" { + if buckets[path[1]] { + w.Write([]byte(fetchBucket[path[1]])) + return + } + } else if buckets[path[0]] && availableObjects[path[0]][path[1]] { + w.Write([]byte(objects[path[0]][path[1]])) + return + } + case 3: + if path[0] == "b" && path[2] == "o" { + if buckets[path[1]] { + w.Write([]byte(objectList[path[1]])) + return + } + } else if buckets[path[0]] { + objName := strings.Join(path[1:], "/") + if availableObjects[path[0]][objName] { + w.Write([]byte(objects[path[0]][objName])) + return + } + } + default: + w.WriteHeader(http.StatusNotFound) + return + } + } + w.WriteHeader(http.StatusInternalServerError) + }) +} diff --git a/x-pack/filebeat/input/gcs/scheduler.go b/x-pack/filebeat/input/gcs/scheduler.go index ef1bebd083d9..3f7a1d833c9f 100644 --- a/x-pack/filebeat/input/gcs/scheduler.go +++ b/x-pack/filebeat/input/gcs/scheduler.go @@ -36,12 +36,17 @@ type scheduler struct { state *state log *logp.Logger limiter *limiter + metrics *inputMetrics } // newScheduler, returns a new scheduler instance func newScheduler(publisher cursor.Publisher, bucket *storage.BucketHandle, src *Source, cfg *config, - state *state, log *logp.Logger, + state *state, metrics *inputMetrics, log *logp.Logger, ) *scheduler { + if metrics == nil { + // metrics are optional, initialize a stub if not provided + metrics = newInputMetrics("", nil) + } return &scheduler{ publisher: publisher, bucket: bucket, @@ -50,6 +55,7 @@ func newScheduler(publisher cursor.Publisher, bucket *storage.BucketHandle, src state: state, log: log, limiter: &limiter{limit: make(chan struct{}, src.MaxWorkers)}, + metrics: metrics, } } @@ -96,11 +102,13 @@ func (s *scheduler) scheduleOnce(ctx context.Context) error { var objects []*storage.ObjectAttrs nextPageToken, err := pager.NextPage(&objects) if err != nil { + s.metrics.errorsTotal.Inc() return err } numObs += len(objects) jobs := s.createJobs(objects, s.log) s.log.Debugf("scheduler: %d objects fetched for current batch", len(objects)) + s.metrics.gcsObjectsListedTotal.Add(uint64(len(objects))) // If previous checkpoint was saved then look up starting point for new jobs if !s.state.checkpoint().LatestEntryTime.IsZero() { @@ -110,6 +118,7 @@ func (s *scheduler) scheduleOnce(ctx context.Context) error { } } s.log.Debugf("scheduler: %d jobs scheduled for current batch", len(jobs)) + s.metrics.gcsJobsScheduledAfterValidation.Update(int64(len(jobs))) // distributes jobs among workers with the help of a limiter for i, job := range jobs { @@ -165,7 +174,7 @@ func (s *scheduler) createJobs(objects []*storage.ObjectAttrs, log *logp.Logger) } objectURI := "gs://" + s.src.BucketName + "/" + obj.Name - job := newJob(s.bucket, obj, objectURI, s.state, s.src, s.publisher, log, false) + job := newJob(s.bucket, obj, objectURI, s.state, s.src, s.publisher, s.metrics, log, false) jobs = append(jobs, job) } @@ -201,7 +210,6 @@ func (s *scheduler) moveToLastSeenJob(jobs []*job) []*job { func (s *scheduler) addFailedJobs(ctx context.Context, jobs []*job) []*job { jobMap := make(map[string]bool) - for _, j := range jobs { jobMap[j.Name()] = true } @@ -215,19 +223,19 @@ func (s *scheduler) addFailedJobs(ctx context.Context, jobs []*job) []*job { if err != nil { if errors.Is(err, storage.ErrObjectNotExist) { // if the object is not found in the bucket, then remove it from the failed job list - s.state.deleteFailedJob(name) + s.state.deleteFailedJob(name, s.metrics) s.log.Debugf("scheduler: failed job %s not found in bucket %s", name, s.src.BucketName) } else { // if there is an error while validating the object, // then update the failed job retry count and work towards natural removal - s.state.updateFailedJobs(name) + s.state.updateFailedJobs(name, s.metrics) s.log.Errorf("scheduler: adding failed job %s to job list caused an error: %v", name, err) } continue } objectURI := "gs://" + s.src.BucketName + "/" + obj.Name - job := newJob(s.bucket, obj, objectURI, s.state, s.src, s.publisher, s.log, true) + job := newJob(s.bucket, obj, objectURI, s.state, s.src, s.publisher, s.metrics, s.log, true) jobs = append(jobs, job) s.log.Debugf("scheduler: adding failed job number %d with name %s to job current list", fj, job.Name()) fj++ diff --git a/x-pack/filebeat/input/gcs/state.go b/x-pack/filebeat/input/gcs/state.go index ea04edcae908..af2ab43cec0a 100644 --- a/x-pack/filebeat/input/gcs/state.go +++ b/x-pack/filebeat/input/gcs/state.go @@ -44,7 +44,7 @@ func newState() *state { // and returns an unlock function, done. The caller must call done when // s and cp are no longer needed in a locked state. done may not be called // more than once. -func (s *state) saveForTx(name string, lastModifiedOn time.Time) (cp *Checkpoint, done func()) { +func (s *state) saveForTx(name string, lastModifiedOn time.Time, metrics *inputMetrics) (cp *Checkpoint, done func()) { s.mu.Lock() if _, ok := s.cp.FailedJobs[name]; !ok { if len(s.cp.ObjectName) == 0 { @@ -61,6 +61,7 @@ func (s *state) saveForTx(name string, lastModifiedOn time.Time) (cp *Checkpoint } else { // clear entry if this is a failed job delete(s.cp.FailedJobs, name) + metrics.gcsObjectsTracked.Dec() } return s.cp, func() { s.mu.Unlock() } } @@ -70,20 +71,29 @@ func (s *state) saveForTx(name string, lastModifiedOn time.Time) (cp *Checkpoint // move ahead in timestamp & objectName due to successful operations from other workers. // A failed job will be re-tried a maximum of 3 times after which the // entry is removed from the map -func (s *state) updateFailedJobs(jobName string) { +func (s *state) updateFailedJobs(jobName string, metrics *inputMetrics) { s.mu.Lock() + if _, ok := s.cp.FailedJobs[jobName]; !ok { + // increment stored state object count & failed job count + metrics.gcsObjectsTracked.Inc() + metrics.gcsFailedJobsTotal.Inc() + } s.cp.FailedJobs[jobName]++ if s.cp.FailedJobs[jobName] > maxFailedJobRetries { delete(s.cp.FailedJobs, jobName) + metrics.gcsExpiredFailedJobsTotal.Inc() + metrics.gcsObjectsTracked.Dec() } s.mu.Unlock() } // deleteFailedJob, deletes a failed job from the failedJobs map // this is used when a job no longer exists in the bucket or gets expired -func (s *state) deleteFailedJob(jobName string) { +func (s *state) deleteFailedJob(jobName string, metrics *inputMetrics) { s.mu.Lock() delete(s.cp.FailedJobs, jobName) + metrics.gcsExpiredFailedJobsTotal.Inc() + metrics.gcsObjectsTracked.Dec() s.mu.Unlock() } diff --git a/x-pack/filebeat/input/gcs/types.go b/x-pack/filebeat/input/gcs/types.go index a34c7f7160ff..72bf98e08e51 100644 --- a/x-pack/filebeat/input/gcs/types.go +++ b/x-pack/filebeat/input/gcs/types.go @@ -12,7 +12,6 @@ import ( // Source, it is the cursor source type Source struct { BucketName string - BucketTimeOut time.Duration ProjectId string MaxWorkers int Poll bool @@ -22,6 +21,7 @@ type Source struct { FileSelectors []fileSelectorConfig ReaderConfig readerConfig ExpandEventListFromField string + Retry retryConfig } func (s *Source) Name() string { diff --git a/x-pack/filebeat/input/http_endpoint/config.go b/x-pack/filebeat/input/http_endpoint/config.go index 5e1c93d2bc36..977e7b5d7d26 100644 --- a/x-pack/filebeat/input/http_endpoint/config.go +++ b/x-pack/filebeat/input/http_endpoint/config.go @@ -37,6 +37,8 @@ type config struct { URL string `config:"url" validate:"required"` Prefix string `config:"prefix"` ContentType string `config:"content_type"` + MaxInFlight int64 `config:"max_in_flight_bytes"` + RetryAfter int `config:"retry_after"` Program string `config:"program"` SecretHeader string `config:"secret.header"` SecretValue string `config:"secret.value"` @@ -66,6 +68,7 @@ func defaultConfig() config { BasicAuth: false, ResponseCode: 200, ResponseBody: `{"message": "success"}`, + RetryAfter: 10, ListenAddress: "127.0.0.1", ListenPort: "8000", URL: "/", diff --git a/x-pack/filebeat/input/http_endpoint/handler.go b/x-pack/filebeat/input/http_endpoint/handler.go index 27f4d12253ef..388287a7e582 100644 --- a/x-pack/filebeat/input/http_endpoint/handler.go +++ b/x-pack/filebeat/input/http_endpoint/handler.go @@ -56,6 +56,20 @@ type handler struct { txBaseID string // Random value to make transaction IDs unique. txIDCounter atomic.Uint64 // Transaction ID counter that is incremented for each request. + // inFlight is the sum of message body length + // that have been received but not yet ACKed + // or timed out or otherwise handled. + // + // Requests that do not request a timeout do + // not contribute to this value. + inFlight atomic.Int64 + // maxInFlight is the maximum value of inFligh + // that will be allowed for any messages received + // by the handler. If non-zero, inFlight may + // not exceed this value. + maxInFlight int64 + retryAfter int + reqLogger *zap.Logger host, scheme string @@ -86,9 +100,38 @@ func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { acked chan struct{} timeout *time.Timer ) + if h.maxInFlight != 0 { + // Consider non-ACKing messages as well. These do not add + // to the sum of in-flight bytes, but we can still assess + // whether a message would take us over the limit. + inFlight := h.inFlight.Load() + r.ContentLength + if inFlight > h.maxInFlight { + w.Header().Set(headerContentEncoding, "application/json") + w.Header().Set("Retry-After", strconv.Itoa(h.retryAfter)) + w.WriteHeader(http.StatusServiceUnavailable) + _, err := fmt.Fprintf(w, + `{"warn":"max in flight message memory exceeded","max_in_flight":%d,"in_flight":%d}`, + h.maxInFlight, inFlight, + ) + if err != nil { + h.log.Errorw("failed to write 503", "error", err) + } + return + } + } if wait != 0 { acked = make(chan struct{}) timeout = time.NewTimer(wait) + h.inFlight.Add(r.ContentLength) + defer func() { + // Any return will be a message handling completion and the + // the removal of the allocation from the queue assuming that + // the client has requested a timeout. Either we have an early + // error condition or timeout and the message is dropped, we + // have ACKed all the events in the request, or the input has + // been cancelled. + h.inFlight.Add(-r.ContentLength) + }() } start := time.Now() acker := newBatchACKTracker(func() { diff --git a/x-pack/filebeat/input/http_endpoint/handler_test.go b/x-pack/filebeat/input/http_endpoint/handler_test.go index 2ac763f052b1..623c9542cc15 100644 --- a/x-pack/filebeat/input/http_endpoint/handler_test.go +++ b/x-pack/filebeat/input/http_endpoint/handler_test.go @@ -192,6 +192,9 @@ type publisher struct { func (p *publisher) Publish(e beat.Event) { p.mu.Lock() p.events = append(p.events, e) + if ack, ok := e.Private.(*batchACKTracker); ok { + ack.ACK() + } p.mu.Unlock() } diff --git a/x-pack/filebeat/input/http_endpoint/input.go b/x-pack/filebeat/input/http_endpoint/input.go index b4ad07e7626b..6d6b0cbc3f41 100644 --- a/x-pack/filebeat/input/http_endpoint/input.go +++ b/x-pack/filebeat/input/http_endpoint/input.go @@ -347,6 +347,8 @@ func newHandler(ctx context.Context, c config, prg *program, pub func(beat.Event hmacType: c.HMACType, hmacPrefix: c.HMACPrefix, }, + maxInFlight: c.MaxInFlight, + retryAfter: c.RetryAfter, program: prg, messageField: c.Prefix, responseCode: c.ResponseCode, diff --git a/x-pack/filebeat/input/http_endpoint/input_test.go b/x-pack/filebeat/input/http_endpoint/input_test.go index 3f530454e1d8..9a3a2368a74a 100644 --- a/x-pack/filebeat/input/http_endpoint/input_test.go +++ b/x-pack/filebeat/input/http_endpoint/input_test.go @@ -10,6 +10,7 @@ import ( "errors" "io" "net/http" + "slices" "strings" "sync" "testing" @@ -24,19 +25,20 @@ import ( ) var serverPoolTests = []struct { - name string - method string - cfgs []*httpEndpoint - events []target - want []mapstr.M - wantErr error + name string + method string + cfgs []*httpEndpoint + events []target + want []mapstr.M + wantStatus int + wantErr error }{ { name: "single", cfgs: []*httpEndpoint{{ addr: "127.0.0.1:9001", config: config{ - ResponseCode: 200, + ResponseCode: http.StatusOK, ResponseBody: `{"message": "success"}`, ListenAddress: "127.0.0.1", ListenPort: "9001", @@ -50,6 +52,7 @@ var serverPoolTests = []struct { {url: "http://127.0.0.1:9001/", event: `{"b":2}`}, {url: "http://127.0.0.1:9001/", event: `{"c":3}`}, }, + wantStatus: http.StatusOK, want: []mapstr.M{ {"json": mapstr.M{"a": int64(1)}}, {"json": mapstr.M{"b": int64(2)}}, @@ -63,7 +66,7 @@ var serverPoolTests = []struct { addr: "127.0.0.1:9001", config: config{ Method: http.MethodPut, - ResponseCode: 200, + ResponseCode: http.StatusOK, ResponseBody: `{"message": "success"}`, ListenAddress: "127.0.0.1", ListenPort: "9001", @@ -77,6 +80,7 @@ var serverPoolTests = []struct { {url: "http://127.0.0.1:9001/", event: `{"b":2}`}, {url: "http://127.0.0.1:9001/", event: `{"c":3}`}, }, + wantStatus: http.StatusOK, want: []mapstr.M{ {"json": mapstr.M{"a": int64(1)}}, {"json": mapstr.M{"b": int64(2)}}, @@ -90,7 +94,7 @@ var serverPoolTests = []struct { addr: "127.0.0.1:9001", config: config{ Method: http.MethodPatch, - ResponseCode: 200, + ResponseCode: http.StatusOK, ResponseBody: `{"message": "success"}`, ListenAddress: "127.0.0.1", ListenPort: "9001", @@ -104,6 +108,7 @@ var serverPoolTests = []struct { {url: "http://127.0.0.1:9001/", event: `{"b":2}`}, {url: "http://127.0.0.1:9001/", event: `{"c":3}`}, }, + wantStatus: http.StatusOK, want: []mapstr.M{ {"json": mapstr.M{"a": int64(1)}}, {"json": mapstr.M{"b": int64(2)}}, @@ -116,7 +121,7 @@ var serverPoolTests = []struct { { addr: "127.0.0.1:9001", config: config{ - ResponseCode: 200, + ResponseCode: http.StatusOK, ResponseBody: `{"message": "success"}`, ListenAddress: "127.0.0.1", ListenPort: "9001", @@ -128,7 +133,7 @@ var serverPoolTests = []struct { { addr: "127.0.0.1:9002", config: config{ - ResponseCode: 200, + ResponseCode: http.StatusOK, ResponseBody: `{"message": "success"}`, ListenAddress: "127.0.0.1", ListenPort: "9002", @@ -143,6 +148,7 @@ var serverPoolTests = []struct { {url: "http://127.0.0.1:9002/b/", event: `{"b":2}`}, {url: "http://127.0.0.1:9001/a/", event: `{"c":3}`}, }, + wantStatus: http.StatusOK, want: []mapstr.M{ {"json": mapstr.M{"a": int64(1)}}, {"json": mapstr.M{"b": int64(2)}}, @@ -155,7 +161,7 @@ var serverPoolTests = []struct { { addr: "127.0.0.1:9001", config: config{ - ResponseCode: 200, + ResponseCode: http.StatusOK, ResponseBody: `{"message": "success"}`, ListenAddress: "127.0.0.1", ListenPort: "9001", @@ -167,7 +173,7 @@ var serverPoolTests = []struct { { addr: "127.0.0.1:9001", config: config{ - ResponseCode: 200, + ResponseCode: http.StatusOK, ResponseBody: `{"message": "success"}`, ListenAddress: "127.0.0.1", ListenPort: "9001", @@ -182,6 +188,7 @@ var serverPoolTests = []struct { {url: "http://127.0.0.1:9001/b/", event: `{"b":2}`}, {url: "http://127.0.0.1:9001/a/", event: `{"c":3}`}, }, + wantStatus: http.StatusOK, want: []mapstr.M{ {"json": mapstr.M{"a": int64(1)}}, {"json": mapstr.M{"b": int64(2)}}, @@ -194,7 +201,7 @@ var serverPoolTests = []struct { { addr: "127.0.0.1:9001", config: config{ - ResponseCode: 200, + ResponseCode: http.StatusOK, ResponseBody: `{"message": "success"}`, ListenAddress: "127.0.0.1", ListenPort: "9001", @@ -207,7 +214,7 @@ var serverPoolTests = []struct { addr: "127.0.0.1:9001", config: config{ TLS: &tlscommon.ServerConfig{}, - ResponseCode: 200, + ResponseCode: http.StatusOK, ResponseBody: `{"message": "success"}`, ListenAddress: "127.0.0.1", ListenPort: "9001", @@ -228,7 +235,7 @@ var serverPoolTests = []struct { TLS: &tlscommon.ServerConfig{ VerificationMode: tlscommon.VerifyStrict, }, - ResponseCode: 200, + ResponseCode: http.StatusOK, ResponseBody: `{"message": "success"}`, ListenAddress: "127.0.0.1", ListenPort: "9001", @@ -243,7 +250,7 @@ var serverPoolTests = []struct { TLS: &tlscommon.ServerConfig{ VerificationMode: tlscommon.VerifyNone, }, - ResponseCode: 200, + ResponseCode: http.StatusOK, ResponseBody: `{"message": "success"}`, ListenAddress: "127.0.0.1", ListenPort: "9001", @@ -255,11 +262,87 @@ var serverPoolTests = []struct { }, wantErr: invalidTLSStateErr{addr: "127.0.0.1:9001", reason: "configuration options do not agree"}, }, + { + name: "exceed_max_in_flight", + method: http.MethodPost, + cfgs: []*httpEndpoint{{ + addr: "127.0.0.1:9001", + config: config{ + Method: http.MethodPost, + ResponseCode: http.StatusOK, + ResponseBody: `{"message": "success"}`, + ListenAddress: "127.0.0.1", + ListenPort: "9001", + URL: "/", + Prefix: "json", + MaxInFlight: 2, + RetryAfter: 10, + ContentType: "application/json", + }, + }}, + events: []target{ + {url: "http://127.0.0.1:9001/?wait_for_completion_timeout=1s", event: `{"a":1}`, wantBody: `{"warn":"max in flight message memory exceeded","max_in_flight":2,"in_flight":7}`, wantHeader: http.Header{"Retry-After": {"10"}}}, + {url: "http://127.0.0.1:9001/?wait_for_completion_timeout=1s", event: `{"b":2}`, wantBody: `{"warn":"max in flight message memory exceeded","max_in_flight":2,"in_flight":7}`, wantHeader: http.Header{"Retry-After": {"10"}}}, + {url: "http://127.0.0.1:9001/?wait_for_completion_timeout=1s", event: `{"c":3}`, wantBody: `{"warn":"max in flight message memory exceeded","max_in_flight":2,"in_flight":7}`, wantHeader: http.Header{"Retry-After": {"10"}}}, + }, + wantStatus: http.StatusServiceUnavailable, + want: nil, + }, + { + name: "not_exceed_max_in_flight", + method: http.MethodPost, + cfgs: []*httpEndpoint{{ + addr: "127.0.0.1:9001", + config: config{ + Method: http.MethodPost, + ResponseCode: http.StatusOK, + ResponseBody: `{"message": "success"}`, + ListenAddress: "127.0.0.1", + ListenPort: "9001", + URL: "/", + Prefix: "json", + MaxInFlight: 20, + RetryAfter: 10, + ContentType: "application/json", + }, + }}, + events: []target{ + {url: "http://127.0.0.1:9001/?wait_for_completion_timeout=1s", event: `{"a":1}`, wantBody: `{"message": "success"}`, wantHeader: http.Header{"Retry-After": nil}}, + {url: "http://127.0.0.1:9001/?wait_for_completion_timeout=1s", event: `{"b":2}`, wantBody: `{"message": "success"}`, wantHeader: http.Header{"Retry-After": nil}}, + {url: "http://127.0.0.1:9001/?wait_for_completion_timeout=1s", event: `{"c":3}`, wantBody: `{"message": "success"}`, wantHeader: http.Header{"Retry-After": nil}}, + }, + wantStatus: http.StatusOK, + want: []mapstr.M{ + {"json": mapstr.M{"a": int64(1)}}, + {"json": mapstr.M{"b": int64(2)}}, + {"json": mapstr.M{"c": int64(3)}}, + }, + }, } type target struct { - url string - event string + url string + event string + wantBody string + wantHeader http.Header +} + +// isWantedHeader returns whether got includes the wanted header and that +// the values match. A nil value for a header in the receiver matches absence +// of that header in the got parameter. +func (t target) isWantedHeader(got http.Header) bool { + for h, v := range t.wantHeader { + if v == nil { + if _, ok := got[h]; ok { + return false + } + continue + } + if !slices.Equal(got[h], v) { + return false + } + } + return true } func TestServerPool(t *testing.T) { @@ -309,9 +392,15 @@ func TestServerPool(t *testing.T) { t.Fatalf("failed to post event #%d: %v", i, err) } body := dump(resp.Body) - if resp.StatusCode != http.StatusOK { - t.Errorf("unexpected response status code: %s (%d)\nresp: %s", - resp.Status, resp.StatusCode, body) + if resp.StatusCode != test.wantStatus { + t.Errorf("unexpected response status code: %s (%d), want: %d\nresp: %s", + resp.Status, resp.StatusCode, test.wantStatus, body) + } + if len(e.wantBody) != 0 && string(body) != e.wantBody { + t.Errorf("unexpected response body:\ngot: %s\nwant:%s", body, e.wantBody) + } + if !e.isWantedHeader(resp.Header) { + t.Errorf("unexpected header:\n--- want\n+++ got\n%s", cmp.Diff(e.wantHeader, resp.Header)) } } cancel() @@ -320,8 +409,8 @@ func TestServerPool(t *testing.T) { for _, e := range pub.events { got = append(got, e.Fields) } - if !cmp.Equal(got, test.want) { - t.Errorf("unexpected result:\n--- got\n--- want\n%s", cmp.Diff(got, test.want)) + if !cmp.Equal(test.want, got) { + t.Errorf("unexpected result:\n--- want\n+++ got\n%s", cmp.Diff(test.want, got)) } // Try to re-register the same addresses. diff --git a/x-pack/filebeat/input/httpjson/input.go b/x-pack/filebeat/input/httpjson/input.go index ad61aceff895..51a9d446f472 100644 --- a/x-pack/filebeat/input/httpjson/input.go +++ b/x-pack/filebeat/input/httpjson/input.go @@ -15,6 +15,7 @@ import ( "net/url" "os" "path/filepath" + "sort" "strings" "time" @@ -33,6 +34,7 @@ import ( "github.com/elastic/beats/v7/libbeat/version" "github.com/elastic/beats/v7/x-pack/filebeat/input/internal/httplog" "github.com/elastic/beats/v7/x-pack/filebeat/input/internal/httpmon" + "github.com/elastic/beats/v7/x-pack/filebeat/input/internal/private" "github.com/elastic/elastic-agent-libs/logp" "github.com/elastic/elastic-agent-libs/mapstr" "github.com/elastic/elastic-agent-libs/monitoring" @@ -91,6 +93,60 @@ func Plugin(log *logp.Logger, store inputcursor.StateStore) v2.Plugin { } } +type redact struct { + value mapstrM + fields []string +} + +func (r redact) MarshalLogObject(enc zapcore.ObjectEncoder) error { + v, err := private.Redact(r.value, "", r.fields) + if err != nil { + return fmt.Errorf("could not redact value: %v", err) + } + return v.MarshalLogObject(enc) +} + +// mapstrM is a non-mutating version of mapstr.M. +// See https://github.com/elastic/elastic-agent-libs/issues/232. +type mapstrM mapstr.M + +// MarshalLogObject implements the zapcore.ObjectMarshaler interface and allows +// for more efficient marshaling of mapstrM in structured logging. +func (m mapstrM) MarshalLogObject(enc zapcore.ObjectEncoder) error { + if len(m) == 0 { + return nil + } + + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + v := m[k] + if inner, ok := tryToMapStr(v); ok { + err := enc.AddObject(k, inner) + if err != nil { + return fmt.Errorf("failed to add object: %w", err) + } + continue + } + zap.Any(k, v).AddTo(enc) + } + return nil +} + +func tryToMapStr(v interface{}) (mapstrM, bool) { + switch m := v.(type) { + case mapstrM: + return m, true + case map[string]interface{}: + return mapstrM(m), true + default: + return nil, false + } +} + func test(url *url.URL) error { port := func() string { if url.Port() != "" { diff --git a/x-pack/filebeat/input/httpjson/request.go b/x-pack/filebeat/input/httpjson/request.go index 160ac67fe9e6..fb847570826a 100644 --- a/x-pack/filebeat/input/httpjson/request.go +++ b/x-pack/filebeat/input/httpjson/request.go @@ -465,7 +465,7 @@ func (rf *requestFactory) newRequest(ctx *transformContext) (transformable, erro } } - rf.log.Debugf("new request: %#v", req) + rf.log.Debugw("new request", "req", redact{value: mapstrM(req), fields: []string{"header.Authorization"}}) return req, nil } diff --git a/x-pack/filebeat/input/netflow/decoder/atomic/bool.go b/x-pack/filebeat/input/netflow/decoder/atomic/bool.go deleted file mode 100644 index b294cc6c395c..000000000000 --- a/x-pack/filebeat/input/netflow/decoder/atomic/bool.go +++ /dev/null @@ -1,30 +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 atomic - -import "sync/atomic" - -type Bool struct { - value uint32 -} - -func (b *Bool) Store(value bool) { - atomic.StoreUint32(&b.value, encodeBool(value)) -} - -func (b *Bool) CAS(old bool, new bool) (swapped bool) { - return atomic.CompareAndSwapUint32(&b.value, encodeBool(old), encodeBool(new)) -} - -func (b *Bool) Load() (value bool) { - return atomic.LoadUint32(&b.value) != 0 -} - -func encodeBool(value bool) (result uint32) { - if value { - result = 1 - } - return -} diff --git a/x-pack/filebeat/input/netflow/decoder/v9/session.go b/x-pack/filebeat/input/netflow/decoder/v9/session.go index 492576f6b962..e72fa1ab80a6 100644 --- a/x-pack/filebeat/input/netflow/decoder/v9/session.go +++ b/x-pack/filebeat/input/netflow/decoder/v9/session.go @@ -8,9 +8,9 @@ import ( "log" "net" "sync" + "sync/atomic" "time" - "github.com/elastic/beats/v7/x-pack/filebeat/input/netflow/decoder/atomic" "github.com/elastic/beats/v7/x-pack/filebeat/input/netflow/decoder/config" "github.com/elastic/beats/v7/x-pack/filebeat/input/netflow/decoder/template" ) @@ -83,7 +83,7 @@ func (s *SessionState) ExpireTemplates() (alive int, removed int) { var toDelete []TemplateKey s.mutex.RLock() for id, template := range s.Templates { - if !template.Delete.CAS(false, true) { + if !template.Delete.CompareAndSwap(false, true) { toDelete = append(toDelete, id) } } @@ -183,7 +183,7 @@ func (m *SessionMap) cleanup() (aliveSession int, removedSession int, aliveTempl a, r := session.ExpireTemplates() aliveTemplates += a removedTemplates += r - if !session.Delete.CAS(false, true) { + if !session.Delete.CompareAndSwap(false, true) { toDelete = append(toDelete, key) } } diff --git a/x-pack/filebeat/input/streaming/config.go b/x-pack/filebeat/input/streaming/config.go index 67ee6e1eb318..eea8c2afc704 100644 --- a/x-pack/filebeat/input/streaming/config.go +++ b/x-pack/filebeat/input/streaming/config.go @@ -41,9 +41,8 @@ type config struct { Redact *redact `config:"redact"` // Retry is the configuration for retrying failed connections. Retry *retry `config:"retry"` - + // Transport is the common the transport config. Transport httpcommon.HTTPTransportSettings `config:",inline"` - // CrowdstrikeAppID is the value used to set the // appId request parameter in the FalconHose stream // discovery request. @@ -166,3 +165,16 @@ func checkURLScheme(c config) error { return fmt.Errorf("unknown stream type: %s", c.Type) } } + +func defaultConfig() config { + return config{ + Transport: httpcommon.HTTPTransportSettings{ + Timeout: 180 * time.Second, + }, + Retry: &retry{ + MaxAttempts: 5, + WaitMin: 1 * time.Second, + WaitMax: 30 * time.Second, + }, + } +} diff --git a/x-pack/filebeat/input/streaming/crowdstrike.go b/x-pack/filebeat/input/streaming/crowdstrike.go index 3fed6a69c1ac..eb1797d2f6d4 100644 --- a/x-pack/filebeat/input/streaming/crowdstrike.go +++ b/x-pack/filebeat/input/streaming/crowdstrike.go @@ -241,7 +241,7 @@ func (s *falconHoseStream) followSession(ctx context.Context, cli *http.Client, } s.metrics.receivedBytesTotal.Add(uint64(len(msg))) state["response"] = []byte(msg) - s.log.Debugw("received firehose message", logp.Namespace("falcon_hose"), debugMsg(msg)) + s.log.Debugw("received firehose message", logp.Namespace("falcon_hose"), "msg", debugMsg(msg)) err = s.process(ctx, state, s.cursor, s.now().In(time.UTC)) if err != nil { s.log.Errorw("failed to process and publish data", "error", err) diff --git a/x-pack/filebeat/input/streaming/input_manager.go b/x-pack/filebeat/input/streaming/input_manager.go index f20b867755b2..c685452c34f1 100644 --- a/x-pack/filebeat/input/streaming/input_manager.go +++ b/x-pack/filebeat/input/streaming/input_manager.go @@ -34,7 +34,7 @@ func NewInputManager(log *logp.Logger, store inputcursor.StateStore) InputManage } func cursorConfigure(cfg *conf.C) ([]inputcursor.Source, inputcursor.Input, error) { - src := &source{cfg: config{}} + src := &source{cfg: defaultConfig()} if err := cfg.Unpack(&src.cfg); err != nil { return nil, nil, err } diff --git a/x-pack/filebeat/input/streaming/input_test.go b/x-pack/filebeat/input/streaming/input_test.go index 6d382bdf6645..c11784ea3dbf 100644 --- a/x-pack/filebeat/input/streaming/input_test.go +++ b/x-pack/filebeat/input/streaming/input_test.go @@ -6,6 +6,7 @@ package streaming import ( "context" + "crypto/tls" "errors" "fmt" "net/http" @@ -41,6 +42,7 @@ type WebSocketHandler func(*testing.T, *websocket.Conn, []string) var inputTests = []struct { name string server func(*testing.T, WebSocketHandler, map[string]interface{}, []string) + proxyServer func(*testing.T, WebSocketHandler, map[string]interface{}, []string) *httptest.Server handler WebSocketHandler config map[string]interface{} response []string @@ -450,6 +452,140 @@ var inputTests = []struct { }, wantErr: fmt.Errorf("failed to establish WebSocket connection after 2 attempts with error websocket: bad handshake"), }, + { + name: "single_event_tls", + server: webSocketServerWithTLS(httptest.NewUnstartedServer), + handler: defaultHandler, + config: map[string]interface{}{ + "program": ` + bytes(state.response).decode_json().as(inner_body,{ + "events": [inner_body], + })`, + "ssl": map[string]interface{}{ + "enabled": true, + "certificate_authorities": []string{"testdata/certs/ca.crt"}, + "certificate": "testdata/certs/cert.pem", + "key": "testdata/certs/key.pem", + }, + }, + response: []string{` + { + "pps": { + "agent": "example.proofpoint.com", + "cid": "mmeng_uivm071" + }, + "ts": "2017-08-17T14:54:12.949180-07:00", + "data": "2017-08-17T14:54:12.949180-07:00 example sendmail[30641]:v7HLqYbx029423: to=/dev/null, ctladdr= (8/0),delay=00:00:00, xdelay=00:00:00, mailer=*file*, tls_verify=NONE, pri=35342,dsn=2.0.0, stat=Sent", + "sm": { + "tls": { + "verify": "NONE" + }, + "stat": "Sent", + "qid": "v7HLqYbx029423", + "dsn": "2.0.0", + "mailer": "*file*", + "to": [ + "/dev/null" + ], + "ctladdr": " (8/0)", + "delay": "00:00:00", + "xdelay": "00:00:00", + "pri": 35342 + }, + "id": "ZeYGULpZmL5N0151HN1OyA" + }`}, + want: []map[string]interface{}{ + { + "pps": map[string]interface{}{ + "agent": "example.proofpoint.com", + "cid": "mmeng_uivm071", + }, + "ts": "2017-08-17T14:54:12.949180-07:00", + "data": "2017-08-17T14:54:12.949180-07:00 example sendmail[30641]:v7HLqYbx029423: to=/dev/null, ctladdr= (8/0),delay=00:00:00, xdelay=00:00:00, mailer=*file*, tls_verify=NONE, pri=35342,dsn=2.0.0, stat=Sent", + "sm": map[string]interface{}{ + "tls": map[string]interface{}{ + "verify": "NONE", + }, + "stat": "Sent", + "qid": "v7HLqYbx029423", + "dsn": "2.0.0", + "mailer": "*file*", + "to": []interface{}{ + "/dev/null", + }, + "ctladdr": " (8/0)", + "delay": "00:00:00", + "xdelay": "00:00:00", + "pri": float64(35342), + }, + "id": "ZeYGULpZmL5N0151HN1OyA", + }, + }, + }, + { + name: "basic_proxy_forwarding", + proxyServer: newWebSocketProxyTestServer, + handler: defaultHandler, + config: map[string]interface{}{ + "program": ` + bytes(state.response).decode_json().as(inner_body,{ + "events": [inner_body], + })`, + }, + response: []string{` + { + "pps": { + "agent": "example.proofpoint.com", + "cid": "mmeng_uivm071" + }, + "ts": "2017-08-17T14:54:12.949180-07:00", + "data": "2017-08-17T14:54:12.949180-07:00 example sendmail[30641]:v7HLqYbx029423: to=/dev/null, ctladdr= (8/0),delay=00:00:00, xdelay=00:00:00, mailer=*file*, tls_verify=NONE, pri=35342,dsn=2.0.0, stat=Sent", + "sm": { + "tls": { + "verify": "NONE" + }, + "stat": "Sent", + "qid": "v7HLqYbx029423", + "dsn": "2.0.0", + "mailer": "*file*", + "to": [ + "/dev/null" + ], + "ctladdr": " (8/0)", + "delay": "00:00:00", + "xdelay": "00:00:00", + "pri": 35342 + }, + "id": "ZeYGULpZmL5N0151HN1OyA" + }`}, + want: []map[string]interface{}{ + { + "pps": map[string]interface{}{ + "agent": "example.proofpoint.com", + "cid": "mmeng_uivm071", + }, + "ts": "2017-08-17T14:54:12.949180-07:00", + "data": "2017-08-17T14:54:12.949180-07:00 example sendmail[30641]:v7HLqYbx029423: to=/dev/null, ctladdr= (8/0),delay=00:00:00, xdelay=00:00:00, mailer=*file*, tls_verify=NONE, pri=35342,dsn=2.0.0, stat=Sent", + "sm": map[string]interface{}{ + "tls": map[string]interface{}{ + "verify": "NONE", + }, + "stat": "Sent", + "qid": "v7HLqYbx029423", + "dsn": "2.0.0", + "mailer": "*file*", + "to": []interface{}{ + "/dev/null", + }, + "ctladdr": " (8/0)", + "delay": "00:00:00", + "xdelay": "00:00:00", + "pri": float64(35342), + }, + "id": "ZeYGULpZmL5N0151HN1OyA", + }, + }, + }, } var urlEvalTests = []struct { @@ -560,6 +696,9 @@ func TestInput(t *testing.T) { if test.server != nil { test.server(t, test.handler, test.config, test.response) } + if test.proxyServer != nil { + test.proxyServer(t, test.handler, test.config, test.response) + } cfg := conf.MustNewConfigFrom(test.config) @@ -771,6 +910,46 @@ func webSocketServerWithRetry(serve func(http.Handler) *httptest.Server) func(*t } } +// webSocketServerWithTLS simulates a WebSocket server with TLS based authentication. +func webSocketServerWithTLS(serve func(http.Handler) *httptest.Server) func(*testing.T, WebSocketHandler, map[string]interface{}, []string) { + return func(t *testing.T, handler WebSocketHandler, config map[string]interface{}, response []string) { + server := serve(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + upgrader := websocket.Upgrader{ + CheckOrigin: func(r *http.Request) bool { + return true + }, + } + + conn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + t.Fatalf("error upgrading connection to WebSocket: %v", err) + return + } + + handler(t, conn, response) + })) + //nolint:gosec // there is no need to use a secure cert for testing + server.TLS = &tls.Config{ + Certificates: []tls.Certificate{generateSelfSignedCert(t)}, + } + server.StartTLS() + + if config["url"] == nil { + config["url"] = "ws" + server.URL[4:] + } + t.Cleanup(server.Close) + } +} + +// generateSelfSignedCert returns a self-signed certificate for testing purposes based on the dummy certs in the testdata directory +func generateSelfSignedCert(t *testing.T) tls.Certificate { + cert, err := tls.LoadX509KeyPair("testdata/certs/cert.pem", "testdata/certs/key.pem") + if err != nil { + t.Fatalf("failed to generate self-signed cert: %v", err) + } + return cert +} + // defaultHandler is a default handler for WebSocket connections. func defaultHandler(t *testing.T, conn *websocket.Conn, response []string) { for _, r := range response { @@ -780,3 +959,73 @@ func defaultHandler(t *testing.T, conn *websocket.Conn, response []string) { } } } + +// webSocketTestServer creates a WebSocket target server that communicates with the proxy handler. +func webSocketTestServer(t *testing.T, handler WebSocketHandler, response []string) *httptest.Server { + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + upgrader := websocket.Upgrader{ + CheckOrigin: func(r *http.Request) bool { + return true + }, + } + conn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + t.Fatalf("failed to upgrade WebSocket connection: %v", err) + return + } + handler(t, conn, response) + })) +} + +// webSocketProxyHandler forwards WebSocket connections to the target server. +// +//nolint:errcheck //we can safely ignore errors checks here +func webSocketProxyHandler(targetURL string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + defer r.Response.Body.Close() + //nolint:bodyclose // we can ignore the body close here + targetConn, _, err := websocket.DefaultDialer.Dial(targetURL, nil) + if err != nil { + http.Error(w, "failed to connect to backend WebSocket server", http.StatusBadGateway) + return + } + defer targetConn.Close() + + upgrader := websocket.Upgrader{ + CheckOrigin: func(r *http.Request) bool { + return true + }, + } + clientConn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + http.Error(w, "failed to upgrade client connection", http.StatusInternalServerError) + return + } + defer clientConn.Close() + // forward messages between client and target server + go func() { + for { + messageType, message, err := targetConn.ReadMessage() + if err != nil { + break + } + clientConn.WriteMessage(messageType, message) + } + }() + for { + messageType, message, err := clientConn.ReadMessage() + if err != nil { + break + } + targetConn.WriteMessage(messageType, message) + } + } +} + +// newWebSocketProxyTestServer creates a proxy server forwarding WebSocket traffic. +func newWebSocketProxyTestServer(t *testing.T, handler WebSocketHandler, config map[string]interface{}, response []string) *httptest.Server { + backendServer := webSocketTestServer(t, handler, response) + config["url"] = "ws" + backendServer.URL[4:] + config["proxy_url"] = "ws" + backendServer.URL[4:] + return httptest.NewServer(webSocketProxyHandler(config["url"].(string))) +} diff --git a/x-pack/filebeat/input/streaming/testdata/certs/ca.crt b/x-pack/filebeat/input/streaming/testdata/certs/ca.crt new file mode 100644 index 000000000000..43e187f1367f --- /dev/null +++ b/x-pack/filebeat/input/streaming/testdata/certs/ca.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIUS/rm8sWDc2a+eD9L+q+9XQpBa5MwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yNDEyMDUxMjM4NThaGA8yMTI0 +MTExMTEyMzg1OFowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx +ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBALhEaFVqFuYwSwH4GHhMeqhilC+sWXKaQP8QmaH7 +HWRST8Ko6YTT9NixUL4Qs5OmzCQFavRN9qtEo4wtqCJBOEyXQG1wAHuLWIY+KOCB +twUg8fP+uYaYUOQOYNLkBz7SLlejuZYTyGxepIkc+UeJRcOE36anIPHpc2KSr3Hm +vKJxZUVpQEbJvQ7pe7+iLL4jSOfzpQNcV9S/bzTo6taZXuo+ryEPlshkU/ME5VCN +LFrU3AW2fzKW0Xa/skkW5izCiAU8KNEy84UQM6aZkJfFi9O394i97sGgYg+q36XL +sXbZ+sCXHI3CGx+pwOx0h7S8n7iJJ7BbmwM6QuLFF6bFYkkCAwEAAaNTMFEwHQYD +VR0OBBYEFEHtfvey8SdncMr7VDqA2YhtEiGYMB8GA1UdIwQYMBaAFEHtfvey8Sdn +cMr7VDqA2YhtEiGYMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB +AKFcAeh9yhIbkkxvXl6ebmLcj817NVjhpcvDZlKP2MVu+w/h70w+JwBktLUlZlXd +UNkKEWZyRvrdmY+YN6rwY/QI75N17bcmDWy6QnNlVJF0AJkBSdbKonCgHrZm7K25 +TOKpj0QF8l7k9wr5FWHHcBw/vFF9cGZ5TO4HbnI25N/cEKgdzZFEVA5Y/Rv7GIGU +COjJG20Cr2HIKvVYoyWvN6sL7+gbzUMyjvQyGMCT7YoIqscUfrUU+T46QaOLAKa3 +z91Obfmv6uTO/rsieoxVWVJ35GeHeNJkAPkr7Z1sWIrreJ/3WsecWuPPEDNDXiSV +5h0bTbbPOyEIe5ydEIbr5kA= +-----END CERTIFICATE----- diff --git a/x-pack/filebeat/input/streaming/testdata/certs/cert.pem b/x-pack/filebeat/input/streaming/testdata/certs/cert.pem new file mode 100644 index 000000000000..43e187f1367f --- /dev/null +++ b/x-pack/filebeat/input/streaming/testdata/certs/cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIUS/rm8sWDc2a+eD9L+q+9XQpBa5MwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yNDEyMDUxMjM4NThaGA8yMTI0 +MTExMTEyMzg1OFowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx +ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBALhEaFVqFuYwSwH4GHhMeqhilC+sWXKaQP8QmaH7 +HWRST8Ko6YTT9NixUL4Qs5OmzCQFavRN9qtEo4wtqCJBOEyXQG1wAHuLWIY+KOCB +twUg8fP+uYaYUOQOYNLkBz7SLlejuZYTyGxepIkc+UeJRcOE36anIPHpc2KSr3Hm +vKJxZUVpQEbJvQ7pe7+iLL4jSOfzpQNcV9S/bzTo6taZXuo+ryEPlshkU/ME5VCN +LFrU3AW2fzKW0Xa/skkW5izCiAU8KNEy84UQM6aZkJfFi9O394i97sGgYg+q36XL +sXbZ+sCXHI3CGx+pwOx0h7S8n7iJJ7BbmwM6QuLFF6bFYkkCAwEAAaNTMFEwHQYD +VR0OBBYEFEHtfvey8SdncMr7VDqA2YhtEiGYMB8GA1UdIwQYMBaAFEHtfvey8Sdn +cMr7VDqA2YhtEiGYMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB +AKFcAeh9yhIbkkxvXl6ebmLcj817NVjhpcvDZlKP2MVu+w/h70w+JwBktLUlZlXd +UNkKEWZyRvrdmY+YN6rwY/QI75N17bcmDWy6QnNlVJF0AJkBSdbKonCgHrZm7K25 +TOKpj0QF8l7k9wr5FWHHcBw/vFF9cGZ5TO4HbnI25N/cEKgdzZFEVA5Y/Rv7GIGU +COjJG20Cr2HIKvVYoyWvN6sL7+gbzUMyjvQyGMCT7YoIqscUfrUU+T46QaOLAKa3 +z91Obfmv6uTO/rsieoxVWVJ35GeHeNJkAPkr7Z1sWIrreJ/3WsecWuPPEDNDXiSV +5h0bTbbPOyEIe5ydEIbr5kA= +-----END CERTIFICATE----- diff --git a/x-pack/filebeat/input/streaming/testdata/certs/key.pem b/x-pack/filebeat/input/streaming/testdata/certs/key.pem new file mode 100644 index 000000000000..1b6ce6bade3c --- /dev/null +++ b/x-pack/filebeat/input/streaming/testdata/certs/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC4RGhVahbmMEsB ++Bh4THqoYpQvrFlymkD/EJmh+x1kUk/CqOmE0/TYsVC+ELOTpswkBWr0TfarRKOM +LagiQThMl0BtcAB7i1iGPijggbcFIPHz/rmGmFDkDmDS5Ac+0i5Xo7mWE8hsXqSJ +HPlHiUXDhN+mpyDx6XNikq9x5ryicWVFaUBGyb0O6Xu/oiy+I0jn86UDXFfUv280 +6OrWmV7qPq8hD5bIZFPzBOVQjSxa1NwFtn8yltF2v7JJFuYswogFPCjRMvOFEDOm +mZCXxYvTt/eIve7BoGIPqt+ly7F22frAlxyNwhsfqcDsdIe0vJ+4iSewW5sDOkLi +xRemxWJJAgMBAAECggEAQprvf5hWaKQiKLcN2UYDvCPN3qGUv3kEb24HqmZDjIS4 +MeuuZQXcZgtJ3TnaP0+2UHro2x/nPqcT2tKSCLe8aurtLeGjOwT2XafQTL52clMj +Qgfb9cvOyXBtDS3BdLKyb5lNtvK1qn5XSPyBGpuC7RZ1ZR7aKLcyrvnIkwpNOwXW +zH5F6pI6HAUPfgYcHfIkQ5kuPCRcvfmv6m9XLYlmiQNkReQ2fWtFF6517R6FGtZu +Z8F0pFz8VtIGQoamX9vEwQhYqBK67msl9gnKjyH3ONckkSRMVagXrwx9F5o+NeRD +IgDFnjH1HgLCXmeCa7BN+eYfGMZ24xisItD7XBzGtQKBgQDlmEncIgpkmtXZSvXs +r5i7epJDDcxC8/ZObsn3zI01t4nmI9+phu7a4fAA+AUP7+HFVdi22JcHDkHZ5J1a +93t+Tcc4yzXk8FovaavRRvJNXv3WhHvgNpe1tvgyMUc8p9QpfbHuafVhQN2qWivh +nnEWagBoguiXaXEIFRXFK6dt5wKBgQDNdZYQ4/Am7HNjI2vqmMccZxuSufUX0xxM +LuDY8UAsPbgRN8wqfY67xCdMztax5y15gF9UPw0hHMlk4m2J4lsqCqgRRWXnTser +rNAseZ1j7MZY0cKACRxvXNtPKmmHKvYHUEZkADT/HrhfZWIce7KEXaxdoGTkssPd +9/WbahLITwKBgFBa2VbTDyIg0sGHK8UXu/O5tWEEfj3clpLi0YsJq05mmzvRyGDT +2dr/gnlEVLk8Mp9XKU7tRQZyJff1vGDvBuiwng4xiP5EZLv9VuYa14jeuyaOHbDe +SoCNthYTCySedHHFDTYtHXVZN3t8raj8RAYdOWFal78OZ0H15zWnzqR3AoGBAJne +mxFxM3RjFpNDftmFq3BpA6xiGdzK3OFtJjUykAXR/xzd9chImfGjGG+cZAt9/3+E +FWCpi7KltWoZbUGbRPz6WB3/JC8Tv9OhK5JzTdz9ARqZlRmAOUxpdVEXiUqScQjP +JLhVs1rw7dF7wvtj5DDfWmwP6B+iha+huM24pfJfAoGAUYeJQ1XqEx+0+b6xrtCm +qxPiiGnJSi4J9CGaZRMTG5qFSQ5jCaWTJSWdiZJgyBMnmQsiuPacefAg91z/NjJC +xM0/sKLe/yPWP1UlwrCl1MDjMwIl/qtWiKXYXpY1qcOONLCFc6OASd1cTOtX/7Km +2g49JWZEY71f7DxLdcWfqWM= +-----END PRIVATE KEY----- diff --git a/x-pack/filebeat/input/streaming/websocket.go b/x-pack/filebeat/input/streaming/websocket.go index 1deaf8b07fa5..8a8cf76fe361 100644 --- a/x-pack/filebeat/input/streaming/websocket.go +++ b/x-pack/filebeat/input/streaming/websocket.go @@ -7,6 +7,7 @@ package streaming import ( "bytes" "context" + "crypto/tls" "errors" "fmt" "io" @@ -14,6 +15,7 @@ import ( "math/rand/v2" "net" "net/http" + "net/url" "strings" "time" @@ -22,6 +24,8 @@ import ( inputcursor "github.com/elastic/beats/v7/filebeat/input/v2/input-cursor" "github.com/elastic/elastic-agent-libs/logp" + "github.com/elastic/elastic-agent-libs/transport/httpcommon" + "github.com/elastic/elastic-agent-libs/transport/tlscommon" ) type websocketStream struct { @@ -136,7 +140,7 @@ func (s *websocketStream) FollowStream(ctx context.Context) error { } s.metrics.receivedBytesTotal.Add(uint64(len(message))) state["response"] = message - s.log.Debugw("received websocket message", logp.Namespace("websocket"), string(message)) + s.log.Debugw("received websocket message", logp.Namespace("websocket"), "msg", string(message)) err = s.process(ctx, state, s.cursor, s.now().In(time.UTC)) if err != nil { s.metrics.errorsTotal.Inc() @@ -220,14 +224,18 @@ func connectWebSocket(ctx context.Context, cfg config, url string, log *logp.Log var response *http.Response var err error headers := formHeader(cfg) - + dialer, err := createWebSocketDialer(cfg) + if err != nil { + return nil, nil, err + } if cfg.Retry != nil { retryConfig := cfg.Retry for attempt := 1; attempt <= retryConfig.MaxAttempts; attempt++ { - conn, response, err = websocket.DefaultDialer.DialContext(ctx, url, headers) + conn, response, err = dialer.DialContext(ctx, url, headers) if err == nil { return conn, response, nil } + //nolint:errorlint // it will never be a wrapped error at this point if err == websocket.ErrBadHandshake { log.Errorf("attempt %d: webSocket connection failed with bad handshake (status %d) retrying...\n", attempt, response.StatusCode) continue @@ -239,7 +247,7 @@ func connectWebSocket(ctx context.Context, cfg config, url string, log *logp.Log return nil, nil, fmt.Errorf("failed to establish WebSocket connection after %d attempts with error %w", retryConfig.MaxAttempts, err) } - return websocket.DefaultDialer.DialContext(ctx, url, headers) + return dialer.DialContext(ctx, url, headers) } // calculateWaitTime calculates the wait time for the next attempt based on the exponential backoff algorithm. @@ -253,6 +261,10 @@ func calculateWaitTime(waitMin, waitMax time.Duration, attempt int) time.Duratio jitter := rand.Float64() * maxJitter waitTime := time.Duration(backoff + jitter) + // caps the wait time to the maximum wait time + if waitTime > waitMax { + waitTime = waitMax + } return waitTime } @@ -269,3 +281,42 @@ func (s *websocketStream) Close() error { s.metrics.Close() return nil } + +func createWebSocketDialer(cfg config) (*websocket.Dialer, error) { + var tlsConfig *tls.Config + dialer := &websocket.Dialer{ + Proxy: http.ProxyFromEnvironment, + } + + // load proxy configuration if available + if cfg.Transport.Proxy.URL != nil { + var proxy func(*http.Request) (*url.URL, error) + proxyURL, err := httpcommon.NewProxyURIFromString(cfg.Transport.Proxy.URL.String()) + if err != nil { + return nil, fmt.Errorf("failed to parse proxy URL: %w", err) + } + // create a custom HTTP Transport with proxy configuration + proxyTransport := &http.Transport{ + Proxy: http.ProxyURL(proxyURL.URI()), + ProxyConnectHeader: cfg.Transport.Proxy.Headers.Headers(), + DialContext: (&net.Dialer{ + Timeout: cfg.Transport.Timeout, + }).DialContext, + } + dialer.NetDialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { + return proxyTransport.DialContext(ctx, network, addr) + } + dialer.Proxy = proxy + } + // load TLS config if available + if cfg.Transport.TLS != nil { + TLSConfig, err := tlscommon.LoadTLSConfig(cfg.Transport.TLS) + if err != nil { + return nil, fmt.Errorf("failed to load TLS config: %w", err) + } + tlsConfig = TLSConfig.ToConfig() + dialer.TLSClientConfig = tlsConfig + } + + return dialer, nil +} diff --git a/x-pack/filebeat/input/unifiedlogs/config.go b/x-pack/filebeat/input/unifiedlogs/config.go new file mode 100644 index 000000000000..0999e7d768b8 --- /dev/null +++ b/x-pack/filebeat/input/unifiedlogs/config.go @@ -0,0 +1,75 @@ +// 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. + +//go:build darwin + +package unifiedlogs + +import ( + "fmt" + "strings" + "time" +) + +type config struct { + showConfig + commonConfig + Backfill bool `config:"backfill"` +} + +type showConfig struct { + ArchiveFile string `config:"archive_file"` + TraceFile string `config:"trace_file"` + Start string `config:"start"` + End string `config:"end"` +} + +type commonConfig struct { + Predicate []string `config:"predicate"` + Process []string `config:"process"` + Source bool `config:"source"` + Info bool `config:"info"` + Debug bool `config:"debug"` + Backtrace bool `config:"backtrace"` + Signpost bool `config:"signpost"` + Unreliable bool `config:"unreliable"` + MachContinuousTime bool `config:"mach_continuous_time"` +} + +func (c config) Validate() error { + if err := checkDateFormat(c.Start); err != nil { + return fmt.Errorf("start date is not valid: %w", err) + } + if err := checkDateFormat(c.End); err != nil { + return fmt.Errorf("end date is not valid: %w", err) + } + if c.ArchiveFile != "" && !strings.HasSuffix(c.ArchiveFile, ".logarchive") { + return fmt.Errorf("archive_file %v has the wrong extension", c.ArchiveFile) + } + if c.TraceFile != "" && !strings.HasSuffix(c.TraceFile, ".tracev3") { + return fmt.Errorf("trace_file %v has the wrong extension", c.TraceFile) + } + return nil +} + +func defaultConfig() config { + return config{} +} + +func checkDateFormat(date string) error { + if date == "" { + return nil + } + acceptedLayouts := []string{ + "2006-01-02", + "2006-01-02 15:04:05", + "2006-01-02 15:04:05-0700", + } + for _, layout := range acceptedLayouts { + if _, err := time.Parse(layout, date); err == nil { + return nil + } + } + return fmt.Errorf("not a valid date, accepted layouts are: %v", acceptedLayouts) +} diff --git a/x-pack/filebeat/input/unifiedlogs/input.go b/x-pack/filebeat/input/unifiedlogs/input.go new file mode 100644 index 000000000000..ca33c03c3bb6 --- /dev/null +++ b/x-pack/filebeat/input/unifiedlogs/input.go @@ -0,0 +1,385 @@ +// 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. + +//go:build darwin + +package unifiedlogs + +import ( + "bufio" + "context" + "encoding/json" + "fmt" + "io" + "os/exec" + "sync" + "sync/atomic" + "time" + + "golang.org/x/sync/errgroup" + + v2 "github.com/elastic/beats/v7/filebeat/input/v2" + inputcursor "github.com/elastic/beats/v7/filebeat/input/v2/input-cursor" + "github.com/elastic/beats/v7/libbeat/beat" + "github.com/elastic/beats/v7/libbeat/feature" + "github.com/elastic/beats/v7/libbeat/monitoring/inputmon" + conf "github.com/elastic/elastic-agent-libs/config" + "github.com/elastic/elastic-agent-libs/logp" + "github.com/elastic/elastic-agent-libs/mapstr" + "github.com/elastic/go-concert/ctxtool" +) + +const ( + inputName = "unifiedlogs" + srcArchiveName = "log-cmd-archive" + srcPollName = "log-cmd-poll" + logDateLayout = "2006-01-02 15:04:05.999999-0700" + cursorDateLayout = "2006-01-02 15:04:05-0700" +) + +var ( + // override for testing + timeNow = time.Now +) + +func Plugin(log *logp.Logger, store inputcursor.StateStore) v2.Plugin { + return v2.Plugin{ + Name: inputName, + Stability: feature.Stable, + Deprecated: false, + Manager: &inputcursor.InputManager{ + Logger: log, + StateStore: store, + Type: inputName, + Configure: cursorConfigure, + }, + } +} + +type logRecord struct { + Timestamp string `json:"timestamp"` +} + +type source struct { + name string +} + +func newSource(config config) source { + if config.ArchiveFile != "" || config.TraceFile != "" { + return source{name: srcArchiveName} + } + return source{name: srcPollName} +} + +func (src source) Name() string { return src.name } + +type input struct { + config + metrics *inputMetrics +} + +func cursorConfigure(cfg *conf.C) ([]inputcursor.Source, inputcursor.Input, error) { + conf := defaultConfig() + if err := cfg.Unpack(&conf); err != nil { + return nil, nil, err + } + sources, inp := newCursorInput(conf) + return sources, inp, nil +} + +func newCursorInput(config config) ([]inputcursor.Source, inputcursor.Input) { + input := &input{config: config} + return []inputcursor.Source{newSource(config)}, input +} + +func (input) Name() string { return inputName } + +func (input input) Test(src inputcursor.Source, _ v2.TestContext) error { + if _, err := exec.LookPath("log"); err != nil { + return err + } + return nil +} + +// Run starts the input and blocks until it ends the execution. +func (input *input) Run(ctxt v2.Context, src inputcursor.Source, resumeCursor inputcursor.Cursor, pub inputcursor.Publisher) error { + reg, unreg := inputmon.NewInputRegistry(input.Name(), ctxt.ID, nil) + defer unreg() + input.metrics = newInputMetrics(reg) + + stdCtx := ctxtool.FromCanceller(ctxt.Cancelation) + log := ctxt.Logger.With("source", src.Name()) + + startFrom, err := loadCursor(resumeCursor, log) + if err != nil { + return err + } + if startFrom != "" { + input.Start = startFrom + } + + return input.runWithMetrics(stdCtx, pub, log) +} + +func (input *input) runWithMetrics(ctx context.Context, pub inputcursor.Publisher, log *logp.Logger) error { + // we create a wrapped publisher for the streaming go routine. + // It will notify the backfilling goroutine with the end date of the + // backfilling period and avoid updating the stored date to resume + // until backfilling is done. + wrappedPub := newWrappedPublisher(!input.mustBackfill(), pub) + + var g errgroup.Group + // we start the streaming command in the background + // it will use the wrapped publisher to set the end date for the + // backfilling process. + if input.mustStream() { + g.Go(func() error { + logCmd := newLogStreamCmd(ctx, input.commonConfig) + return input.runLogCmd(ctx, logCmd, wrappedPub, log) + }) + } + + if input.mustBackfill() { + g.Go(func() error { + if input.mustStream() { + t := wrappedPub.getFirstProcessedTime() + // The time resolution of the log tool is microsecond, while it only + // accepts second resolution as an end parameter. + // To avoid potentially losing data we move the end forward one second, + // since it is preferable to have some duplicated events. + t = t.Add(time.Second) + input.End = t.Format(cursorDateLayout) + + // to avoid race conditions updating the cursor, and to be able to + // resume from the oldest point in time, we only update cursor + // from the streaming goroutine once backfilling is done. + defer wrappedPub.startUpdatingCursor() + } + logCmd := newLogShowCmd(ctx, input.config) + err := input.runLogCmd(ctx, logCmd, pub, log) + if !input.mustStream() { + log.Debugf("finished processing events, stopping") + } + return err + }) + } + + return g.Wait() +} + +// mustStream returns true in case a stream command is needed. +// This is the default case and the only exceptions are when an archive file or an end date are set. +func (input *input) mustStream() bool { + return !(input.ArchiveFile != "" || input.TraceFile != "" || input.End != "") +} + +// mustBackfill returns true in case a show command is needed. +// This happens when start or end dates are set (for example when resuming filebeat), when an archive file is used, +// or when user forces it via the backfill config. +func (input *input) mustBackfill() bool { + return input.Backfill || input.ArchiveFile != "" || input.TraceFile != "" || input.Start != "" || input.End != "" +} + +func (input *input) runLogCmd(ctx context.Context, logCmd *exec.Cmd, pub inputcursor.Publisher, log *logp.Logger) error { + outpipe, err := logCmd.StdoutPipe() + if err != nil { + return fmt.Errorf("get stdout pipe: %w", err) + } + errpipe, err := logCmd.StderrPipe() + if err != nil { + return fmt.Errorf("get stderr pipe: %w", err) + } + + log.Debugf("exec command start: %v", logCmd) + defer log.Debugf("exec command end: %v", logCmd) + + if err := logCmd.Start(); err != nil { + return fmt.Errorf("start log command: %w", err) + } + + if err := input.processLogs(outpipe, pub, log); err != nil { + log.Errorf("process logs: %v", err) + } + + stderrBytes, _ := io.ReadAll(errpipe) + if err := logCmd.Wait(); err != nil && ctx.Err() == nil { + return fmt.Errorf("%q exited with an error: %w, %q", logCmd, err, string(stderrBytes)) + } + + return nil +} + +func (input *input) processLogs(stdout io.Reader, pub inputcursor.Publisher, log *logp.Logger) error { + scanner := bufio.NewScanner(stdout) + + var ( + event beat.Event + line string + logRecordLine logRecord + timestamp time.Time + err error + ) + + for scanner.Scan() { + line = scanner.Text() + if err = json.Unmarshal([]byte(line), &logRecordLine); err != nil { + log.Errorf("invalid json log: %v", err) + input.metrics.errs.Add(1) + continue + } + + if logRecordLine == (logRecord{}) { + continue + } + + timestamp, err = time.Parse(logDateLayout, logRecordLine.Timestamp) + if err != nil { + input.metrics.errs.Add(1) + log.Errorf("invalid timestamp: %v", err) + continue + } + + event = makeEvent(timestamp, line) + if err = pub.Publish(event, timestamp); err != nil { + log.Errorf("publish event: %v", err) + input.metrics.errs.Add(1) + continue + } + } + if err = scanner.Err(); err != nil { + input.metrics.errs.Add(1) + return fmt.Errorf("scanning stdout: %w", err) + } + + return nil +} + +// wrappedPublisher wraps a publisher and stores the first published event date. +// this is required in order to backfill the events when we start a streaming command. +type wrappedPublisher struct { + firstTimeOnce sync.Once + firstTimeC chan struct{} + firstProcessedTime time.Time + + updateCursor *atomic.Bool + + inner inputcursor.Publisher +} + +func newWrappedPublisher(updateCursor bool, inner inputcursor.Publisher) *wrappedPublisher { + var atomicUC atomic.Bool + atomicUC.Store(updateCursor) + return &wrappedPublisher{ + firstTimeC: make(chan struct{}), + updateCursor: &atomicUC, + inner: inner, + } +} + +func (pub *wrappedPublisher) Publish(event beat.Event, cursor interface{}) error { + pub.firstTimeOnce.Do(func() { + pub.firstProcessedTime = cursor.(time.Time) + close(pub.firstTimeC) + }) + if !pub.updateCursor.Load() { + cursor = nil + } + return pub.inner.Publish(event, cursor) +} + +// getFirstProcessedTime will block until there is a value set for firstProcessedTime. +func (pub *wrappedPublisher) getFirstProcessedTime() time.Time { + <-pub.firstTimeC + return pub.firstProcessedTime +} + +func (pub *wrappedPublisher) startUpdatingCursor() { + pub.updateCursor.Store(true) +} + +func loadCursor(c inputcursor.Cursor, log *logp.Logger) (string, error) { + if c.IsNew() { + return "", nil + } + var ( + startFrom string + cursor time.Time + ) + if err := c.Unpack(&cursor); err != nil { + return "", fmt.Errorf("unpack cursor: %w", err) + } + log.Infof("cursor loaded, resuming from: %v", startFrom) + return cursor.Format(cursorDateLayout), nil +} + +func newLogShowCmd(ctx context.Context, cfg config) *exec.Cmd { + return exec.CommandContext(ctx, "log", newLogCmdArgs("show", cfg)...) // #nosec G204 +} + +func newLogStreamCmd(ctx context.Context, cfg commonConfig) *exec.Cmd { + return exec.CommandContext(ctx, "log", newLogCmdArgs("stream", config{commonConfig: cfg})...) // #nosec G204 +} + +func newLogCmdArgs(subcmd string, config config) []string { + args := []string{subcmd, "--style", "ndjson"} + if config.ArchiveFile != "" { + args = append(args, "--archive", config.ArchiveFile) + } + if config.TraceFile != "" { + args = append(args, "--file", config.TraceFile) + } + if len(config.Predicate) > 0 { + for _, p := range config.Predicate { + args = append(args, "--predicate", p) + } + } + if len(config.Process) > 0 { + for _, p := range config.Process { + args = append(args, "--process", p) + } + } + if config.Source { + args = append(args, "--source") + } + if config.Info { + args = append(args, "--info") + } + if config.Debug { + args = append(args, "--debug") + } + if config.Backtrace { + args = append(args, "--backtrace") + } + if config.Signpost { + args = append(args, "--signpost") + } + if config.Unreliable { + args = append(args, "--unreliable") + } + if config.MachContinuousTime { + args = append(args, "--mach-continuous-time") + } + if config.Start != "" { + args = append(args, "--start", config.Start) + } + if config.End != "" { + args = append(args, "--end", config.End) + } + return args +} + +func makeEvent(timestamp time.Time, message string) beat.Event { + now := timeNow() + fields := mapstr.M{ + "event": mapstr.M{ + "created": now, + }, + "message": message, + } + + return beat.Event{ + Timestamp: timestamp, + Fields: fields, + } +} diff --git a/x-pack/filebeat/input/unifiedlogs/input_test.go b/x-pack/filebeat/input/unifiedlogs/input_test.go new file mode 100644 index 000000000000..907c927254d3 --- /dev/null +++ b/x-pack/filebeat/input/unifiedlogs/input_test.go @@ -0,0 +1,391 @@ +// 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. + +//go:build darwin + +package unifiedlogs + +import ( + "bufio" + "bytes" + "context" + "fmt" + "os" + "os/exec" + "path" + "regexp" + "strings" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + inputcursor "github.com/elastic/beats/v7/filebeat/input/v2/input-cursor" + "github.com/elastic/beats/v7/libbeat/beat" + "github.com/elastic/elastic-agent-libs/logp" +) + +var _ inputcursor.Publisher = (*publisher)(nil) + +type publisher struct { + m sync.Mutex + + events []beat.Event + cursors []*time.Time +} + +func (p *publisher) Publish(e beat.Event, cursor interface{}) error { + p.m.Lock() + defer p.m.Unlock() + + p.events = append(p.events, e) + var c *time.Time + if cursor != nil { + cv := cursor.(time.Time) + c = &cv + } + p.cursors = append(p.cursors, c) + return nil +} + +func TestInput(t *testing.T) { + archivePath, err := openArchive() + require.NoError(t, err) + t.Cleanup(func() { os.RemoveAll(archivePath) }) + + testCases := []struct { + name string + cfg config + timeUntilClose time.Duration + assertFunc func(collect *assert.CollectT, events []beat.Event, cursors []*time.Time) + expectedLogStreamCmd string + expectedLogShowCmd string + expectedRunErrorMsg string + }{ + { + name: "Default stream", + cfg: config{}, + timeUntilClose: time.Second, + expectedLogStreamCmd: "/usr/bin/log stream --style ndjson", + assertFunc: func(collect *assert.CollectT, events []beat.Event, cursors []*time.Time) { + assert.NotEmpty(collect, events) + assert.NotEmpty(collect, cursors) + assert.Equal(collect, len(events), len(cursors)) + lastEvent := events[len(events)-1] + lastCursor := cursors[len(cursors)-1] + assert.EqualValues(collect, &lastEvent.Timestamp, lastCursor) + }, + }, + { + name: "Archive not found", + cfg: config{ + showConfig: showConfig{ + ArchiveFile: "notfound.logarchive", + }, + }, + timeUntilClose: time.Second, + expectedLogShowCmd: "/usr/bin/log show --style ndjson --archive notfound.logarchive", + expectedRunErrorMsg: "\"/usr/bin/log show --style ndjson --archive notfound.logarchive\" exited with an error: exit status 64", + }, + { + name: "Archived file", + cfg: config{ + showConfig: showConfig{ + ArchiveFile: archivePath, + }, + }, + timeUntilClose: time.Second, + expectedLogShowCmd: fmt.Sprintf("/usr/bin/log show --style ndjson --archive %s", archivePath), + assertFunc: eventsAndCursorAssertN(462), + }, + { + name: "Trace file", + cfg: config{ + showConfig: showConfig{ + TraceFile: path.Join(archivePath, "logdata.LiveData.tracev3"), + }, + }, + timeUntilClose: time.Second, + expectedLogShowCmd: fmt.Sprintf("/usr/bin/log show --style ndjson --file %s", path.Join(archivePath, "logdata.LiveData.tracev3")), + assertFunc: eventsAndCursorAssertN(7), + }, + { + name: "With start date", + cfg: config{ + showConfig: showConfig{ + ArchiveFile: archivePath, + Start: "2024-12-04 13:46:00+0200", + }, + }, + timeUntilClose: time.Second, + expectedLogShowCmd: fmt.Sprintf("/usr/bin/log show --style ndjson --archive %s --start 2024-12-04 13:46:00+0200", archivePath), + assertFunc: eventsAndCursorAssertN(314), + }, + { + name: "With start and end dates", + cfg: config{ + showConfig: showConfig{ + ArchiveFile: archivePath, + Start: "2024-12-04 13:45:00+0200", + End: "2024-12-04 13:46:00+0200", + }, + }, + timeUntilClose: time.Second, + expectedLogShowCmd: fmt.Sprintf("/usr/bin/log show --style ndjson --archive %s --start 2024-12-04 13:45:00+0200 --end 2024-12-04 13:46:00+0200", archivePath), + assertFunc: eventsAndCursorAssertN(149), + }, + { + name: "With end date", + cfg: config{ + showConfig: showConfig{ + ArchiveFile: archivePath, + End: "2024-12-04 13:46:00+0200", + }, + }, + timeUntilClose: time.Second, + expectedLogShowCmd: fmt.Sprintf("/usr/bin/log show --style ndjson --archive %s --end 2024-12-04 13:46:00+0200", archivePath), + assertFunc: eventsAndCursorAssertN(462), + }, + { + name: "With predicate", + cfg: config{ + showConfig: showConfig{ + ArchiveFile: archivePath, + }, + commonConfig: commonConfig{ + Predicate: []string{ + `processImagePath == "/kernel"`, + }, + }, + }, + timeUntilClose: time.Second, + expectedLogShowCmd: fmt.Sprintf("/usr/bin/log show --style ndjson --archive %s --predicate processImagePath == \"/kernel\"", archivePath), + assertFunc: eventsAndCursorAssertN(460), + }, + { + name: "With process", + cfg: config{ + showConfig: showConfig{ + ArchiveFile: archivePath, + }, + commonConfig: commonConfig{ + Process: []string{ + "0", + }, + }, + }, + timeUntilClose: time.Second, + expectedLogShowCmd: fmt.Sprintf("/usr/bin/log show --style ndjson --archive %s --process 0", archivePath), + assertFunc: eventsAndCursorAssertN(462), + }, + { + name: "With optional flags", + cfg: config{ + showConfig: showConfig{ + ArchiveFile: archivePath, + }, + commonConfig: commonConfig{ + Info: true, + Debug: true, + Backtrace: true, + Signpost: true, + MachContinuousTime: true, + }, + }, + timeUntilClose: time.Second, + expectedLogShowCmd: fmt.Sprintf("/usr/bin/log show --style ndjson --archive %s --info --debug --backtrace --signpost --mach-continuous-time", archivePath), + assertFunc: eventsAndCursorAssertN(462), + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + _, cursorInput := newCursorInput(tc.cfg) + input := cursorInput.(*input) + + ctx, cancel := context.WithCancel(context.Background()) + + pub := &publisher{} + log, buf := logp.NewInMemory("unifiedlogs_test", logp.JSONEncoderConfig()) + + var wg sync.WaitGroup + wg.Add(1) + go func(t *testing.T) { + defer wg.Done() + err := input.runWithMetrics(ctx, pub, log) + if tc.expectedRunErrorMsg == "" { + assert.NoError(t, err) + } else { + assert.ErrorContains(t, err, tc.expectedRunErrorMsg) + } + }(t) + + select { + case <-ctx.Done(): + case <-time.After(tc.timeUntilClose): + } + + cancel() + wg.Wait() + + assert.EventuallyWithT(t, + func(collect *assert.CollectT) { + assert.Equal(collect, tc.expectedLogStreamCmd, filterStartLogStreamLogline(buf.Bytes())) + assert.Equal(collect, tc.expectedLogShowCmd, filterStartLogShowLogline(buf.Bytes())) + if tc.assertFunc != nil { + tc.assertFunc(collect, pub.events, pub.cursors) + } + }, + 30*time.Second, time.Second, + ) + }) + } +} + +func TestBackfillAndStream(t *testing.T) { + archivePath, err := openArchive() + require.NoError(t, err) + t.Cleanup(func() { os.RemoveAll(archivePath) }) + + cfg := config{ + Backfill: true, + showConfig: showConfig{ + Start: time.Now().Add(-5 * time.Second).Format("2006-01-02 15:04:05"), + }, + commonConfig: commonConfig{ + Info: true, + Debug: true, + Backtrace: true, + Signpost: true, + MachContinuousTime: true, + }, + } + + expectedLogShowCmd := fmt.Sprintf("/usr/bin/log show --style ndjson --info --debug --backtrace --signpost --mach-continuous-time --start %v", time.Now().Format("2006-01-02")) + expectedLogStreamCmd := "/usr/bin/log stream --style ndjson --info --debug --backtrace --signpost --mach-continuous-time" + + _, cursorInput := newCursorInput(cfg) + input := cursorInput.(*input) + + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + pub := &publisher{} + log, buf := logp.NewInMemory("unifiedlogs_test", logp.JSONEncoderConfig()) + + var wg sync.WaitGroup + wg.Add(1) + go func(t *testing.T) { + defer wg.Done() + err := input.runWithMetrics(ctx, pub, log) + assert.NoError(t, err) + }(t) + + var firstStreamedEventTime *time.Time + assert.EventuallyWithT(t, + func(collect *assert.CollectT) { + showCmdLog := filterStartLogShowLogline(buf.Bytes()) + assert.Equal(collect, expectedLogStreamCmd, filterStartLogStreamLogline(buf.Bytes())) + assert.True(collect, strings.HasPrefix(showCmdLog, expectedLogShowCmd)) + assert.NotEmpty(collect, pub.events) + assert.NotEmpty(collect, pub.cursors) + + var endTime time.Time + regex := regexp.MustCompile(`--end\s+(\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}[+-]\d{4})`) + matches := regex.FindStringSubmatch(showCmdLog) + assert.Equal(collect, 2, len(matches)) + endTime, _ = time.Parse("2006-01-02 15:04:05-0700", matches[1]) + endTime = endTime.Truncate(time.Second) + + if firstStreamedEventTime == nil { + for i := range pub.events { + if pub.cursors[i] == nil { + first := pub.events[i].Timestamp.Add(time.Second).Truncate(time.Second) + firstStreamedEventTime = &first + break + } + } + } + assert.NotNil(collect, firstStreamedEventTime) + assert.EqualValues(collect, endTime, *firstStreamedEventTime) + assert.True(collect, strings.HasPrefix(showCmdLog, filterEndLogShowLogline(buf.Bytes()))) + }, + 30*time.Second, time.Second, + ) + + cancel() + wg.Wait() +} + +const ( + cmdStartPrefix = "exec command start: " + cmdEndPrefix = "exec command end: " +) + +func filterStartLogStreamLogline(buf []byte) string { + const cmd = "/usr/bin/log stream" + return filterLogCmdLine(buf, cmd, cmdStartPrefix) +} + +func filterStartLogShowLogline(buf []byte) string { + const cmd = "/usr/bin/log show" + return filterLogCmdLine(buf, cmd, cmdStartPrefix) +} + +func filterEndLogShowLogline(buf []byte) string { + const cmd = "/usr/bin/log show" + return filterLogCmdLine(buf, cmd, cmdEndPrefix) +} + +func filterLogCmdLine(buf []byte, cmd, cmdPrefix string) string { + scanner := bufio.NewScanner(bytes.NewBuffer(buf)) + for scanner.Scan() { + text := scanner.Text() + parts := strings.Split(text, "\t") + if len(parts) != 4 { + continue + } + + trimmed := strings.TrimPrefix(parts[3], cmdStartPrefix) + if strings.HasPrefix(trimmed, cmd) { + return trimmed + } + } + return "" +} + +func eventsAndCursorAssertN(n int) func(collect *assert.CollectT, events []beat.Event, cursors []*time.Time) { + return func(collect *assert.CollectT, events []beat.Event, cursors []*time.Time) { + assert.Equal(collect, n, len(events)) + assert.Equal(collect, n, len(cursors)) + lastEvent := events[len(events)-1] + lastCursor := cursors[len(cursors)-1] + assert.EqualValues(collect, &lastEvent.Timestamp, lastCursor) + } +} + +func openArchive() (string, error) { + return extractTarGz(path.Join("testdata", "test.logarchive.tar.gz")) +} + +func extractTarGz(tarGzPath string) (string, error) { + // Create a temporary directory + tempDir, err := os.MkdirTemp("", "extracted-*") + if err != nil { + return "", fmt.Errorf("failed to create temporary directory: %v", err) + } + + // Use the 'tar' command to extract the .tar.gz file + cmd := exec.Command("tar", "-xzf", tarGzPath, "-C", tempDir) + + // Run the command + if err := cmd.Run(); err != nil { + return "", fmt.Errorf("failed to extract .tar.gz: %v", err) + } + + return path.Join(tempDir, "test.logarchive"), nil +} diff --git a/x-pack/filebeat/input/unifiedlogs/metrics.go b/x-pack/filebeat/input/unifiedlogs/metrics.go new file mode 100644 index 000000000000..2e24c0b4121f --- /dev/null +++ b/x-pack/filebeat/input/unifiedlogs/metrics.go @@ -0,0 +1,27 @@ +// 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. + +//go:build darwin + +package unifiedlogs + +import ( + "github.com/elastic/elastic-agent-libs/monitoring" +) + +type inputMetrics struct { + errs *monitoring.Uint // total number of errors +} + +func newInputMetrics(reg *monitoring.Registry) *inputMetrics { + if reg == nil { + return nil + } + + out := &inputMetrics{ + errs: monitoring.NewUint(reg, "errors_total"), + } + + return out +} diff --git a/x-pack/filebeat/input/unifiedlogs/testdata/test.logarchive.tar.gz b/x-pack/filebeat/input/unifiedlogs/testdata/test.logarchive.tar.gz new file mode 100644 index 000000000000..fc507f9b1e9e Binary files /dev/null and b/x-pack/filebeat/input/unifiedlogs/testdata/test.logarchive.tar.gz differ diff --git a/x-pack/functionbeat/.gitignore b/x-pack/functionbeat/.gitignore deleted file mode 100644 index e89322a26571..000000000000 --- a/x-pack/functionbeat/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -.idea -.vagrant -.vscode -/*/_meta/kibana.generated -functionbeat -functionbeat.test -build -data -logs -./fields.yml diff --git a/x-pack/functionbeat/Dockerfile b/x-pack/functionbeat/Dockerfile deleted file mode 100644 index f903da58b533..000000000000 --- a/x-pack/functionbeat/Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -FROM golang:1.22.9 - -RUN \ - apt-get update \ - && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ - netcat-openbsd \ - rsync \ - python3 \ - python3-pip \ - python3-venv \ - && rm -rf /var/lib/apt/lists/* - -# Use a virtualenv to avoid the PEP668 "externally managed environment" error caused by conflicts -# with the system Python installation. golang:1.20.6 uses Debian 12 which now enforces PEP668. -ENV VIRTUAL_ENV=/opt/venv -RUN python3 -m venv $VIRTUAL_ENV -ENV PATH="$VIRTUAL_ENV/bin:$PATH" - -RUN pip3 install --upgrade pip==20.1.1 - -# Setup work environment -ENV FUNCTIONBEAT_PATH /go/src/github.com/elastic/beats/x-pack/functionbeat - -RUN mkdir -p $FUNCTIONBEAT_PATH/build/coverage -WORKDIR $FUNCTIONBEAT_PATH diff --git a/x-pack/functionbeat/Jenkinsfile.yml b/x-pack/functionbeat/Jenkinsfile.yml deleted file mode 100644 index d67e79288728..000000000000 --- a/x-pack/functionbeat/Jenkinsfile.yml +++ /dev/null @@ -1,100 +0,0 @@ -when: - branches: true ## for all the branches - changeset: ## when PR contains any of those entries in the changeset - - "^x-pack/functionbeat/.*" - - "@ci" ## special token regarding the changeset for the ci - - "@xpack" ## special token regarding the changeset for the xpack - comments: ## when PR comment contains any of those entries - - "/test x-pack/functionbeat" - labels: ## when PR labels matches any of those entries - - "x-pack-functionbeat" - parameters: ## when parameter was selected in the UI. - - "x-pack-functionbeat" - tags: true ## for all the tags -platform: "immutable && ubuntu-22" ## default label for all the stages -stages: - arm: - mage: "mage build unitTest" - platforms: ## override default label in this specific stage. - - "ubuntu-2204-aarch64" - when: ## Override the top-level when. - comments: - - "/test x-pack/functionbeat for arm" - labels: - - "arm" - parameters: - - "armTest" - stage: extended - unitTest: - mage: "mage build unitTest" - stage: mandatory - goIntegTest: - mage: "mage goIntegTest" - stage: mandatory - macos: - mage: "mage build unitTest" - platforms: ## override default label in this specific stage. - - "macos12 && x86_64" - when: ## Override the top-level when. - comments: - - "/test x-pack/functionbeat for macos" - labels: - - "macOS" - parameters: - - "macosTest" - tags: true ## for all the tags - stage: extended - macosM1: - mage: "mage build unitTest" - platforms: ## override default label in this specific stage. - - "orka && darwin && aarch64" - when: ## Override the top-level when. - comments: - - "/test functonbeat for macos-m1" - labels: - - "macos-m1" - parameters: - - "macosM1Test" - tags: false ## for all the tags - stage: extended - windows-2022: - mage: "mage build unitTest" - platforms: ## override default labels in this specific stage. - - "windows-2022" - stage: mandatory - windows-2019: - mage: "mage build unitTest" - platforms: ## override default labels in this specific stage. - - "windows-2019" - stage: extended_win - windows-2016: - mage: "mage build unitTest" - platforms: ## override default labels in this specific stage. - - "windows-2016" - stage: mandatory - windows-2012: - mage: "mage build unitTest" - platforms: ## override default labels in this specific stage. - - "windows-2012-r2" - stage: extended_win - windows-10: - mage: "mage build unitTest" - platforms: ## override default labels in this specific stage. - - "windows-10" - stage: extended_win - windows-8: - mage: "mage build unitTest" - platforms: ## override default labels in this specific stage. - - "windows-8" - stage: extended_win - packaging-linux: - packaging-linux: "mage package" - e2e: - enabled: false - stage: packaging - when: - branches: false ## Only on a PR basis for the time being - tags: false ## packaging on branches/tags is already in place with the downstream build. - changeset: ## when PR contains any of those entries in the changeset - - "^x-pack/functionbeat/.*" - - "@xpack" ## special token regarding the changeset for the xpack diff --git a/x-pack/functionbeat/Makefile b/x-pack/functionbeat/Makefile deleted file mode 100644 index be4e2ceaeb31..000000000000 --- a/x-pack/functionbeat/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Variables -# -GOX_FLAGS=-arch="amd64 386 arm ppc64 ppc64le" -ES_BEATS?=../../ - -# -# Includes -# -include $(ES_BEATS)/dev-tools/make/mage.mk diff --git a/x-pack/functionbeat/_meta/config/beat.reference.yml.tmpl b/x-pack/functionbeat/_meta/config/beat.reference.yml.tmpl deleted file mode 100644 index 2f280df4c3ac..000000000000 --- a/x-pack/functionbeat/_meta/config/beat.reference.yml.tmpl +++ /dev/null @@ -1,297 +0,0 @@ -########################## Functionbeat Configuration ########################### - -# This file is a full configuration example documenting all non-deprecated -# options in comments. For a shorter configuration example, that contains only -# the most common options, please see functionbeat.yml in the same directory. -# -# You can find the full configuration reference here: -# https://www.elastic.co/guide/en/beats/functionbeat/index.html - -{{header "Provider"}} -# Configure functions to run on AWS Lambda, currently, we assume that the credentials -# are present in the environment to correctly create the function when using the CLI. -# -# Configure which S3 endpoint should we use. -functionbeat.provider.aws.endpoint: "s3.amazonaws.com" -# Configure which S3 bucket we should upload the lambda artifact. -functionbeat.provider.aws.deploy_bucket: "functionbeat-deploy" - -# Configure credentials of Functionbeat while deploying to AWS. -# Available options: -# * access_key_id, secret_access_key and/or session_token -#functionbeat.provider.aws.access_key_id: '${AWS_ACCESS_KEY_ID:""}' -#functionbeat.provider.aws.secret_access_key: '${AWS_SECRET_ACCESS_KEY:""}' -#functionbeat.provider.aws.session_token: '${AWS_SESSION_TOKEN:""}' -# * role_arn -#functionbeat.provider.aws.role_arn: arn:aws:iam::123456789012:role/test-fnb -# * credential_profile_name and/or shared_credential_file -#functionbeat.provider.aws.credential_profile_name: fnb-aws -#functionbeat.provider.aws.shared_credential_file: /etc/functionbeat/aws_credentials - -functionbeat.provider.aws.functions: - # Define the list of functions available, each function is required to have a unique name. - # Create a function that accepts events coming from cloudwatchlogs. - - name: cloudwatch - enabled: false - type: cloudwatch_logs - - # Description of the method to help identify them when you run multiple functions. - description: "lambda function for cloudwatch logs" - - # Concurrency, is the reserved number of instances for that function. - # Default is 5. - # - # Note: There is a hard limit of 1000 functions of any kind per account. - #concurrency: 5 - - # The maximum memory allocated for this function, the configured size must be a factor of 64. - # There is a hard limit of 3008MiB for each function. Default is 128MiB. - #memory_size: 128MiB - - # The amount of time the function is allowed to run. - #timeout: 3s - - # Execution role of the function. - #role: arn:aws:iam::123456789012:role/MyFunction - - # Connect to private resources in an Amazon VPC. - #virtual_private_cloud: - # security_group_ids: [] - # subnet_ids: [] - - # Dead letter queue configuration, this must be set to an ARN pointing to an SQS queue. - #dead_letter_config.target_arn: - - # Tags are key-value pairs attached to the function. - #tags: - # department: ops - - # Optional fields that you can specify to add additional information to the - # output. Fields can be scalar values, arrays, dictionaries, or any nested - # combination of these. - #fields: - # env: staging - - # List of cloudwatch log group registered to that function. - triggers: - - log_group_name: /aws/lambda/functionbeat-cloudwatch - #filter_pattern: mylog_ - - # Define custom processors for this function. - #processors: - # - dissect: - # tokenizer: "%{key1} %{key2}" - - # Set to true to publish fields with null values in events. - #keep_null: false - - # Create a function that accepts events from SQS queues. - - name: sqs - enabled: false - type: sqs - - # Description of the method to help identify them when you run multiple functions. - description: "lambda function for SQS events" - - # Concurrency, is the reserved number of instances for that function. - # Default is 5. - # - # Note: There is a hard limit of 1000 functions of any kind per account. - #concurrency: 5 - - # The maximum memory allocated for this function, the configured size must be a factor of 64. - # There is a hard limit of 3008MiB for each function. Default is 128MiB. - #memory_size: 128MiB - - # The amount of time the function is allowed to run. - #timeout: 3s - - # Execution role of the function. - #role: arn:aws:iam::123456789012:role/MyFunction - - # Connect to private resources in an Amazon VPC. - #virtual_private_cloud: - # security_group_ids: [] - # subnet_ids: [] - - # Dead letter queue configuration, this must be set to an ARN pointing to an SQS queue. - #dead_letter_config.target_arn: - - # Tags are key-value pairs attached to the function. - #tags: - # department: ops - - # Optional fields that you can specify to add additional information to the - # output. Fields can be scalar values, arrays, dictionaries, or any nested - # combination of these. - #fields: - # env: staging - - # List of SQS queues. - triggers: - # Arn for the SQS queue. - - event_source_arn: arn:aws:sqs:us-east-1:xxxxx:myevents - - # Define custom processors for this function. - #processors: - # - decode_json_fields: - # fields: ["message"] - # process_array: false - # max_depth: 1 - # target: "" - # overwrite_keys: false - # - - # Set to true to publish fields with null values in events. - #keep_null: false - - # Create a function that accepts events from Kinesis streams. - - name: kinesis - enabled: false - type: kinesis - - # Description of the method to help identify them when you run multiple functions. - description: "lambda function for Kinesis events" - - # Concurrency, is the reserved number of instances for that function. - # Default is 5. - # - # Note: There is a hard limit of 1000 functions of any kind per account. - #concurrency: 5 - - # The maximum memory allocated for this function, the configured size must be a factor of 64. - # There is a hard limit of 3008MiB for each function. Default is 128MiB. - #memory_size: 128MiB - - # The amount of time the function is allowed to run. - #timeout: 3s - - # Execution role of the function. - #role: arn:aws:iam::123456789012:role/MyFunction - - # Connect to private resources in an Amazon VPC. - #virtual_private_cloud: - # security_group_ids: [] - # subnet_ids: [] - - # Dead letter queue configuration, this must be set to an ARN pointing to an SQS queue. - #dead_letter_config.target_arn: - - # Tags are key-value pairs attached to the function. - #tags: - # department: ops - - # Optional fields that you can specify to add additional information to the - # output. Fields can be scalar values, arrays, dictionaries, or any nested - # combination of these. - #fields: - # env: staging - - # Define custom processors for this function. - #processors: - # This example extracts the raw data from events. - # - decode_base64_field: - # field: - # from: message - # to: message - # - decompress_gzip_field: - # field: - # from: message - # to: message - # - decode_json_fields: - # fields: ["message"] - # process_array: false - # max_depth: 1 - # target: "" - # overwrite_keys: false - - # List of Kinesis streams. - triggers: - # Arn for the Kinesis stream. - - event_source_arn: arn:aws:kinesis:us-east-1:xxxxx:myevents - - # batch_size is the number of events read in a batch. - # Default is 10. - #batch_size: 100 - - # Starting position is where to start reading events from the Kinesis stream. - # Default is trim_horizon. - #starting_position: "trim_horizon" - - # parallelization_factor is the number of batches to process from each shard concurrently. - # Default is 1. - #parallelization_factor: 1 - - # Set to true to publish fields with null values in events. - #keep_null: false - - # Create a function that accepts Cloudwatch logs from Kinesis streams. - - name: cloudwatch-logs-kinesis - enabled: false - type: cloudwatch_logs_kinesis - - # Description of the method to help identify them when you run multiple functions. - description: "lambda function for Cloudwatch logs in Kinesis events" - - # Set base64_encoded if your data is base64 encoded. - #base64_encoded: false - - # Set compressed if your data is compressed with gzip. - #compressed: true - - # Concurrency, is the reserved number of instances for that function. - # Default is 5. - # - # Note: There is a hard limit of 1000 functions of any kind per account. - #concurrency: 5 - - # The maximum memory allocated for this function, the configured size must be a factor of 64. - # There is a hard limit of 3008MiB for each function. Default is 128MiB. - #memory_size: 128MiB - - # Dead letter queue configuration, this must be set to an ARN pointing to an SQS queue. - #dead_letter_config.target_arn: - - # Tags are key-value pairs attached to the function. - #tags: - # department: ops - - # The amount of time the function is allowed to run. - #timeout: 3s - - # Execution role of the function. - #role: arn:aws:iam::123456789012:role/MyFunction - - # Connect to private resources in an Amazon VPC. - #virtual_private_cloud: - # security_group_ids: [] - # subnet_ids: [] - # - # Define custom processors for this function. - #processors: - # - decode_json_fields: - # fields: ["message"] - # process_array: false - # max_depth: 1 - # target: "" - # overwrite_keys: false - - # List of Kinesis streams. - triggers: - # Arn for the Kinesis stream. - - event_source_arn: arn:aws:kinesis:us-east-1:xxxxx:myevents - - # batch_size is the number of events read in a batch. - # Default is 10. - #batch_size: 100 - - # Starting position is where to start reading events from the Kinesis stream. - # Default is trim_horizon. - #starting_position: "trim_horizon" - - # parallelization_factor is the number of batches to process from each shard concurrently. - # Default is 1. - #parallelization_factor: 1 - - # Set to true to publish fields with null values in events. - #keep_null: false diff --git a/x-pack/functionbeat/_meta/config/beat.yml.tmpl b/x-pack/functionbeat/_meta/config/beat.yml.tmpl deleted file mode 100644 index e3872794a27f..000000000000 --- a/x-pack/functionbeat/_meta/config/beat.yml.tmpl +++ /dev/null @@ -1,253 +0,0 @@ -###################### Functionbeat Configuration Example ####################### - -# This file is an example configuration file highlighting only the most common -# options. The functionbeat.reference.yml file from the same directory contains all the -# supported options with more comments. You can use it as a reference. -# -# You can find the full configuration reference here: -# https://www.elastic.co/guide/en/beats/functionbeat/index.html -# - -{{header "Provider"}} -# Configure functions to run on AWS Lambda, currently, we assume that the credentials -# are present in the environment to correctly create the function when using the CLI. -# -# Configure which S3 endpoint should we use. -functionbeat.provider.aws.endpoint: "s3.amazonaws.com" -# Configure which S3 bucket we should upload the lambda artifact. -functionbeat.provider.aws.deploy_bucket: "functionbeat-deploy" - -functionbeat.provider.aws.functions: - # Define the list of functions available, each function is required to have a unique name. - # Create a function that accepts events coming from cloudwatchlogs. - - name: cloudwatch - enabled: false - type: cloudwatch_logs - - # Description of the method to help identify them when you run multiple functions. - description: "lambda function for cloudwatch logs" - - # Concurrency, is the reserved number of instances for that function. - # Default is 5. - # - # Note: There is a hard limit of 1000 functions of any kind per account. - #concurrency: 5 - - # The maximum memory allocated for this function, the configured size must be a factor of 64. - # There is a hard limit of 3008MiB for each function. Default is 128MiB. - #memory_size: 128MiB - - # Dead letter queue configuration, this must be set to an ARN pointing to an SQS queue. - #dead_letter_config.target_arn: - - # Execution role of the function. - #role: arn:aws:iam::123456789012:role/MyFunction - - # Connect to private resources in an Amazon VPC. - #virtual_private_cloud: - # security_group_ids: [] - # subnet_ids: [] - - # Optional fields that you can specify to add additional information to the - # output. Fields can be scalar values, arrays, dictionaries, or any nested - # combination of these. - #fields: - # env: staging - - # List of cloudwatch log groups registered to that function. - triggers: - - log_group_name: /aws/lambda/functionbeat-cloudwatch_logs - filter_pattern: mylog_ - - # Define custom processors for this function. - #processors: - # - dissect: - # tokenizer: "%{key1} %{key2}" - - # Create a function that accepts events from SQS queues. - - name: sqs - enabled: false - type: sqs - - # Description of the method to help identify them when you run multiple functions. - description: "lambda function for SQS events" - - # Concurrency, is the reserved number of instances for that function. - # Default is 5. - # - # Note: There is a hard limit of 1000 functions of any kind per account. - #concurrency: 5 - - # The maximum memory allocated for this function, the configured size must be a factor of 64. - # There is a hard limit of 3008MiB for each function. Default is 128MiB. - #memory_size: 128MiB - - # Dead letter queue configuration, this must be set to an ARN pointing to an SQS queue. - #dead_letter_config.target_arn: - - # Execution role of the function. - #role: arn:aws:iam::123456789012:role/MyFunction - - # Connect to private resources in an Amazon VPC. - #virtual_private_cloud: - # security_group_ids: [] - # subnet_ids: [] - - # Optional fields that you can specify to add additional information to the - # output. Fields can be scalar values, arrays, dictionaries, or any nested - # combination of these. - #fields: - # env: staging - - # List of SQS queues. - triggers: - # Arn for the SQS queue. - - event_source_arn: arn:aws:sqs:us-east-1:xxxxx:myevents - - # Define custom processors for this function. - #processors: - # - decode_json_fields: - # fields: ["message"] - # process_array: false - # max_depth: 1 - # target: "" - # overwrite_keys: false - # - - # Create a function that accepts events from Kinesis streams. - - name: kinesis - enabled: false - type: kinesis - - # Description of the method to help identify them when you run multiple functions. - description: "lambda function for Kinesis events" - - # Concurrency, is the reserved number of instances for that function. - # Default is 5. - # - # Note: There is a hard limit of 1000 functions of any kind per account. - #concurrency: 5 - - # The maximum memory allocated for this function, the configured size must be a factor of 64. - # There is a hard limit of 3008MiB for each function. Default is 128MiB. - #memory_size: 128MiB - - # Dead letter queue configuration, this must be set to an ARN pointing to an SQS queue. - #dead_letter_config.target_arn: - - # Execution role of the function. - #role: arn:aws:iam::123456789012:role/MyFunction - - # Connect to private resources in an Amazon VPC. - #virtual_private_cloud: - # security_group_ids: [] - # subnet_ids: [] - - # Optional fields that you can specify to add additional information to the - # output. Fields can be scalar values, arrays, dictionaries, or any nested - # combination of these. - #fields: - # env: staging - - # Define custom processors for this function. - #processors: - # This example extracts the raw data from events. - # - decode_base64_field: - # field: - # from: message - # to: message - # - decompress_gzip_field: - # field: - # from: message - # to: message - # - decode_json_fields: - # fields: ["message"] - # process_array: false - # max_depth: 1 - # target: "" - # overwrite_keys: false - - # List of Kinesis streams. - triggers: - # Arn for the Kinesis stream. - - event_source_arn: arn:aws:kinesis:us-east-1:xxxxx:myevents - - # batch_size is the number of events read in a batch. - # Default is 10. - #batch_size: 100 - - # Starting position is where to start reading events from the Kinesis stream. - # Default is trim_horizon. - #starting_position: "trim_horizon" - - # parallelization_factor is the number of batches to process from each shard concurrently. - # Default is 1. - #parallelization_factor: 1 - - # Create a function that accepts Cloudwatch logs from Kinesis streams. - - name: cloudwatch-logs-kinesis - enabled: false - type: cloudwatch_logs_kinesis - - # Description of the method to help identify them when you run multiple functions. - description: "lambda function for Cloudwatch logs in Kinesis events" - - # Set base64_encoded if your data is base64 encoded. - #base64_encoded: false - - # Set compressed if your data is compressed with gzip. - #compressed: true - - # Concurrency, is the reserved number of instances for that function. - # Default is 5. - # - # Note: There is a hard limit of 1000 functions of any kind per account. - #concurrency: 5 - - # The maximum memory allocated for this function, the configured size must be a factor of 64. - # There is a hard limit of 3008MiB for each function. Default is 128MiB. - #memory_size: 128MiB - - # Dead letter queue configuration, this must be set to an ARN pointing to an SQS queue. - #dead_letter_config.target_arn: - - # Execution role of the function. - #role: arn:aws:iam::123456789012:role/MyFunction - - # Connect to private resources in an Amazon VPC. - #virtual_private_cloud: - # security_group_ids: [] - # subnet_ids: [] - - # Optional fields that you can specify to add additional information to the - # output. Fields can be scalar values, arrays, dictionaries, or any nested - # combination of these. - #fields: - # env: staging - - # Define custom processors for this function. - #processors: - # - decode_json_fields: - # fields: ["message"] - # process_array: false - # max_depth: 1 - # target: "" - # overwrite_keys: false - - # List of Kinesis streams. - triggers: - # Arn for the Kinesis stream. - - event_source_arn: arn:aws:kinesis:us-east-1:xxxxx:myevents - - # batch_size is the number of events read in a batch. - # Default is 10. - #batch_size: 100 - - # Starting position is where to start reading events from the Kinesis stream. - # Default is trim_horizon. - #starting_position: "trim_horizon" - - # parallelization_factor is the number of batches to process from each shard concurrently. - # Default is 1. - #parallelization_factor: 1 - diff --git a/x-pack/functionbeat/_meta/fields.yml b/x-pack/functionbeat/_meta/fields.yml deleted file mode 100644 index a150a420e350..000000000000 --- a/x-pack/functionbeat/_meta/fields.yml +++ /dev/null @@ -1,4 +0,0 @@ -- key: functionbeat - title: Functionbeat - description: - fields: diff --git a/x-pack/functionbeat/config/config.go b/x-pack/functionbeat/config/config.go deleted file mode 100644 index 5ae52d96fd20..000000000000 --- a/x-pack/functionbeat/config/config.go +++ /dev/null @@ -1,143 +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. - -// Config is put into a different package to prevent cyclic imports in case -// it is needed in several locations - -package config - -import ( - "fmt" - "regexp" - - "github.com/elastic/beats/v7/libbeat/cfgfile" - conf "github.com/elastic/elastic-agent-libs/config" -) - -var ( - // We're appending the function name to the role name. - // Limiting this to 30 because, we're prefixing the role name - // with "functionbeat-lambda-"(20 chars) and suffixing with - // the region, the max of which is "ap-southeast-2" (14 chars) - // Length constraints for roleName in AWS is 64 characters max per - // https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateRole.html - - functionPattern = "^[A-Za-z][A-Za-z0-9\\-]{0,30}$" - functionRE = regexp.MustCompile(functionPattern) - configOverrides = conf.MustNewConfigFrom(map[string]interface{}{ - "path.data": "/tmp", - "path.logs": "/tmp/logs", - "keystore.path": "/tmp/functionbeat.keystore", - "setup.template.enabled": true, - "queue.mem": map[string]interface{}{ - "flush.min_events": 10, - "flush.timeout": "0.01s", - }, - }) - functionLoggingOverrides = conf.MustNewConfigFrom(map[string]interface{}{ - "logging.to_stderr": true, - "logging.to_files": false, - }) - logstashOverrides = conf.MustNewConfigFrom(map[string]interface{}{ - "output.logstash.pipelining": 0, - }) - - // Overrides overrides the default configuration provided by libbeat. - Overrides = []cfgfile.ConditionalOverride{ - cfgfile.ConditionalOverride{ - Check: always, - Config: configOverrides, - }, - cfgfile.ConditionalOverride{ - Check: isLogstash, - Config: logstashOverrides, - }, - } - - functionOverride = cfgfile.ConditionalOverride{ - Check: always, - Config: functionLoggingOverrides, - } - - // FunctionOverrides contain logging settings - FunctionOverrides = append(Overrides, functionOverride) -) - -// Config default configuration for Functionbeat. -type Config struct { - Provider *conf.C `config:"provider" validate:"required"` -} - -// ProviderConfig is a generic configured used by providers. -type ProviderConfig struct { - Functions []*conf.C `config:"functions"` -} - -// FunctionConfig minimal configuration from each function. -type FunctionConfig struct { - Type string `config:"type"` - Name functionName `config:"name"` - Enabled bool `config:"enabled"` -} - -// DefaultConfig is the default configuration for Functionbeat. -var DefaultConfig = Config{} - -// DefaultFunctionConfig is the default configuration for new function. -var DefaultFunctionConfig = FunctionConfig{ - Enabled: true, -} - -var always = func(_ *conf.C) bool { - return true -} - -var isLogstash = func(cfg *conf.C) bool { - return isOutput(cfg, "logstash") -} - -func isOutput(cfg *conf.C, name string) bool { - outputCfg, err := cfg.Child("output", -1) - if err != nil { - return false - } - return outputCfg.HasField(name) -} - -type functionName string - -func (f *functionName) Unpack(s string) error { - if !functionRE.MatchString(s) { - return fmt.Errorf( - "invalid name: '%s', name must match [a-zA-Z0-9-] and be at most 30 characters", - s, - ) - } - *f = functionName(s) - return nil -} - -func (f *functionName) String() string { - return string(*f) -} - -// Validate enforces that function names are unique. -func (p *ProviderConfig) Validate() error { - names := make(map[functionName]bool) - for _, rawfn := range p.Functions { - fc := FunctionConfig{} - rawfn.Unpack(&fc) - - if !fc.Enabled { - return nil - } - - if _, found := names[fc.Name]; found { - return fmt.Errorf("function name '%s' already exist, name must be unique", fc.Name) - } - - names[fc.Name] = true - } - return nil -} diff --git a/x-pack/functionbeat/config/config_test.go b/x-pack/functionbeat/config/config_test.go deleted file mode 100644 index acede0920959..000000000000 --- a/x-pack/functionbeat/config/config_test.go +++ /dev/null @@ -1,128 +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. - -// Config is put into a different package to prevent cyclic imports in case -// it is needed in several locations - -package config - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - conf "github.com/elastic/elastic-agent-libs/config" -) - -func TestNameMustBeUnique(t *testing.T) { - tests := []struct { - name string - v map[string]interface{} - err bool - }{ - { - name: "not unique names", - err: true, - v: map[string]interface{}{ - "functions": []map[string]interface{}{ - map[string]interface{}{ - "enabled": true, - "type": "cloudwatchlogs", - "name": "ok", - }, - map[string]interface{}{ - "enabled": true, - "type": "cloudwatchlogs", - "name": "ok", - }, - }, - }, - }, - { - name: "not unique names but duplicate is disabled", - err: false, - v: map[string]interface{}{ - "functions": []map[string]interface{}{ - map[string]interface{}{ - "enabled": true, - "type": "cloudwatchlogs", - "name": "ok", - }, - map[string]interface{}{ - "enabled": false, - "type": "cloudwatchlogs", - "name": "ok", - }, - }, - }, - }, - { - name: "name are uniques", - err: false, - v: map[string]interface{}{ - "functions": []map[string]interface{}{ - map[string]interface{}{ - "enabled": true, - "type": "cloudwatchlogs", - "name": "ok", - }, - map[string]interface{}{ - "enabled": true, - "type": "cloudwatchlogs", - "name": "another", - }, - }, - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - cfg, err := conf.NewConfigFrom(test.v) - if !assert.NoError(t, err) { - return - } - provider := ProviderConfig{} - - err = cfg.Unpack(&provider) - if test.err == true { - assert.Error(t, err) - return - } - assert.NoError(t, err) - }) - } -} - -func TestFunctionName(t *testing.T) { - t.Run("valid function name", func(t *testing.T) { - f := functionName("") - err := f.Unpack("hello-world") - if !assert.NoError(t, err) { - return - } - assert.Equal(t, functionName("hello-world"), f) - }) - - t.Run("valid function name: length of 30 chars", func(t *testing.T) { - f := functionName("") - err := f.Unpack("something-which-is--30--chars") - if !assert.NoError(t, err) { - return - } - assert.Equal(t, functionName("something-which-is--30--chars"), f) - }) - - t.Run("invalid function name", func(t *testing.T) { - f := functionName("") - err := f.Unpack("hello world") - assert.Error(t, err) - }) - - t.Run("invalid function name: length", func(t *testing.T) { - f := functionName("") - err := f.Unpack("something-which-is-greater-than-thirty-characters") - assert.Error(t, err) - }) -} diff --git a/x-pack/functionbeat/conftest.py b/x-pack/functionbeat/conftest.py deleted file mode 100644 index 8e1002b41e5d..000000000000 --- a/x-pack/functionbeat/conftest.py +++ /dev/null @@ -1,5 +0,0 @@ -import os -import sys - -sys.path.append(os.path.join(os.path.dirname(__file__), '../../libbeat/tests/system')) -sys.path.append(os.path.join(os.path.dirname(__file__), './tests/system')) diff --git a/x-pack/functionbeat/dev-tools/packaging/packages.yml b/x-pack/functionbeat/dev-tools/packaging/packages.yml deleted file mode 100644 index 480b31820b5f..000000000000 --- a/x-pack/functionbeat/dev-tools/packaging/packages.yml +++ /dev/null @@ -1,100 +0,0 @@ ---- - -# This file contains the package specifications for Functionbeat. - -shared: - - &common - name: '{{.BeatName}}' - service_name: '{{.BeatServiceName}}' - os: '{{.GOOS}}' - arch: '{{.PackageArch}}' - vendor: '{{.BeatVendor}}' - version: '{{ beat_version }}' - license: '{{.BeatLicense}}' - url: '{{.BeatURL}}' - description: '{{.BeatDescription}}' - - - &binary_files - '{{.BeatName}}{{.BinaryExt}}': - source: build/golang-crossbuild/{{.BeatName}}-{{.GOOS}}-{{.Platform.Arch}}{{.BinaryExt}} - mode: 0755 - fields.yml: - source: fields.yml - mode: 0644 - LICENSE.txt: - source: '{{ repo.RootDir }}/LICENSE.txt' - mode: 0644 - NOTICE.txt: - source: '{{ repo.RootDir }}/NOTICE.txt' - mode: 0644 - README.md: - template: '{{ elastic_beats_dir }}/dev-tools/packaging/templates/common/README.md.tmpl' - mode: 0644 - .build_hash.txt: - content: > - {{ commit }} - mode: 0644 - '{{.BeatName}}.reference.yml': - source: '{{.BeatName}}.reference.yml' - mode: 0644 - '{{.BeatName}}.yml': - source: '{{.BeatName}}.yml' - mode: 0600 - config: true - - # Binary package spec (tar.gz for linux/darwin) - - &binary_spec - <<: *common - files: - <<: *binary_files - - # - # License modifiers for the Elastic License - # - - &elastic_license_for_binaries - license: "Elastic License" - files: - LICENSE.txt: - source: '{{ repo.RootDir }}/licenses/ELASTIC-LICENSE.txt' - mode: 0644 - # - # Binaries used to run functions. - # - - &functionbeat_binaries - files: - pkg/functionbeat-aws: - source: 'provider/aws/build/golang-crossbuild/aws-linux-amd64' - mode: 0755 - -# specs is a list of named packaging "flavors". -specs: - functionbeat: - ### - # Elastic Licensed Packages - ### - - os: windows - types: [zip] - spec: - <<: *binary_spec - <<: *functionbeat_binaries - <<: *elastic_license_for_binaries - files: - '{{.BeatName}}{{.BinaryExt}}': - source: build/golang-crossbuild/{{.BeatName}}-{{.GOOS}}-{{.Platform.Arch}}{{.BinaryExt}} - - - os: darwin - types: [tgz] - spec: - <<: *binary_spec - <<: *functionbeat_binaries - <<: *elastic_license_for_binaries - - - os: linux - types: [tgz] - spec: - <<: *binary_spec - <<: *functionbeat_binaries - <<: *elastic_license_for_binaries - files: - '{{.BeatName}}{{.BinaryExt}}': - source: build/golang-crossbuild/{{.BeatName}}-{{.GOOS}}-{{.Platform.Arch}}{{.BinaryExt}} diff --git a/x-pack/functionbeat/docker-compose.yml b/x-pack/functionbeat/docker-compose.yml deleted file mode 100644 index aa6cc364a7e7..000000000000 --- a/x-pack/functionbeat/docker-compose.yml +++ /dev/null @@ -1,28 +0,0 @@ -version: '2.3' -services: - beat: - build: ${PWD}/. - depends_on: - - proxy_dep - working_dir: /go/src/github.com/elastic/beats/x-pack/functionbeat - volumes: - - ${PWD}/../..:/go/src/github.com/elastic/beats/ - # We launch docker containers to test docker autodiscover: - - /var/run/docker.sock:/var/run/docker.sock - command: make - - # This is a proxy used to block beats until all services are healthy. - # See: https://github.com/docker/compose/issues/4369 - proxy_dep: - image: busybox - depends_on: - elasticsearch: { condition: service_healthy } - - elasticsearch: - extends: - file: ${ES_BEATS}/testing/environments/${TESTING_ENVIRONMENT}.yml - service: elasticsearch - healthcheck: - test: ["CMD-SHELL", "curl -u admin:testing -s http://localhost:9200/_cat/health?h=status | grep -q green"] - retries: 300 - interval: 1s diff --git a/x-pack/functionbeat/docs/config-options-aws.asciidoc b/x-pack/functionbeat/docs/config-options-aws.asciidoc deleted file mode 100644 index 7f0328127f02..000000000000 --- a/x-pack/functionbeat/docs/config-options-aws.asciidoc +++ /dev/null @@ -1,219 +0,0 @@ -[id="configuration-{beatname_lc}-options"] -[role="xpack"] - -:libbeat-xpack-dir: ../../../x-pack/libbeat - -== Configure AWS functions - -++++ -AWS functions -++++ - -{beatname_uc} runs as a function in your serverless environment. - -Before deploying {beatname_uc}, you need to configure one or more functions and -specify details about the services that will trigger the functions. - -You configure the functions in the the +{beatname_lc}.yml+ configuration file. -When you're done, you can <> -to your serverless environment. - -The `aws` functions require AWS credentials configuration in order to make AWS API calls. -Users can either use `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` and/or -`AWS_SESSION_TOKEN`, or use shared AWS credentials file. -Please see <> for more details. - -The following example configures two functions: `cloudwatch` and `sqs`. The -`cloudwatch` function collects events from CloudWatch Logs. The `sqs` function -collects messages from Amazon Simple Queue Service (SQS). Both functions forward -the events to {es}. - -["source","sh",subs="attributes"] ----- -{beatname_lc}.provider.aws.endpoint: "s3.amazonaws.com" -{beatname_lc}.provider.aws.deploy_bucket: "functionbeat-deploy" -{beatname_lc}.provider.aws.functions: - - name: cloudwatch - enabled: true - type: cloudwatch_logs - description: "lambda function for cloudwatch logs" - triggers: - - log_group_name: /aws/lambda/my-lambda-function - #filter_pattern: mylog_ - - name: sqs - enabled: true - type: sqs - description: "lambda function for SQS events" - triggers: - - event_source_arn: arn:aws:sqs:us-east-1:123456789012:myevents - -cloud.id: "MyESDeployment:SomeLongString==" -cloud.auth: "elastic:SomeLongString" - -processors: - - add_host_metadata: ~ - - add_cloud_metadata: ~ ----- - -[id="{beatname_lc}-options"] -[float] -=== Configuration options -You can specify the following options to configure the functions that you want -to deploy. - -TIP: If you change the configuration after deploying the function, use -the <> to update your deployment. - -[float] -[id="{beatname_lc}-deploy-bucket"] -==== `provider.aws.deploy_bucket` - -A unique name for the S3 bucket that the Lambda artifact will be uploaded to. - -[float] -[id="{beatname_lc}-name"] -==== `name` - -A unique name for the Lambda function. This is the name of the function as it -will appear in the Lambda console on AWS. - -[float] -[id="{beatname_lc}-type"] -==== `type` - -The type of service to monitor. For this release, the supported types -are: - -[horizontal] -`cloudwatch_logs`:: Collects events from CloudWatch logs. -`sqs`:: Collects data from Amazon Simple Queue Service (SQS). -`kinesis`:: Collects data from a Kinesis stream. - -[float] -[id="{beatname_lc}-description"] -==== `description` - -A description of the function. This description is useful when you are running -multiple functions and need more context about how each function is used. - -[float] -[id="{beatname_lc}-triggers"] -==== `triggers` - -A list of triggers that will cause the function to execute. The list of valid -triggers depends on the `type`: - -* For `cloudwatch_logs`, specify a list of log groups. Because the AWS limit is -one subscription filter per CloudWatch log group, the log groups specified here -must have no other subscription filters, or deployment will fail. -For more information, see <>. -* For `sqs` or `kinesis`, specify a list of Amazon Resource Names (ARNs). - -[float] -[id="{beatname_lc}-filter_pattern"] -==== `filter_pattern` - -A regular expression that matches the events you want to collect. Setting this -option may reduce execution costs because the function only executes if there is -data that matches the pattern. - -[float] -[id="{beatname_lc}-concurrency"] -==== `concurrency` - -The reserved number of instances for the function. Setting this option may -reduce execution costs by limiting the number of functions that can execute in -your serverless environment. The default is unreserved. - -[float] -[id="{beatname_lc}-memory-size"] -==== `memory_size` - -The maximum amount of memory to allocate for this function. Specify a value that -is a factor of 64. There is a hard limit of 3008 MiB for each function. The -default is 128 MiB. - -[float] -[id="{beatname_lc}-role"] -==== `role` - -The custom execution role to use for the deployed function. For example: - -[source,yaml] ----- - role: arn:aws:iam::123456789012:role/MyFunction ----- - -Make sure the custom role has the permissions required to run the function. For -more information, see <>. - -If `role` is not specified, the function uses the default role and policy -created during deployment. - -[float] -[id="{beatname_lc}-virtual_private_cloud"] -==== `virtual_private_cloud` - -Specifies additional settings required to connect to private resources in an -Amazon Virtual Private Cloud (VPC). For example: - -[source,yaml] ----- - virtual_private_cloud: - security_group_ids: - - mySecurityGroup - - anotherSecurityGroup - subnet_ids: - - myUniqueID ----- - -[float] -[id="{beatname_lc}-dead-letter-config"] -==== `dead_letter_config.target_arn` - -The dead letter queue to use for messages that can't be processed successfully. -Set this option to an ARN that points to an SQS queue. - -[float] -[id="{beatname_lc}-batch-size"] -==== `batch_size` - -The number of events to read from a Kinesis stream, the minimum value is 100 and the maximum is -10000. The default is 100. - -[float] -[id="{beatname_lc}-starting-position"] -==== `starting_position` - -The starting position to read from a Kinesis stream, valids values are `trim_horizon` and `latest`. -The default is trim_horizon. - -[float] -[id="{beatname_lc}-parallelization-factor"] -==== `parallelization_factor` - -The number of batches to process from each shard concurrently, the minimum value is 1 and the maximum is 10 -The default is 1. - -[float] -[id="{beatname_lc}-keep-null"] -==== `keep_null` - -If this option is set to true, fields with `null` values will be published in -the output document. By default, `keep_null` is set to `false`. - -[float] -[id="{beatname_lc}-index"] -==== `index` - -If present, this formatted string overrides the index for events from this function -(for elasticsearch outputs), or sets the `raw_index` field of the event's -metadata (for other outputs). This string can only refer to the agent name and -version and the event timestamp; for access to dynamic fields, use -`output.elasticsearch.index` or a processor. - -Example value: `"%{[agent.name]}-myindex-%{+yyyy.MM.dd}"` might -expand to `"functionbeat-myindex-2019.12.13"`. - -[id="aws-credentials-config"] -include::{libbeat-xpack-dir}/docs/aws-credentials-config.asciidoc[] diff --git a/x-pack/functionbeat/docs/configuring-howto.asciidoc b/x-pack/functionbeat/docs/configuring-howto.asciidoc deleted file mode 100644 index fad0629261be..000000000000 --- a/x-pack/functionbeat/docs/configuring-howto.asciidoc +++ /dev/null @@ -1,66 +0,0 @@ -[id="configuring-howto-{beatname_lc}"] -[role="xpack"] -= Configure {beatname_uc} - -[partintro] --- -++++ -Configure -++++ - -include::{libbeat-dir}/shared/configuring-intro.asciidoc[] - -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <<{beatname_lc}-reference-yml>> - --- - -include::./config-options-aws.asciidoc[] - -include::./general-options.asciidoc[] - -[role="xpack"] -include::{libbeat-dir}/outputconfig.asciidoc[] - -ifndef::no_kerberos[] -include::{libbeat-dir}/shared-kerberos-config.asciidoc[] -endif::[] - -[role="xpack"] -include::{libbeat-dir}/shared-ssl-config.asciidoc[] - -[role="xpack"] -include::{libbeat-dir}/shared-ilm.asciidoc[] - -[role="xpack"] -include::{libbeat-dir}/setup-config.asciidoc[] - -[role="xpack"] -include::./filtering.asciidoc[] - -:allplatforms: -[role="xpack"] -include::{libbeat-dir}/queueconfig.asciidoc[] -:allplatforms!: - -[role="xpack"] -include::{libbeat-dir}/loggingconfig.asciidoc[] - -[role="xpack"] -include::{libbeat-dir}/regexp.asciidoc[] - -[role="xpack"] -include::{libbeat-dir}/shared-instrumentation.asciidoc[] - -[role="xpack"] -include::{libbeat-dir}/reference-yml.asciidoc[] diff --git a/x-pack/functionbeat/docs/deploying.asciidoc b/x-pack/functionbeat/docs/deploying.asciidoc deleted file mode 100644 index 5cfe9d98982d..000000000000 --- a/x-pack/functionbeat/docs/deploying.asciidoc +++ /dev/null @@ -1,113 +0,0 @@ -[id="deploy-to-cloud-provider"] -[role="xpack"] -=== Deploy {beatname_uc} to your cloud provider - -After configuring {beatname_uc} and defining cloud functions for the services -you want to monitor, deploy the functions to your cloud provider. To do this, -you can use the {beatname_uc} manager (good for getting started), or use your -own deployment infrastructure. - -[[manager-deployment]] -==== Use the {beatname_uc} manager - -Use the built-in manager to deploy, update, or delete {beatname_uc} functions -when you don't have your own deployment infrastructure or process in place. - -During deployment, the {beatname_uc} manager: - -* Exports a function template to use for deployment. For AWS, it exports an -{cloudformation-ref} template. To inspect the template, run the -<> command. -* Creates a zip package that includes the function code and +{beatname_lc}.yml+ -config file. -* Uploads the package to the specified cloud provider. - -See <<{beatname_lc}-deploying>> in the getting started to learn how to deploy -functions by using the {beatname_uc} manager. - -[[own-deployment]] -==== Use your own deployment infrastructure - -If you don't want to use the {beatname_uc} manager, use your own deployment -infrastructure. To do this, create a package, then deploy it to your cloud -provider: - -. Set the following environment variables: -+ -`BEAT_STRICT_PERMS=false`:: This setting makes the function skip the ownership -check on the configuration file. -`ENABLED_FUNCTIONS=function-name-1,function-name-2`:: Specifies a -comma-separated list of functions that are enabled in the configuration file. For -example, to package functions called `my-kinesis` and `my-cloudwatch-logs`, run: -+ -*linux and mac*: -+ -[source, shell] ----- -export BEAT_STRICT_PERMS=false -export ENABLED_FUNCTIONS=my-kinesis,my-cloudwatch-logs ----- -+ -*win*: -+ -[source, shell] ----- -set BEAT_STRICT_PERMS=false -set ENABLED_FUNCTIONS=my-kinesis,my-cloudwatch-logs ----- -+ -TIP: For easier management, we recommend having one Lambda per function. - -. Run the `package` command to package the functions and dependencies into an -archive. For example: -+ -*linux and mac:* -+ -["source","sh",subs="attributes"] ----------------------------------------------------------------------- -./{beatname_lc} -v -e -d "*" package --output /path/to/folder/package-{{.Provider}}.zip ----------------------------------------------------------------------- -+ -*win:* -+ -["source","sh",subs="attributes"] ----------------------------------------------------------------------- -.{backslash}{beatname_lc}.exe -v -e -d "*" package --output /path/to/folder/package-{{.Provider}}.zip ----------------------------------------------------------------------- -+ -For `--output` specify a full path pattern. -+ -The `package` command generates deployment packages for each provider specified -in the configuration. Each package contains: -+ -* a binary with the function code -* the `functionbeat.yml` config file - -. If certificates are required, add the cert files to the zip package under the -same path as the configured +{beatname_lc}.yml+ file. - -. Export a function template to use for deployment: -+ -*linux and mac:* -+ -["source","sh",subs="attributes"] ----------------------------------------------------------------------- -./{beatname_lc} export function FUNCTION_NAME ----------------------------------------------------------------------- -+ -*win:* -+ -["source","sh",subs="attributes"] ----------------------------------------------------------------------- -.{backslash}{beatname_lc}.exe export function FUNCTION_NAME ----------------------------------------------------------------------- -+ -{beatname_uc} writes the template to stdout. For AWS functions, it writes an -{cloudformation-ref} template. - -. Modify the template to work with your infrastructure. - -. Deploy the package, using the infrastructure and automation supported by your -cloud provider, for example, {cloudformation-ref}. -+ -For more information about deployment, see your cloud provider's documentation. diff --git a/x-pack/functionbeat/docs/export-cloudformation-template.asciidoc b/x-pack/functionbeat/docs/export-cloudformation-template.asciidoc deleted file mode 100644 index 803ab5a6f8b4..000000000000 --- a/x-pack/functionbeat/docs/export-cloudformation-template.asciidoc +++ /dev/null @@ -1,27 +0,0 @@ -[[export-cloudformation-template]] -[role="xpack"] -=== Export AWS CloudFormation template - -You can use {beatname_uc} to export an {cloudformation-ref} template then use -the template with automation software to deploy {beatname_uc} code to your cloud -environment. - -After configuring {beatname_uc}, use the following command to export the -CloudFormation template: - -*linux and mac:* - -["source","sh",subs="attributes"] ----------------------------------------------------------------------- -./{beatname_lc} export function FUNCTION_NAME ----------------------------------------------------------------------- - -*win:* - -["source","sh",subs="attributes"] ----------------------------------------------------------------------- -.{backslash}{beatname_lc}.exe export function FUNCTION_NAME ----------------------------------------------------------------------- - -{beatname_uc} writes the CloudFormation template to stdout. Modify the template -to work with your infrastructure. diff --git a/x-pack/functionbeat/docs/faq-resource-limit.asciidoc b/x-pack/functionbeat/docs/faq-resource-limit.asciidoc deleted file mode 100644 index c4db5a4c6831..000000000000 --- a/x-pack/functionbeat/docs/faq-resource-limit.asciidoc +++ /dev/null @@ -1,55 +0,0 @@ -[[unable-to-deploy-resource-limit]] -=== Deployment to AWS fails with "resource limit exceeded" - -Deployment fails with the following message if you attempt to deploy a Lambda -function that reads from a CloudWatch log group that already has a subscription -filter defined on it: - -[source,shell] ----- -CREATE_FAILED, ResourceStatusReason: Resource limit exceeded ----- - -The AWS limit on subscription filters is one per log group. If you've already -deployed a Lambda function that monitors the log group, even if you deleted the -function, the filter subscription might still exist. - -To resolve this issue, use the AWS logs -https://docs.aws.amazon.com/cli/latest/reference/logs/describe-subscription-filters.html[`describe-subscription-filters`] -command on the log group. For example, if you're using the AWS CLI, run: - -[source,shell] ----- -aws logs describe-subscription-filters --log-group-name /aws/lambda/hello-world-python ----- - -The output will look something like: - -[source,json] ----- -{ - "subscriptionFilters": [ - { - "filterPattern": "", - "filterName": "fnb-cloudwatch-stack-fnbcloudwatch3SFawslambdahelloworldpython-11WH0BC1BM1NP", - "creationTime": 1565194872642, - "logGroupName": "/aws/lambda/hello-world-python", - "destinationArn": "arn:aws:lambda:us-east-2:551009506772:function:cloudwatch", - "distribution": "ByLogStream" - } - ] -} ----- - -If you're no longer using the subscription filter, you can use the AWS logs -https://docs.aws.amazon.com/cli/latest/reference/logs/delete-subscription-filter.html[`delete-subscription-filter`] -command to delete it. For example: - -[source,shell] ----- -aws logs delete-subscription-filter --log-group-name /aws/lambda/hello-world-python --filter-name fnb-cloudwatch-stack-fnbcloudwatch3SFawslambdahelloworldpython-11WH0BC1BM1NP ----- - -Before attempting to redeploy the function, you might need to go to the -CloudFormation console in AWS and delete the stack that {beatname_uc} -created for the failed deployment. diff --git a/x-pack/functionbeat/docs/faq.asciidoc b/x-pack/functionbeat/docs/faq.asciidoc deleted file mode 100644 index 6e942b9633cd..000000000000 --- a/x-pack/functionbeat/docs/faq.asciidoc +++ /dev/null @@ -1,23 +0,0 @@ -[[faq]] -[role="xpack"] -== Common problems - -This section describes common problems you might encounter with -{beatname_uc}. Also check out the -https://discuss.elastic.co/c/beats/{beatname_lc}[{beatname_uc} discussion forum]. - -[[unable-to-deploy]] -=== Deployment to AWS fails with "failed to create the stack" - -Deployment fails if you attempt to deploy the Lambda function to the wrong -region. - -You must deploy the function to the region where your services are running. For -example, if you want to monitor CloudWatch logs for a service running in the -`us-east-1` region, you must deploy the Lambda function to the same region, or -deployment fails. - -include::faq-resource-limit.asciidoc[] - -include::{libbeat-dir}/shared-faq.asciidoc[] - diff --git a/x-pack/functionbeat/docs/fields.asciidoc b/x-pack/functionbeat/docs/fields.asciidoc deleted file mode 100644 index 08589bd02996..000000000000 --- a/x-pack/functionbeat/docs/fields.asciidoc +++ /dev/null @@ -1,15676 +0,0 @@ - -//// -This file is generated! See _meta/fields.yml and scripts/generate_fields_docs.py -//// - -:edit_url: - -[[exported-fields]] -= Exported fields - -[partintro] - --- -This document describes the fields that are exported by Functionbeat. They are -grouped in the following categories: - -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> - --- -[[exported-fields-beat-common]] -== Beat fields - -Contains common beat fields available in all event types. - - - -*`agent.hostname`*:: -+ --- -Deprecated - use agent.name or agent.id to identify an agent. - - -type: alias - -alias to: agent.name - --- - -*`beat.timezone`*:: -+ --- -type: alias - -alias to: event.timezone - --- - -*`fields`*:: -+ --- -Contains user configurable fields. - - -type: object - --- - -*`beat.name`*:: -+ --- -type: alias - -alias to: host.name - --- - -*`beat.hostname`*:: -+ --- -type: alias - -alias to: agent.name - --- - -*`timeseries.instance`*:: -+ --- -Time series instance id - -type: keyword - --- - -[[exported-fields-cloud]] -== Cloud provider metadata fields - -Metadata from cloud providers added by the add_cloud_metadata processor. - - - -*`cloud.image.id`*:: -+ --- -Image ID for the cloud instance. - - -example: ami-abcd1234 - --- - -*`meta.cloud.provider`*:: -+ --- -type: alias - -alias to: cloud.provider - --- - -*`meta.cloud.instance_id`*:: -+ --- -type: alias - -alias to: cloud.instance.id - --- - -*`meta.cloud.instance_name`*:: -+ --- -type: alias - -alias to: cloud.instance.name - --- - -*`meta.cloud.machine_type`*:: -+ --- -type: alias - -alias to: cloud.machine.type - --- - -*`meta.cloud.availability_zone`*:: -+ --- -type: alias - -alias to: cloud.availability_zone - --- - -*`meta.cloud.project_id`*:: -+ --- -type: alias - -alias to: cloud.project.id - --- - -*`meta.cloud.region`*:: -+ --- -type: alias - -alias to: cloud.region - --- - -[[exported-fields-docker-processor]] -== Docker fields - -Docker stats collected from Docker. - - - - -*`docker.container.id`*:: -+ --- -type: alias - -alias to: container.id - --- - -*`docker.container.image`*:: -+ --- -type: alias - -alias to: container.image.name - --- - -*`docker.container.name`*:: -+ --- -type: alias - -alias to: container.name - --- - -*`docker.container.labels`*:: -+ --- -Image labels. - - -type: object - --- - -[[exported-fields-ecs]] -== ECS fields - - -This section defines Elastic Common Schema (ECS) fields—a common set of fields -to be used when storing event data in {es}. - -This is an exhaustive list, and fields listed here are not necessarily used by {beatname_uc}. -The goal of ECS is to enable and encourage users of {es} to normalize their event data, -so that they can better analyze, visualize, and correlate the data represented in their events. - -See the {ecs-ref}[ECS reference] for more information. - -*`@timestamp`*:: -+ --- -Date/time when the event originated. -This is the date/time extracted from the event, typically representing when the event was generated by the source. -If the event source has no original timestamp, this value is typically populated by the first time the event was received by the pipeline. -Required field for all events. - -type: date - -example: 2016-05-23T08:05:34.853Z - -required: True - --- - -*`labels`*:: -+ --- -Custom key/value pairs. -Can be used to add meta information to events. Should not contain nested objects. All values are stored as keyword. -Example: `docker` and `k8s` labels. - -type: object - -example: {"application": "foo-bar", "env": "production"} - --- - -*`message`*:: -+ --- -For log events the message field contains the log message, optimized for viewing in a log viewer. -For structured logs without an original message field, other fields can be concatenated to form a human-readable summary of the event. -If multiple messages exist, they can be combined into one message. - -type: match_only_text - -example: Hello World - --- - -*`tags`*:: -+ --- -List of keywords used to tag each event. - -type: keyword - -example: ["production", "env2"] - --- - -[float] -=== agent - -The agent fields contain the data about the software entity, if any, that collects, detects, or observes events on a host, or takes measurements on a host. -Examples include Beats. Agents may also run on observers. ECS agent.* fields shall be populated with details of the agent running on the host or observer where the event happened or the measurement was taken. - - -*`agent.build.original`*:: -+ --- -Extended build information for the agent. -This field is intended to contain any build information that a data source may provide, no specific formatting is required. - -type: keyword - -example: metricbeat version 7.6.0 (amd64), libbeat 7.6.0 [6a23e8f8f30f5001ba344e4e54d8d9cb82cb107c built 2020-02-05 23:10:10 +0000 UTC] - --- - -*`agent.ephemeral_id`*:: -+ --- -Ephemeral identifier of this agent (if one exists). -This id normally changes across restarts, but `agent.id` does not. - -type: keyword - -example: 8a4f500f - --- - -*`agent.id`*:: -+ --- -Unique identifier of this agent (if one exists). -Example: For Beats this would be beat.id. - -type: keyword - -example: 8a4f500d - --- - -*`agent.name`*:: -+ --- -Custom name of the agent. -This is a name that can be given to an agent. This can be helpful if for example two Filebeat instances are running on the same host but a human readable separation is needed on which Filebeat instance data is coming from. -If no name is given, the name is often left empty. - -type: keyword - -example: foo - --- - -*`agent.type`*:: -+ --- -Type of the agent. -The agent type always stays the same and should be given by the agent used. In case of Filebeat the agent would always be Filebeat also if two Filebeat instances are run on the same machine. - -type: keyword - -example: filebeat - --- - -*`agent.version`*:: -+ --- -Version of the agent. - -type: keyword - -example: 6.0.0-rc2 - --- - -[float] -=== as - -An autonomous system (AS) is a collection of connected Internet Protocol (IP) routing prefixes under the control of one or more network operators on behalf of a single administrative entity or domain that presents a common, clearly defined routing policy to the internet. - - -*`as.number`*:: -+ --- -Unique number allocated to the autonomous system. The autonomous system number (ASN) uniquely identifies each network on the Internet. - -type: long - -example: 15169 - --- - -*`as.organization.name`*:: -+ --- -Organization name. - -type: keyword - -example: Google LLC - --- - -*`as.organization.name.text`*:: -+ --- -type: match_only_text - --- - -[float] -=== client - -A client is defined as the initiator of a network connection for events regarding sessions, connections, or bidirectional flow records. -For TCP events, the client is the initiator of the TCP connection that sends the SYN packet(s). For other protocols, the client is generally the initiator or requestor in the network transaction. Some systems use the term "originator" to refer the client in TCP connections. The client fields describe details about the system acting as the client in the network event. Client fields are usually populated in conjunction with server fields. Client fields are generally not populated for packet-level events. -Client / server representations can add semantic context to an exchange, which is helpful to visualize the data in certain situations. If your context falls in that category, you should still ensure that source and destination are filled appropriately. - - -*`client.address`*:: -+ --- -Some event client addresses are defined ambiguously. The event will sometimes list an IP, a domain or a unix socket. You should always store the raw address in the `.address` field. -Then it should be duplicated to `.ip` or `.domain`, depending on which one it is. - -type: keyword - --- - -*`client.as.number`*:: -+ --- -Unique number allocated to the autonomous system. The autonomous system number (ASN) uniquely identifies each network on the Internet. - -type: long - -example: 15169 - --- - -*`client.as.organization.name`*:: -+ --- -Organization name. - -type: keyword - -example: Google LLC - --- - -*`client.as.organization.name.text`*:: -+ --- -type: match_only_text - --- - -*`client.bytes`*:: -+ --- -Bytes sent from the client to the server. - -type: long - -example: 184 - -format: bytes - --- - -*`client.domain`*:: -+ --- -The domain name of the client system. -This value may be a host name, a fully qualified domain name, or another host naming format. The value may derive from the original event or be added from enrichment. - -type: keyword - -example: foo.example.com - --- - -*`client.geo.city_name`*:: -+ --- -City name. - -type: keyword - -example: Montreal - --- - -*`client.geo.continent_code`*:: -+ --- -Two-letter code representing continent's name. - -type: keyword - -example: NA - --- - -*`client.geo.continent_name`*:: -+ --- -Name of the continent. - -type: keyword - -example: North America - --- - -*`client.geo.country_iso_code`*:: -+ --- -Country ISO code. - -type: keyword - -example: CA - --- - -*`client.geo.country_name`*:: -+ --- -Country name. - -type: keyword - -example: Canada - --- - -*`client.geo.location`*:: -+ --- -Longitude and latitude. - -type: geo_point - -example: { "lon": -73.614830, "lat": 45.505918 } - --- - -*`client.geo.name`*:: -+ --- -User-defined description of a location, at the level of granularity they care about. -Could be the name of their data centers, the floor number, if this describes a local physical entity, city names. -Not typically used in automated geolocation. - -type: keyword - -example: boston-dc - --- - -*`client.geo.postal_code`*:: -+ --- -Postal code associated with the location. -Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country. - -type: keyword - -example: 94040 - --- - -*`client.geo.region_iso_code`*:: -+ --- -Region ISO code. - -type: keyword - -example: CA-QC - --- - -*`client.geo.region_name`*:: -+ --- -Region name. - -type: keyword - -example: Quebec - --- - -*`client.geo.timezone`*:: -+ --- -The time zone of the location, such as IANA time zone name. - -type: keyword - -example: America/Argentina/Buenos_Aires - --- - -*`client.ip`*:: -+ --- -IP address of the client (IPv4 or IPv6). - -type: ip - --- - -*`client.mac`*:: -+ --- -MAC address of the client. -The notation format from RFC 7042 is suggested: Each octet (that is, 8-bit byte) is represented by two [uppercase] hexadecimal digits giving the value of the octet as an unsigned integer. Successive octets are separated by a hyphen. - -type: keyword - -example: 00-00-5E-00-53-23 - --- - -*`client.nat.ip`*:: -+ --- -Translated IP of source based NAT sessions (e.g. internal client to internet). -Typically connections traversing load balancers, firewalls, or routers. - -type: ip - --- - -*`client.nat.port`*:: -+ --- -Translated port of source based NAT sessions (e.g. internal client to internet). -Typically connections traversing load balancers, firewalls, or routers. - -type: long - -format: string - --- - -*`client.packets`*:: -+ --- -Packets sent from the client to the server. - -type: long - -example: 12 - --- - -*`client.port`*:: -+ --- -Port of the client. - -type: long - -format: string - --- - -*`client.registered_domain`*:: -+ --- -The highest registered client domain, stripped of the subdomain. -For example, the registered domain for "foo.example.com" is "example.com". -This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk". - -type: keyword - -example: example.com - --- - -*`client.subdomain`*:: -+ --- -The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. -For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period. - -type: keyword - -example: east - --- - -*`client.top_level_domain`*:: -+ --- -The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". -This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk". - -type: keyword - -example: co.uk - --- - -*`client.user.domain`*:: -+ --- -Name of the directory the user is a member of. -For example, an LDAP or Active Directory domain name. - -type: keyword - --- - -*`client.user.email`*:: -+ --- -User email address. - -type: keyword - --- - -*`client.user.full_name`*:: -+ --- -User's full name, if available. - -type: keyword - -example: Albert Einstein - --- - -*`client.user.full_name.text`*:: -+ --- -type: match_only_text - --- - -*`client.user.group.domain`*:: -+ --- -Name of the directory the group is a member of. -For example, an LDAP or Active Directory domain name. - -type: keyword - --- - -*`client.user.group.id`*:: -+ --- -Unique identifier for the group on the system/platform. - -type: keyword - --- - -*`client.user.group.name`*:: -+ --- -Name of the group. - -type: keyword - --- - -*`client.user.hash`*:: -+ --- -Unique user hash to correlate information for a user in anonymized form. -Useful if `user.id` or `user.name` contain confidential information and cannot be used. - -type: keyword - --- - -*`client.user.id`*:: -+ --- -Unique identifier of the user. - -type: keyword - -example: S-1-5-21-202424912787-2692429404-2351956786-1000 - --- - -*`client.user.name`*:: -+ --- -Short name or login of the user. - -type: keyword - -example: a.einstein - --- - -*`client.user.name.text`*:: -+ --- -type: match_only_text - --- - -*`client.user.roles`*:: -+ --- -Array of user roles at the time of the event. - -type: keyword - -example: ["kibana_admin", "reporting_user"] - --- - -[float] -=== cloud - -Fields related to the cloud or infrastructure the events are coming from. - - -*`cloud.account.id`*:: -+ --- -The cloud account or organization id used to identify different entities in a multi-tenant environment. -Examples: AWS account id, Google Cloud ORG Id, or other unique identifier. - -type: keyword - -example: 666777888999 - --- - -*`cloud.account.name`*:: -+ --- -The cloud account name or alias used to identify different entities in a multi-tenant environment. -Examples: AWS account name, Google Cloud ORG display name. - -type: keyword - -example: elastic-dev - --- - -*`cloud.availability_zone`*:: -+ --- -Availability zone in which this host, resource, or service is located. - -type: keyword - -example: us-east-1c - --- - -*`cloud.instance.id`*:: -+ --- -Instance ID of the host machine. - -type: keyword - -example: i-1234567890abcdef0 - --- - -*`cloud.instance.name`*:: -+ --- -Instance name of the host machine. - -type: keyword - --- - -*`cloud.machine.type`*:: -+ --- -Machine type of the host machine. - -type: keyword - -example: t2.medium - --- - -*`cloud.origin.account.id`*:: -+ --- -The cloud account or organization id used to identify different entities in a multi-tenant environment. -Examples: AWS account id, Google Cloud ORG Id, or other unique identifier. - -type: keyword - -example: 666777888999 - --- - -*`cloud.origin.account.name`*:: -+ --- -The cloud account name or alias used to identify different entities in a multi-tenant environment. -Examples: AWS account name, Google Cloud ORG display name. - -type: keyword - -example: elastic-dev - --- - -*`cloud.origin.availability_zone`*:: -+ --- -Availability zone in which this host, resource, or service is located. - -type: keyword - -example: us-east-1c - --- - -*`cloud.origin.instance.id`*:: -+ --- -Instance ID of the host machine. - -type: keyword - -example: i-1234567890abcdef0 - --- - -*`cloud.origin.instance.name`*:: -+ --- -Instance name of the host machine. - -type: keyword - --- - -*`cloud.origin.machine.type`*:: -+ --- -Machine type of the host machine. - -type: keyword - -example: t2.medium - --- - -*`cloud.origin.project.id`*:: -+ --- -The cloud project identifier. -Examples: Google Cloud Project id, Azure Project id. - -type: keyword - -example: my-project - --- - -*`cloud.origin.project.name`*:: -+ --- -The cloud project name. -Examples: Google Cloud Project name, Azure Project name. - -type: keyword - -example: my project - --- - -*`cloud.origin.provider`*:: -+ --- -Name of the cloud provider. Example values are aws, azure, gcp, or digitalocean. - -type: keyword - -example: aws - --- - -*`cloud.origin.region`*:: -+ --- -Region in which this host, resource, or service is located. - -type: keyword - -example: us-east-1 - --- - -*`cloud.origin.service.name`*:: -+ --- -The cloud service name is intended to distinguish services running on different platforms within a provider, eg AWS EC2 vs Lambda, GCP GCE vs App Engine, Azure VM vs App Server. -Examples: app engine, app service, cloud run, fargate, lambda. - -type: keyword - -example: lambda - --- - -*`cloud.project.id`*:: -+ --- -The cloud project identifier. -Examples: Google Cloud Project id, Azure Project id. - -type: keyword - -example: my-project - --- - -*`cloud.project.name`*:: -+ --- -The cloud project name. -Examples: Google Cloud Project name, Azure Project name. - -type: keyword - -example: my project - --- - -*`cloud.provider`*:: -+ --- -Name of the cloud provider. Example values are aws, azure, gcp, or digitalocean. - -type: keyword - -example: aws - --- - -*`cloud.region`*:: -+ --- -Region in which this host, resource, or service is located. - -type: keyword - -example: us-east-1 - --- - -*`cloud.service.name`*:: -+ --- -The cloud service name is intended to distinguish services running on different platforms within a provider, eg AWS EC2 vs Lambda, GCP GCE vs App Engine, Azure VM vs App Server. -Examples: app engine, app service, cloud run, fargate, lambda. - -type: keyword - -example: lambda - --- - -*`cloud.target.account.id`*:: -+ --- -The cloud account or organization id used to identify different entities in a multi-tenant environment. -Examples: AWS account id, Google Cloud ORG Id, or other unique identifier. - -type: keyword - -example: 666777888999 - --- - -*`cloud.target.account.name`*:: -+ --- -The cloud account name or alias used to identify different entities in a multi-tenant environment. -Examples: AWS account name, Google Cloud ORG display name. - -type: keyword - -example: elastic-dev - --- - -*`cloud.target.availability_zone`*:: -+ --- -Availability zone in which this host, resource, or service is located. - -type: keyword - -example: us-east-1c - --- - -*`cloud.target.instance.id`*:: -+ --- -Instance ID of the host machine. - -type: keyword - -example: i-1234567890abcdef0 - --- - -*`cloud.target.instance.name`*:: -+ --- -Instance name of the host machine. - -type: keyword - --- - -*`cloud.target.machine.type`*:: -+ --- -Machine type of the host machine. - -type: keyword - -example: t2.medium - --- - -*`cloud.target.project.id`*:: -+ --- -The cloud project identifier. -Examples: Google Cloud Project id, Azure Project id. - -type: keyword - -example: my-project - --- - -*`cloud.target.project.name`*:: -+ --- -The cloud project name. -Examples: Google Cloud Project name, Azure Project name. - -type: keyword - -example: my project - --- - -*`cloud.target.provider`*:: -+ --- -Name of the cloud provider. Example values are aws, azure, gcp, or digitalocean. - -type: keyword - -example: aws - --- - -*`cloud.target.region`*:: -+ --- -Region in which this host, resource, or service is located. - -type: keyword - -example: us-east-1 - --- - -*`cloud.target.service.name`*:: -+ --- -The cloud service name is intended to distinguish services running on different platforms within a provider, eg AWS EC2 vs Lambda, GCP GCE vs App Engine, Azure VM vs App Server. -Examples: app engine, app service, cloud run, fargate, lambda. - -type: keyword - -example: lambda - --- - -[float] -=== code_signature - -These fields contain information about binary code signatures. - - -*`code_signature.digest_algorithm`*:: -+ --- -The hashing algorithm used to sign the process. -This value can distinguish signatures when a file is signed multiple times by the same signer but with a different digest algorithm. - -type: keyword - -example: sha256 - --- - -*`code_signature.exists`*:: -+ --- -Boolean to capture if a signature is present. - -type: boolean - -example: true - --- - -*`code_signature.signing_id`*:: -+ --- -The identifier used to sign the process. -This is used to identify the application manufactured by a software vendor. The field is relevant to Apple *OS only. - -type: keyword - -example: com.apple.xpc.proxy - --- - -*`code_signature.status`*:: -+ --- -Additional information about the certificate status. -This is useful for logging cryptographic errors with the certificate validity or trust status. Leave unpopulated if the validity or trust of the certificate was unchecked. - -type: keyword - -example: ERROR_UNTRUSTED_ROOT - --- - -*`code_signature.subject_name`*:: -+ --- -Subject name of the code signer - -type: keyword - -example: Microsoft Corporation - --- - -*`code_signature.team_id`*:: -+ --- -The team identifier used to sign the process. -This is used to identify the team or vendor of a software product. The field is relevant to Apple *OS only. - -type: keyword - -example: EQHXZ8M8AV - --- - -*`code_signature.timestamp`*:: -+ --- -Date and time when the code signature was generated and signed. - -type: date - -example: 2021-01-01T12:10:30Z - --- - -*`code_signature.trusted`*:: -+ --- -Stores the trust status of the certificate chain. -Validating the trust of the certificate chain may be complicated, and this field should only be populated by tools that actively check the status. - -type: boolean - -example: true - --- - -*`code_signature.valid`*:: -+ --- -Boolean to capture if the digital signature is verified against the binary content. -Leave unpopulated if a certificate was unchecked. - -type: boolean - -example: true - --- - -[float] -=== container - -Container fields are used for meta information about the specific container that is the source of information. These fields help correlate data based containers from any runtime. - - -*`container.cpu.usage`*:: -+ --- -Percent CPU used which is normalized by the number of CPU cores and it ranges from 0 to 1. Scaling factor: 1000. - -type: scaled_float - --- - -*`container.disk.read.bytes`*:: -+ --- -The total number of bytes (gauge) read successfully (aggregated from all disks) since the last metric collection. - -type: long - --- - -*`container.disk.write.bytes`*:: -+ --- -The total number of bytes (gauge) written successfully (aggregated from all disks) since the last metric collection. - -type: long - --- - -*`container.id`*:: -+ --- -Unique container id. - -type: keyword - --- - -*`container.image.name`*:: -+ --- -Name of the image the container was built on. - -type: keyword - --- - -*`container.image.tag`*:: -+ --- -Container image tags. - -type: keyword - --- - -*`container.labels`*:: -+ --- -Image labels. - -type: object - --- - -*`container.memory.usage`*:: -+ --- -Memory usage percentage and it ranges from 0 to 1. Scaling factor: 1000. - -type: scaled_float - --- - -*`container.name`*:: -+ --- -Container name. - -type: keyword - --- - -*`container.network.egress.bytes`*:: -+ --- -The number of bytes (gauge) sent out on all network interfaces by the container since the last metric collection. - -type: long - --- - -*`container.network.ingress.bytes`*:: -+ --- -The number of bytes received (gauge) on all network interfaces by the container since the last metric collection. - -type: long - --- - -*`container.runtime`*:: -+ --- -Runtime managing this container. - -type: keyword - -example: docker - --- - -[float] -=== data_stream - -The data_stream fields take part in defining the new data stream naming scheme. -In the new data stream naming scheme the value of the data stream fields combine to the name of the actual data stream in the following manner: `{data_stream.type}-{data_stream.dataset}-{data_stream.namespace}`. This means the fields can only contain characters that are valid as part of names of data streams. More details about this can be found in this https://www.elastic.co/blog/an-introduction-to-the-elastic-data-stream-naming-scheme[blog post]. -An Elasticsearch data stream consists of one or more backing indices, and a data stream name forms part of the backing indices names. Due to this convention, data streams must also follow index naming restrictions. For example, data stream names cannot include `\`, `/`, `*`, `?`, `"`, `<`, `>`, `|`, ` ` (space character), `,`, or `#`. Please see the Elasticsearch reference for additional https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html#indices-create-api-path-params[restrictions]. - - -*`data_stream.dataset`*:: -+ --- -The field can contain anything that makes sense to signify the source of the data. -Examples include `nginx.access`, `prometheus`, `endpoint` etc. For data streams that otherwise fit, but that do not have dataset set we use the value "generic" for the dataset value. `event.dataset` should have the same value as `data_stream.dataset`. -Beyond the Elasticsearch data stream naming criteria noted above, the `dataset` value has additional restrictions: - * Must not contain `-` - * No longer than 100 characters - -type: constant_keyword - -example: nginx.access - --- - -*`data_stream.namespace`*:: -+ --- -A user defined namespace. Namespaces are useful to allow grouping of data. -Many users already organize their indices this way, and the data stream naming scheme now provides this best practice as a default. Many users will populate this field with `default`. If no value is used, it falls back to `default`. -Beyond the Elasticsearch index naming criteria noted above, `namespace` value has the additional restrictions: - * Must not contain `-` - * No longer than 100 characters - -type: constant_keyword - -example: production - --- - -*`data_stream.type`*:: -+ --- -An overarching type for the data stream. -Currently allowed values are "logs" and "metrics". We expect to also add "traces" and "synthetics" in the near future. - -type: constant_keyword - -example: logs - --- - -[float] -=== destination - -Destination fields capture details about the receiver of a network exchange/packet. These fields are populated from a network event, packet, or other event containing details of a network transaction. -Destination fields are usually populated in conjunction with source fields. The source and destination fields are considered the baseline and should always be filled if an event contains source and destination details from a network transaction. If the event also contains identification of the client and server roles, then the client and server fields should also be populated. - - -*`destination.address`*:: -+ --- -Some event destination addresses are defined ambiguously. The event will sometimes list an IP, a domain or a unix socket. You should always store the raw address in the `.address` field. -Then it should be duplicated to `.ip` or `.domain`, depending on which one it is. - -type: keyword - --- - -*`destination.as.number`*:: -+ --- -Unique number allocated to the autonomous system. The autonomous system number (ASN) uniquely identifies each network on the Internet. - -type: long - -example: 15169 - --- - -*`destination.as.organization.name`*:: -+ --- -Organization name. - -type: keyword - -example: Google LLC - --- - -*`destination.as.organization.name.text`*:: -+ --- -type: match_only_text - --- - -*`destination.bytes`*:: -+ --- -Bytes sent from the destination to the source. - -type: long - -example: 184 - -format: bytes - --- - -*`destination.domain`*:: -+ --- -The domain name of the destination system. -This value may be a host name, a fully qualified domain name, or another host naming format. The value may derive from the original event or be added from enrichment. - -type: keyword - -example: foo.example.com - --- - -*`destination.geo.city_name`*:: -+ --- -City name. - -type: keyword - -example: Montreal - --- - -*`destination.geo.continent_code`*:: -+ --- -Two-letter code representing continent's name. - -type: keyword - -example: NA - --- - -*`destination.geo.continent_name`*:: -+ --- -Name of the continent. - -type: keyword - -example: North America - --- - -*`destination.geo.country_iso_code`*:: -+ --- -Country ISO code. - -type: keyword - -example: CA - --- - -*`destination.geo.country_name`*:: -+ --- -Country name. - -type: keyword - -example: Canada - --- - -*`destination.geo.location`*:: -+ --- -Longitude and latitude. - -type: geo_point - -example: { "lon": -73.614830, "lat": 45.505918 } - --- - -*`destination.geo.name`*:: -+ --- -User-defined description of a location, at the level of granularity they care about. -Could be the name of their data centers, the floor number, if this describes a local physical entity, city names. -Not typically used in automated geolocation. - -type: keyword - -example: boston-dc - --- - -*`destination.geo.postal_code`*:: -+ --- -Postal code associated with the location. -Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country. - -type: keyword - -example: 94040 - --- - -*`destination.geo.region_iso_code`*:: -+ --- -Region ISO code. - -type: keyword - -example: CA-QC - --- - -*`destination.geo.region_name`*:: -+ --- -Region name. - -type: keyword - -example: Quebec - --- - -*`destination.geo.timezone`*:: -+ --- -The time zone of the location, such as IANA time zone name. - -type: keyword - -example: America/Argentina/Buenos_Aires - --- - -*`destination.ip`*:: -+ --- -IP address of the destination (IPv4 or IPv6). - -type: ip - --- - -*`destination.mac`*:: -+ --- -MAC address of the destination. -The notation format from RFC 7042 is suggested: Each octet (that is, 8-bit byte) is represented by two [uppercase] hexadecimal digits giving the value of the octet as an unsigned integer. Successive octets are separated by a hyphen. - -type: keyword - -example: 00-00-5E-00-53-23 - --- - -*`destination.nat.ip`*:: -+ --- -Translated ip of destination based NAT sessions (e.g. internet to private DMZ) -Typically used with load balancers, firewalls, or routers. - -type: ip - --- - -*`destination.nat.port`*:: -+ --- -Port the source session is translated to by NAT Device. -Typically used with load balancers, firewalls, or routers. - -type: long - -format: string - --- - -*`destination.packets`*:: -+ --- -Packets sent from the destination to the source. - -type: long - -example: 12 - --- - -*`destination.port`*:: -+ --- -Port of the destination. - -type: long - -format: string - --- - -*`destination.registered_domain`*:: -+ --- -The highest registered destination domain, stripped of the subdomain. -For example, the registered domain for "foo.example.com" is "example.com". -This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk". - -type: keyword - -example: example.com - --- - -*`destination.subdomain`*:: -+ --- -The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. -For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period. - -type: keyword - -example: east - --- - -*`destination.top_level_domain`*:: -+ --- -The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". -This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk". - -type: keyword - -example: co.uk - --- - -*`destination.user.domain`*:: -+ --- -Name of the directory the user is a member of. -For example, an LDAP or Active Directory domain name. - -type: keyword - --- - -*`destination.user.email`*:: -+ --- -User email address. - -type: keyword - --- - -*`destination.user.full_name`*:: -+ --- -User's full name, if available. - -type: keyword - -example: Albert Einstein - --- - -*`destination.user.full_name.text`*:: -+ --- -type: match_only_text - --- - -*`destination.user.group.domain`*:: -+ --- -Name of the directory the group is a member of. -For example, an LDAP or Active Directory domain name. - -type: keyword - --- - -*`destination.user.group.id`*:: -+ --- -Unique identifier for the group on the system/platform. - -type: keyword - --- - -*`destination.user.group.name`*:: -+ --- -Name of the group. - -type: keyword - --- - -*`destination.user.hash`*:: -+ --- -Unique user hash to correlate information for a user in anonymized form. -Useful if `user.id` or `user.name` contain confidential information and cannot be used. - -type: keyword - --- - -*`destination.user.id`*:: -+ --- -Unique identifier of the user. - -type: keyword - -example: S-1-5-21-202424912787-2692429404-2351956786-1000 - --- - -*`destination.user.name`*:: -+ --- -Short name or login of the user. - -type: keyword - -example: a.einstein - --- - -*`destination.user.name.text`*:: -+ --- -type: match_only_text - --- - -*`destination.user.roles`*:: -+ --- -Array of user roles at the time of the event. - -type: keyword - -example: ["kibana_admin", "reporting_user"] - --- - -[float] -=== dll - -These fields contain information about code libraries dynamically loaded into processes. - -Many operating systems refer to "shared code libraries" with different names, but this field set refers to all of the following: -* Dynamic-link library (`.dll`) commonly used on Windows -* Shared Object (`.so`) commonly used on Unix-like operating systems -* Dynamic library (`.dylib`) commonly used on macOS - - -*`dll.code_signature.digest_algorithm`*:: -+ --- -The hashing algorithm used to sign the process. -This value can distinguish signatures when a file is signed multiple times by the same signer but with a different digest algorithm. - -type: keyword - -example: sha256 - --- - -*`dll.code_signature.exists`*:: -+ --- -Boolean to capture if a signature is present. - -type: boolean - -example: true - --- - -*`dll.code_signature.signing_id`*:: -+ --- -The identifier used to sign the process. -This is used to identify the application manufactured by a software vendor. The field is relevant to Apple *OS only. - -type: keyword - -example: com.apple.xpc.proxy - --- - -*`dll.code_signature.status`*:: -+ --- -Additional information about the certificate status. -This is useful for logging cryptographic errors with the certificate validity or trust status. Leave unpopulated if the validity or trust of the certificate was unchecked. - -type: keyword - -example: ERROR_UNTRUSTED_ROOT - --- - -*`dll.code_signature.subject_name`*:: -+ --- -Subject name of the code signer - -type: keyword - -example: Microsoft Corporation - --- - -*`dll.code_signature.team_id`*:: -+ --- -The team identifier used to sign the process. -This is used to identify the team or vendor of a software product. The field is relevant to Apple *OS only. - -type: keyword - -example: EQHXZ8M8AV - --- - -*`dll.code_signature.timestamp`*:: -+ --- -Date and time when the code signature was generated and signed. - -type: date - -example: 2021-01-01T12:10:30Z - --- - -*`dll.code_signature.trusted`*:: -+ --- -Stores the trust status of the certificate chain. -Validating the trust of the certificate chain may be complicated, and this field should only be populated by tools that actively check the status. - -type: boolean - -example: true - --- - -*`dll.code_signature.valid`*:: -+ --- -Boolean to capture if the digital signature is verified against the binary content. -Leave unpopulated if a certificate was unchecked. - -type: boolean - -example: true - --- - -*`dll.hash.md5`*:: -+ --- -MD5 hash. - -type: keyword - --- - -*`dll.hash.sha1`*:: -+ --- -SHA1 hash. - -type: keyword - --- - -*`dll.hash.sha256`*:: -+ --- -SHA256 hash. - -type: keyword - --- - -*`dll.hash.sha512`*:: -+ --- -SHA512 hash. - -type: keyword - --- - -*`dll.hash.ssdeep`*:: -+ --- -SSDEEP hash. - -type: keyword - --- - -*`dll.name`*:: -+ --- -Name of the library. -This generally maps to the name of the file on disk. - -type: keyword - -example: kernel32.dll - --- - -*`dll.path`*:: -+ --- -Full file path of the library. - -type: keyword - -example: C:\Windows\System32\kernel32.dll - --- - -*`dll.pe.architecture`*:: -+ --- -CPU architecture target for the file. - -type: keyword - -example: x64 - --- - -*`dll.pe.company`*:: -+ --- -Internal company name of the file, provided at compile-time. - -type: keyword - -example: Microsoft Corporation - --- - -*`dll.pe.description`*:: -+ --- -Internal description of the file, provided at compile-time. - -type: keyword - -example: Paint - --- - -*`dll.pe.file_version`*:: -+ --- -Internal version of the file, provided at compile-time. - -type: keyword - -example: 6.3.9600.17415 - --- - -*`dll.pe.imphash`*:: -+ --- -A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. -Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html. - -type: keyword - -example: 0c6803c4e922103c4dca5963aad36ddf - --- - -*`dll.pe.original_file_name`*:: -+ --- -Internal name of the file, provided at compile-time. - -type: keyword - -example: MSPAINT.EXE - --- - -*`dll.pe.product`*:: -+ --- -Internal product name of the file, provided at compile-time. - -type: keyword - -example: Microsoft® Windows® Operating System - --- - -[float] -=== dns - -Fields describing DNS queries and answers. -DNS events should either represent a single DNS query prior to getting answers (`dns.type:query`) or they should represent a full exchange and contain the query details as well as all of the answers that were provided for this query (`dns.type:answer`). - - -*`dns.answers`*:: -+ --- -An array containing an object for each answer section returned by the server. -The main keys that should be present in these objects are defined by ECS. Records that have more information may contain more keys than what ECS defines. -Not all DNS data sources give all details about DNS answers. At minimum, answer objects must contain the `data` key. If more information is available, map as much of it to ECS as possible, and add any additional fields to the answer objects as custom fields. - -type: object - --- - -*`dns.answers.class`*:: -+ --- -The class of DNS data contained in this resource record. - -type: keyword - -example: IN - --- - -*`dns.answers.data`*:: -+ --- -The data describing the resource. -The meaning of this data depends on the type and class of the resource record. - -type: keyword - -example: 10.10.10.10 - --- - -*`dns.answers.name`*:: -+ --- -The domain name to which this resource record pertains. -If a chain of CNAME is being resolved, each answer's `name` should be the one that corresponds with the answer's `data`. It should not simply be the original `question.name` repeated. - -type: keyword - -example: www.example.com - --- - -*`dns.answers.ttl`*:: -+ --- -The time interval in seconds that this resource record may be cached before it should be discarded. Zero values mean that the data should not be cached. - -type: long - -example: 180 - --- - -*`dns.answers.type`*:: -+ --- -The type of data contained in this resource record. - -type: keyword - -example: CNAME - --- - -*`dns.header_flags`*:: -+ --- -Array of 2 letter DNS header flags. -Expected values are: AA, TC, RD, RA, AD, CD, DO. - -type: keyword - -example: ["RD", "RA"] - --- - -*`dns.id`*:: -+ --- -The DNS packet identifier assigned by the program that generated the query. The identifier is copied to the response. - -type: keyword - -example: 62111 - --- - -*`dns.op_code`*:: -+ --- -The DNS operation code that specifies the kind of query in the message. This value is set by the originator of a query and copied into the response. - -type: keyword - -example: QUERY - --- - -*`dns.question.class`*:: -+ --- -The class of records being queried. - -type: keyword - -example: IN - --- - -*`dns.question.name`*:: -+ --- -The name being queried. -If the name field contains non-printable characters (below 32 or above 126), those characters should be represented as escaped base 10 integers (\DDD). Back slashes and quotes should be escaped. Tabs, carriage returns, and line feeds should be converted to \t, \r, and \n respectively. - -type: keyword - -example: www.example.com - --- - -*`dns.question.registered_domain`*:: -+ --- -The highest registered domain, stripped of the subdomain. -For example, the registered domain for "foo.example.com" is "example.com". -This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk". - -type: keyword - -example: example.com - --- - -*`dns.question.subdomain`*:: -+ --- -The subdomain is all of the labels under the registered_domain. -If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period. - -type: keyword - -example: www - --- - -*`dns.question.top_level_domain`*:: -+ --- -The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". -This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk". - -type: keyword - -example: co.uk - --- - -*`dns.question.type`*:: -+ --- -The type of record being queried. - -type: keyword - -example: AAAA - --- - -*`dns.resolved_ip`*:: -+ --- -Array containing all IPs seen in `answers.data`. -The `answers` array can be difficult to use, because of the variety of data formats it can contain. Extracting all IP addresses seen in there to `dns.resolved_ip` makes it possible to index them as IP addresses, and makes them easier to visualize and query for. - -type: ip - -example: ["10.10.10.10", "10.10.10.11"] - --- - -*`dns.response_code`*:: -+ --- -The DNS response code. - -type: keyword - -example: NOERROR - --- - -*`dns.type`*:: -+ --- -The type of DNS event captured, query or answer. -If your source of DNS events only gives you DNS queries, you should only create dns events of type `dns.type:query`. -If your source of DNS events gives you answers as well, you should create one event per query (optionally as soon as the query is seen). And a second event containing all query details as well as an array of answers. - -type: keyword - -example: answer - --- - -[float] -=== ecs - -Meta-information specific to ECS. - - -*`ecs.version`*:: -+ --- -ECS version this event conforms to. `ecs.version` is a required field and must exist in all events. -When querying across multiple indices -- which may conform to slightly different ECS versions -- this field lets integrations adjust to the schema version of the events. - -type: keyword - -example: 1.0.0 - -required: True - --- - -[float] -=== elf - -These fields contain Linux Executable Linkable Format (ELF) metadata. - - -*`elf.architecture`*:: -+ --- -Machine architecture of the ELF file. - -type: keyword - -example: x86-64 - --- - -*`elf.byte_order`*:: -+ --- -Byte sequence of ELF file. - -type: keyword - -example: Little Endian - --- - -*`elf.cpu_type`*:: -+ --- -CPU type of the ELF file. - -type: keyword - -example: Intel - --- - -*`elf.creation_date`*:: -+ --- -Extracted when possible from the file's metadata. Indicates when it was built or compiled. It can also be faked by malware creators. - -type: date - --- - -*`elf.exports`*:: -+ --- -List of exported element names and types. - -type: flattened - --- - -*`elf.header.abi_version`*:: -+ --- -Version of the ELF Application Binary Interface (ABI). - -type: keyword - --- - -*`elf.header.class`*:: -+ --- -Header class of the ELF file. - -type: keyword - --- - -*`elf.header.data`*:: -+ --- -Data table of the ELF header. - -type: keyword - --- - -*`elf.header.entrypoint`*:: -+ --- -Header entrypoint of the ELF file. - -type: long - -format: string - --- - -*`elf.header.object_version`*:: -+ --- -"0x1" for original ELF files. - -type: keyword - --- - -*`elf.header.os_abi`*:: -+ --- -Application Binary Interface (ABI) of the Linux OS. - -type: keyword - --- - -*`elf.header.type`*:: -+ --- -Header type of the ELF file. - -type: keyword - --- - -*`elf.header.version`*:: -+ --- -Version of the ELF header. - -type: keyword - --- - -*`elf.imports`*:: -+ --- -List of imported element names and types. - -type: flattened - --- - -*`elf.sections`*:: -+ --- -An array containing an object for each section of the ELF file. -The keys that should be present in these objects are defined by sub-fields underneath `elf.sections.*`. - -type: nested - --- - -*`elf.sections.chi2`*:: -+ --- -Chi-square probability distribution of the section. - -type: long - -format: number - --- - -*`elf.sections.entropy`*:: -+ --- -Shannon entropy calculation from the section. - -type: long - -format: number - --- - -*`elf.sections.flags`*:: -+ --- -ELF Section List flags. - -type: keyword - --- - -*`elf.sections.name`*:: -+ --- -ELF Section List name. - -type: keyword - --- - -*`elf.sections.physical_offset`*:: -+ --- -ELF Section List offset. - -type: keyword - --- - -*`elf.sections.physical_size`*:: -+ --- -ELF Section List physical size. - -type: long - -format: bytes - --- - -*`elf.sections.type`*:: -+ --- -ELF Section List type. - -type: keyword - --- - -*`elf.sections.virtual_address`*:: -+ --- -ELF Section List virtual address. - -type: long - -format: string - --- - -*`elf.sections.virtual_size`*:: -+ --- -ELF Section List virtual size. - -type: long - -format: string - --- - -*`elf.segments`*:: -+ --- -An array containing an object for each segment of the ELF file. -The keys that should be present in these objects are defined by sub-fields underneath `elf.segments.*`. - -type: nested - --- - -*`elf.segments.sections`*:: -+ --- -ELF object segment sections. - -type: keyword - --- - -*`elf.segments.type`*:: -+ --- -ELF object segment type. - -type: keyword - --- - -*`elf.shared_libraries`*:: -+ --- -List of shared libraries used by this ELF object. - -type: keyword - --- - -*`elf.telfhash`*:: -+ --- -telfhash symbol hash for ELF file. - -type: keyword - --- - -[float] -=== error - -These fields can represent errors of any kind. -Use them for errors that happen while fetching events or in cases where the event itself contains an error. - - -*`error.code`*:: -+ --- -Error code describing the error. - -type: keyword - --- - -*`error.id`*:: -+ --- -Unique identifier for the error. - -type: keyword - --- - -*`error.message`*:: -+ --- -Error message. - -type: match_only_text - --- - -*`error.stack_trace`*:: -+ --- -The stack trace of this error in plain text. - -type: wildcard - --- - -*`error.stack_trace.text`*:: -+ --- -type: match_only_text - --- - -*`error.type`*:: -+ --- -The type of the error, for example the class name of the exception. - -type: keyword - -example: java.lang.NullPointerException - --- - -[float] -=== event - -The event fields are used for context information about the log or metric event itself. -A log is defined as an event containing details of something that happened. Log events must include the time at which the thing happened. Examples of log events include a process starting on a host, a network packet being sent from a source to a destination, or a network connection between a client and a server being initiated or closed. A metric is defined as an event containing one or more numerical measurements and the time at which the measurement was taken. Examples of metric events include memory pressure measured on a host and device temperature. See the `event.kind` definition in this section for additional details about metric and state events. - - -*`event.action`*:: -+ --- -The action captured by the event. -This describes the information in the event. It is more specific than `event.category`. Examples are `group-add`, `process-started`, `file-created`. The value is normally defined by the implementer. - -type: keyword - -example: user-password-change - --- - -*`event.agent_id_status`*:: -+ --- -Agents are normally responsible for populating the `agent.id` field value. If the system receiving events is capable of validating the value based on authentication information for the client then this field can be used to reflect the outcome of that validation. -For example if the agent's connection is authenticated with mTLS and the client cert contains the ID of the agent to which the cert was issued then the `agent.id` value in events can be checked against the certificate. If the values match then `event.agent_id_status: verified` is added to the event, otherwise one of the other allowed values should be used. -If no validation is performed then the field should be omitted. -The allowed values are: -`verified` - The `agent.id` field value matches expected value obtained from auth metadata. -`mismatch` - The `agent.id` field value does not match the expected value obtained from auth metadata. -`missing` - There was no `agent.id` field in the event to validate. -`auth_metadata_missing` - There was no auth metadata or it was missing information about the agent ID. - -type: keyword - -example: verified - --- - -*`event.category`*:: -+ --- -This is one of four ECS Categorization Fields, and indicates the second level in the ECS category hierarchy. -`event.category` represents the "big buckets" of ECS categories. For example, filtering on `event.category:process` yields all events relating to process activity. This field is closely related to `event.type`, which is used as a subcategory. -This field is an array. This will allow proper categorization of some events that fall in multiple categories. - -type: keyword - -example: authentication - --- - -*`event.code`*:: -+ --- -Identification code for this event, if one exists. -Some event sources use event codes to identify messages unambiguously, regardless of message language or wording adjustments over time. An example of this is the Windows Event ID. - -type: keyword - -example: 4648 - --- - -*`event.created`*:: -+ --- -event.created contains the date/time when the event was first read by an agent, or by your pipeline. -This field is distinct from @timestamp in that @timestamp typically contain the time extracted from the original event. -In most situations, these two timestamps will be slightly different. The difference can be used to calculate the delay between your source generating an event, and the time when your agent first processed it. This can be used to monitor your agent's or pipeline's ability to keep up with your event source. -In case the two timestamps are identical, @timestamp should be used. - -type: date - -example: 2016-05-23T08:05:34.857Z - --- - -*`event.dataset`*:: -+ --- -Name of the dataset. -If an event source publishes more than one type of log or events (e.g. access log, error log), the dataset is used to specify which one the event comes from. -It's recommended but not required to start the dataset name with the module name, followed by a dot, then the dataset name. - -type: keyword - -example: apache.access - --- - -*`event.duration`*:: -+ --- -Duration of the event in nanoseconds. -If event.start and event.end are known this value should be the difference between the end and start time. - -type: long - -format: duration - --- - -*`event.end`*:: -+ --- -event.end contains the date when the event ended or when the activity was last observed. - -type: date - --- - -*`event.hash`*:: -+ --- -Hash (perhaps logstash fingerprint) of raw field to be able to demonstrate log integrity. - -type: keyword - -example: 123456789012345678901234567890ABCD - --- - -*`event.id`*:: -+ --- -Unique ID to describe the event. - -type: keyword - -example: 8a4f500d - --- - -*`event.ingested`*:: -+ --- -Timestamp when an event arrived in the central data store. -This is different from `@timestamp`, which is when the event originally occurred. It's also different from `event.created`, which is meant to capture the first time an agent saw the event. -In normal conditions, assuming no tampering, the timestamps should chronologically look like this: `@timestamp` < `event.created` < `event.ingested`. - -type: date - -example: 2016-05-23T08:05:35.101Z - --- - -*`event.kind`*:: -+ --- -This is one of four ECS Categorization Fields, and indicates the highest level in the ECS category hierarchy. -`event.kind` gives high-level information about what type of information the event contains, without being specific to the contents of the event. For example, values of this field distinguish alert events from metric events. -The value of this field can be used to inform how these kinds of events should be handled. They may warrant different retention, different access control, it may also help understand whether the data coming in at a regular interval or not. - -type: keyword - -example: alert - --- - -*`event.module`*:: -+ --- -Name of the module this data is coming from. -If your monitoring agent supports the concept of modules or plugins to process events of a given source (e.g. Apache logs), `event.module` should contain the name of this module. - -type: keyword - -example: apache - --- - -*`event.original`*:: -+ --- -Raw text message of entire event. Used to demonstrate log integrity or where the full log message (before splitting it up in multiple parts) may be required, e.g. for reindex. -This field is not indexed and doc_values are disabled. It cannot be searched, but it can be retrieved from `_source`. If users wish to override this and index this field, please see `Field data types` in the `Elasticsearch Reference`. - -type: keyword - -example: Sep 19 08:26:10 host CEF:0|Security| threatmanager|1.0|100| worm successfully stopped|10|src=10.0.0.1 dst=2.1.2.2spt=1232 - -Field is not indexed. - --- - -*`event.outcome`*:: -+ --- -This is one of four ECS Categorization Fields, and indicates the lowest level in the ECS category hierarchy. -`event.outcome` simply denotes whether the event represents a success or a failure from the perspective of the entity that produced the event. -Note that when a single transaction is described in multiple events, each event may populate different values of `event.outcome`, according to their perspective. -Also note that in the case of a compound event (a single event that contains multiple logical events), this field should be populated with the value that best captures the overall success or failure from the perspective of the event producer. -Further note that not all events will have an associated outcome. For example, this field is generally not populated for metric events, events with `event.type:info`, or any events for which an outcome does not make logical sense. - -type: keyword - -example: success - --- - -*`event.provider`*:: -+ --- -Source of the event. -Event transports such as Syslog or the Windows Event Log typically mention the source of an event. It can be the name of the software that generated the event (e.g. Sysmon, httpd), or of a subsystem of the operating system (kernel, Microsoft-Windows-Security-Auditing). - -type: keyword - -example: kernel - --- - -*`event.reason`*:: -+ --- -Reason why this event happened, according to the source. -This describes the why of a particular action or outcome captured in the event. Where `event.action` captures the action from the event, `event.reason` describes why that action was taken. For example, a web proxy with an `event.action` which denied the request may also populate `event.reason` with the reason why (e.g. `blocked site`). - -type: keyword - -example: Terminated an unexpected process - --- - -*`event.reference`*:: -+ --- -Reference URL linking to additional information about this event. -This URL links to a static definition of this event. Alert events, indicated by `event.kind:alert`, are a common use case for this field. - -type: keyword - -example: https://system.example.com/event/#0001234 - --- - -*`event.risk_score`*:: -+ --- -Risk score or priority of the event (e.g. security solutions). Use your system's original value here. - -type: float - --- - -*`event.risk_score_norm`*:: -+ --- -Normalized risk score or priority of the event, on a scale of 0 to 100. -This is mainly useful if you use more than one system that assigns risk scores, and you want to see a normalized value across all systems. - -type: float - --- - -*`event.sequence`*:: -+ --- -Sequence number of the event. -The sequence number is a value published by some event sources, to make the exact ordering of events unambiguous, regardless of the timestamp precision. - -type: long - -format: string - --- - -*`event.severity`*:: -+ --- -The numeric severity of the event according to your event source. -What the different severity values mean can be different between sources and use cases. It's up to the implementer to make sure severities are consistent across events from the same source. -The Syslog severity belongs in `log.syslog.severity.code`. `event.severity` is meant to represent the severity according to the event source (e.g. firewall, IDS). If the event source does not publish its own severity, you may optionally copy the `log.syslog.severity.code` to `event.severity`. - -type: long - -example: 7 - -format: string - --- - -*`event.start`*:: -+ --- -event.start contains the date when the event started or when the activity was first observed. - -type: date - --- - -*`event.timezone`*:: -+ --- -This field should be populated when the event's timestamp does not include timezone information already (e.g. default Syslog timestamps). It's optional otherwise. -Acceptable timezone formats are: a canonical ID (e.g. "Europe/Amsterdam"), abbreviated (e.g. "EST") or an HH:mm differential (e.g. "-05:00"). - -type: keyword - --- - -*`event.type`*:: -+ --- -This is one of four ECS Categorization Fields, and indicates the third level in the ECS category hierarchy. -`event.type` represents a categorization "sub-bucket" that, when used along with the `event.category` field values, enables filtering events down to a level appropriate for single visualization. -This field is an array. This will allow proper categorization of some events that fall in multiple event types. - -type: keyword - --- - -*`event.url`*:: -+ --- -URL linking to an external system to continue investigation of this event. -This URL links to another system where in-depth investigation of the specific occurrence of this event can take place. Alert events, indicated by `event.kind:alert`, are a common use case for this field. - -type: keyword - -example: https://mysystem.example.com/alert/5271dedb-f5b0-4218-87f0-4ac4870a38fe - --- - -[float] -=== faas - -The user fields describe information about the function as a service that is relevant to the event. - - -*`faas.coldstart`*:: -+ --- -Boolean value indicating a cold start of a function. - -type: boolean - --- - -*`faas.execution`*:: -+ --- -The execution ID of the current function execution. - -type: keyword - -example: af9d5aa4-a685-4c5f-a22b-444f80b3cc28 - --- - -*`faas.trigger`*:: -+ --- -Details about the function trigger. - -type: nested - --- - -*`faas.trigger.request_id`*:: -+ --- -The ID of the trigger request , message, event, etc. - -type: keyword - -example: 123456789 - --- - -*`faas.trigger.type`*:: -+ --- -The trigger for the function execution. -Expected values are: - * http - * pubsub - * datasource - * timer - * other - -type: keyword - -example: http - --- - -[float] -=== file - -A file is defined as a set of information that has been created on, or has existed on a filesystem. -File objects can be associated with host events, network events, and/or file events (e.g., those produced by File Integrity Monitoring [FIM] products or services). File fields provide details about the affected file associated with the event or metric. - - -*`file.accessed`*:: -+ --- -Last time the file was accessed. -Note that not all filesystems keep track of access time. - -type: date - --- - -*`file.attributes`*:: -+ --- -Array of file attributes. -Attributes names will vary by platform. Here's a non-exhaustive list of values that are expected in this field: archive, compressed, directory, encrypted, execute, hidden, read, readonly, system, write. - -type: keyword - -example: ["readonly", "system"] - --- - -*`file.code_signature.digest_algorithm`*:: -+ --- -The hashing algorithm used to sign the process. -This value can distinguish signatures when a file is signed multiple times by the same signer but with a different digest algorithm. - -type: keyword - -example: sha256 - --- - -*`file.code_signature.exists`*:: -+ --- -Boolean to capture if a signature is present. - -type: boolean - -example: true - --- - -*`file.code_signature.signing_id`*:: -+ --- -The identifier used to sign the process. -This is used to identify the application manufactured by a software vendor. The field is relevant to Apple *OS only. - -type: keyword - -example: com.apple.xpc.proxy - --- - -*`file.code_signature.status`*:: -+ --- -Additional information about the certificate status. -This is useful for logging cryptographic errors with the certificate validity or trust status. Leave unpopulated if the validity or trust of the certificate was unchecked. - -type: keyword - -example: ERROR_UNTRUSTED_ROOT - --- - -*`file.code_signature.subject_name`*:: -+ --- -Subject name of the code signer - -type: keyword - -example: Microsoft Corporation - --- - -*`file.code_signature.team_id`*:: -+ --- -The team identifier used to sign the process. -This is used to identify the team or vendor of a software product. The field is relevant to Apple *OS only. - -type: keyword - -example: EQHXZ8M8AV - --- - -*`file.code_signature.timestamp`*:: -+ --- -Date and time when the code signature was generated and signed. - -type: date - -example: 2021-01-01T12:10:30Z - --- - -*`file.code_signature.trusted`*:: -+ --- -Stores the trust status of the certificate chain. -Validating the trust of the certificate chain may be complicated, and this field should only be populated by tools that actively check the status. - -type: boolean - -example: true - --- - -*`file.code_signature.valid`*:: -+ --- -Boolean to capture if the digital signature is verified against the binary content. -Leave unpopulated if a certificate was unchecked. - -type: boolean - -example: true - --- - -*`file.created`*:: -+ --- -File creation time. -Note that not all filesystems store the creation time. - -type: date - --- - -*`file.ctime`*:: -+ --- -Last time the file attributes or metadata changed. -Note that changes to the file content will update `mtime`. This implies `ctime` will be adjusted at the same time, since `mtime` is an attribute of the file. - -type: date - --- - -*`file.device`*:: -+ --- -Device that is the source of the file. - -type: keyword - -example: sda - --- - -*`file.directory`*:: -+ --- -Directory where the file is located. It should include the drive letter, when appropriate. - -type: keyword - -example: /home/alice - --- - -*`file.drive_letter`*:: -+ --- -Drive letter where the file is located. This field is only relevant on Windows. -The value should be uppercase, and not include the colon. - -type: keyword - -example: C - --- - -*`file.elf.architecture`*:: -+ --- -Machine architecture of the ELF file. - -type: keyword - -example: x86-64 - --- - -*`file.elf.byte_order`*:: -+ --- -Byte sequence of ELF file. - -type: keyword - -example: Little Endian - --- - -*`file.elf.cpu_type`*:: -+ --- -CPU type of the ELF file. - -type: keyword - -example: Intel - --- - -*`file.elf.creation_date`*:: -+ --- -Extracted when possible from the file's metadata. Indicates when it was built or compiled. It can also be faked by malware creators. - -type: date - --- - -*`file.elf.exports`*:: -+ --- -List of exported element names and types. - -type: flattened - --- - -*`file.elf.header.abi_version`*:: -+ --- -Version of the ELF Application Binary Interface (ABI). - -type: keyword - --- - -*`file.elf.header.class`*:: -+ --- -Header class of the ELF file. - -type: keyword - --- - -*`file.elf.header.data`*:: -+ --- -Data table of the ELF header. - -type: keyword - --- - -*`file.elf.header.entrypoint`*:: -+ --- -Header entrypoint of the ELF file. - -type: long - -format: string - --- - -*`file.elf.header.object_version`*:: -+ --- -"0x1" for original ELF files. - -type: keyword - --- - -*`file.elf.header.os_abi`*:: -+ --- -Application Binary Interface (ABI) of the Linux OS. - -type: keyword - --- - -*`file.elf.header.type`*:: -+ --- -Header type of the ELF file. - -type: keyword - --- - -*`file.elf.header.version`*:: -+ --- -Version of the ELF header. - -type: keyword - --- - -*`file.elf.imports`*:: -+ --- -List of imported element names and types. - -type: flattened - --- - -*`file.elf.sections`*:: -+ --- -An array containing an object for each section of the ELF file. -The keys that should be present in these objects are defined by sub-fields underneath `elf.sections.*`. - -type: nested - --- - -*`file.elf.sections.chi2`*:: -+ --- -Chi-square probability distribution of the section. - -type: long - -format: number - --- - -*`file.elf.sections.entropy`*:: -+ --- -Shannon entropy calculation from the section. - -type: long - -format: number - --- - -*`file.elf.sections.flags`*:: -+ --- -ELF Section List flags. - -type: keyword - --- - -*`file.elf.sections.name`*:: -+ --- -ELF Section List name. - -type: keyword - --- - -*`file.elf.sections.physical_offset`*:: -+ --- -ELF Section List offset. - -type: keyword - --- - -*`file.elf.sections.physical_size`*:: -+ --- -ELF Section List physical size. - -type: long - -format: bytes - --- - -*`file.elf.sections.type`*:: -+ --- -ELF Section List type. - -type: keyword - --- - -*`file.elf.sections.virtual_address`*:: -+ --- -ELF Section List virtual address. - -type: long - -format: string - --- - -*`file.elf.sections.virtual_size`*:: -+ --- -ELF Section List virtual size. - -type: long - -format: string - --- - -*`file.elf.segments`*:: -+ --- -An array containing an object for each segment of the ELF file. -The keys that should be present in these objects are defined by sub-fields underneath `elf.segments.*`. - -type: nested - --- - -*`file.elf.segments.sections`*:: -+ --- -ELF object segment sections. - -type: keyword - --- - -*`file.elf.segments.type`*:: -+ --- -ELF object segment type. - -type: keyword - --- - -*`file.elf.shared_libraries`*:: -+ --- -List of shared libraries used by this ELF object. - -type: keyword - --- - -*`file.elf.telfhash`*:: -+ --- -telfhash symbol hash for ELF file. - -type: keyword - --- - -*`file.extension`*:: -+ --- -File extension, excluding the leading dot. -Note that when the file name has multiple extensions (example.tar.gz), only the last one should be captured ("gz", not "tar.gz"). - -type: keyword - -example: png - --- - -*`file.fork_name`*:: -+ --- -A fork is additional data associated with a filesystem object. -On Linux, a resource fork is used to store additional data with a filesystem object. A file always has at least one fork for the data portion, and additional forks may exist. -On NTFS, this is analogous to an Alternate Data Stream (ADS), and the default data stream for a file is just called $DATA. Zone.Identifier is commonly used by Windows to track contents downloaded from the Internet. An ADS is typically of the form: `C:\path\to\filename.extension:some_fork_name`, and `some_fork_name` is the value that should populate `fork_name`. `filename.extension` should populate `file.name`, and `extension` should populate `file.extension`. The full path, `file.path`, will include the fork name. - -type: keyword - -example: Zone.Identifer - --- - -*`file.gid`*:: -+ --- -Primary group ID (GID) of the file. - -type: keyword - -example: 1001 - --- - -*`file.group`*:: -+ --- -Primary group name of the file. - -type: keyword - -example: alice - --- - -*`file.hash.md5`*:: -+ --- -MD5 hash. - -type: keyword - --- - -*`file.hash.sha1`*:: -+ --- -SHA1 hash. - -type: keyword - --- - -*`file.hash.sha256`*:: -+ --- -SHA256 hash. - -type: keyword - --- - -*`file.hash.sha512`*:: -+ --- -SHA512 hash. - -type: keyword - --- - -*`file.hash.ssdeep`*:: -+ --- -SSDEEP hash. - -type: keyword - --- - -*`file.inode`*:: -+ --- -Inode representing the file in the filesystem. - -type: keyword - -example: 256383 - --- - -*`file.mime_type`*:: -+ --- -MIME type should identify the format of the file or stream of bytes using https://www.iana.org/assignments/media-types/media-types.xhtml[IANA official types], where possible. When more than one type is applicable, the most specific type should be used. - -type: keyword - --- - -*`file.mode`*:: -+ --- -Mode of the file in octal representation. - -type: keyword - -example: 0640 - --- - -*`file.mtime`*:: -+ --- -Last time the file content was modified. - -type: date - --- - -*`file.name`*:: -+ --- -Name of the file including the extension, without the directory. - -type: keyword - -example: example.png - --- - -*`file.owner`*:: -+ --- -File owner's username. - -type: keyword - -example: alice - --- - -*`file.path`*:: -+ --- -Full path to the file, including the file name. It should include the drive letter, when appropriate. - -type: keyword - -example: /home/alice/example.png - --- - -*`file.path.text`*:: -+ --- -type: match_only_text - --- - -*`file.pe.architecture`*:: -+ --- -CPU architecture target for the file. - -type: keyword - -example: x64 - --- - -*`file.pe.company`*:: -+ --- -Internal company name of the file, provided at compile-time. - -type: keyword - -example: Microsoft Corporation - --- - -*`file.pe.description`*:: -+ --- -Internal description of the file, provided at compile-time. - -type: keyword - -example: Paint - --- - -*`file.pe.file_version`*:: -+ --- -Internal version of the file, provided at compile-time. - -type: keyword - -example: 6.3.9600.17415 - --- - -*`file.pe.imphash`*:: -+ --- -A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. -Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html. - -type: keyword - -example: 0c6803c4e922103c4dca5963aad36ddf - --- - -*`file.pe.original_file_name`*:: -+ --- -Internal name of the file, provided at compile-time. - -type: keyword - -example: MSPAINT.EXE - --- - -*`file.pe.product`*:: -+ --- -Internal product name of the file, provided at compile-time. - -type: keyword - -example: Microsoft® Windows® Operating System - --- - -*`file.size`*:: -+ --- -File size in bytes. -Only relevant when `file.type` is "file". - -type: long - -example: 16384 - --- - -*`file.target_path`*:: -+ --- -Target path for symlinks. - -type: keyword - --- - -*`file.target_path.text`*:: -+ --- -type: match_only_text - --- - -*`file.type`*:: -+ --- -File type (file, dir, or symlink). - -type: keyword - -example: file - --- - -*`file.uid`*:: -+ --- -The user ID (UID) or security identifier (SID) of the file owner. - -type: keyword - -example: 1001 - --- - -*`file.x509.alternative_names`*:: -+ --- -List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses. - -type: keyword - -example: *.elastic.co - --- - -*`file.x509.issuer.common_name`*:: -+ --- -List of common name (CN) of issuing certificate authority. - -type: keyword - -example: Example SHA2 High Assurance Server CA - --- - -*`file.x509.issuer.country`*:: -+ --- -List of country (C) codes - -type: keyword - -example: US - --- - -*`file.x509.issuer.distinguished_name`*:: -+ --- -Distinguished name (DN) of issuing certificate authority. - -type: keyword - -example: C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA - --- - -*`file.x509.issuer.locality`*:: -+ --- -List of locality names (L) - -type: keyword - -example: Mountain View - --- - -*`file.x509.issuer.organization`*:: -+ --- -List of organizations (O) of issuing certificate authority. - -type: keyword - -example: Example Inc - --- - -*`file.x509.issuer.organizational_unit`*:: -+ --- -List of organizational units (OU) of issuing certificate authority. - -type: keyword - -example: www.example.com - --- - -*`file.x509.issuer.state_or_province`*:: -+ --- -List of state or province names (ST, S, or P) - -type: keyword - -example: California - --- - -*`file.x509.not_after`*:: -+ --- -Time at which the certificate is no longer considered valid. - -type: date - -example: 2020-07-16 03:15:39+00:00 - --- - -*`file.x509.not_before`*:: -+ --- -Time at which the certificate is first considered valid. - -type: date - -example: 2019-08-16 01:40:25+00:00 - --- - -*`file.x509.public_key_algorithm`*:: -+ --- -Algorithm used to generate the public key. - -type: keyword - -example: RSA - --- - -*`file.x509.public_key_curve`*:: -+ --- -The curve used by the elliptic curve public key algorithm. This is algorithm specific. - -type: keyword - -example: nistp521 - --- - -*`file.x509.public_key_exponent`*:: -+ --- -Exponent used to derive the public key. This is algorithm specific. - -type: long - -example: 65537 - -Field is not indexed. - --- - -*`file.x509.public_key_size`*:: -+ --- -The size of the public key space in bits. - -type: long - -example: 2048 - --- - -*`file.x509.serial_number`*:: -+ --- -Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters. - -type: keyword - -example: 55FBB9C7DEBF09809D12CCAA - --- - -*`file.x509.signature_algorithm`*:: -+ --- -Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353. - -type: keyword - -example: SHA256-RSA - --- - -*`file.x509.subject.common_name`*:: -+ --- -List of common names (CN) of subject. - -type: keyword - -example: shared.global.example.net - --- - -*`file.x509.subject.country`*:: -+ --- -List of country (C) code - -type: keyword - -example: US - --- - -*`file.x509.subject.distinguished_name`*:: -+ --- -Distinguished name (DN) of the certificate subject entity. - -type: keyword - -example: C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net - --- - -*`file.x509.subject.locality`*:: -+ --- -List of locality names (L) - -type: keyword - -example: San Francisco - --- - -*`file.x509.subject.organization`*:: -+ --- -List of organizations (O) of subject. - -type: keyword - -example: Example, Inc. - --- - -*`file.x509.subject.organizational_unit`*:: -+ --- -List of organizational units (OU) of subject. - -type: keyword - --- - -*`file.x509.subject.state_or_province`*:: -+ --- -List of state or province names (ST, S, or P) - -type: keyword - -example: California - --- - -*`file.x509.version_number`*:: -+ --- -Version of x509 format. - -type: keyword - -example: 3 - --- - -[float] -=== geo - -Geo fields can carry data about a specific location related to an event. -This geolocation information can be derived from techniques such as Geo IP, or be user-supplied. - - -*`geo.city_name`*:: -+ --- -City name. - -type: keyword - -example: Montreal - --- - -*`geo.continent_code`*:: -+ --- -Two-letter code representing continent's name. - -type: keyword - -example: NA - --- - -*`geo.continent_name`*:: -+ --- -Name of the continent. - -type: keyword - -example: North America - --- - -*`geo.country_iso_code`*:: -+ --- -Country ISO code. - -type: keyword - -example: CA - --- - -*`geo.country_name`*:: -+ --- -Country name. - -type: keyword - -example: Canada - --- - -*`geo.location`*:: -+ --- -Longitude and latitude. - -type: geo_point - -example: { "lon": -73.614830, "lat": 45.505918 } - --- - -*`geo.name`*:: -+ --- -User-defined description of a location, at the level of granularity they care about. -Could be the name of their data centers, the floor number, if this describes a local physical entity, city names. -Not typically used in automated geolocation. - -type: keyword - -example: boston-dc - --- - -*`geo.postal_code`*:: -+ --- -Postal code associated with the location. -Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country. - -type: keyword - -example: 94040 - --- - -*`geo.region_iso_code`*:: -+ --- -Region ISO code. - -type: keyword - -example: CA-QC - --- - -*`geo.region_name`*:: -+ --- -Region name. - -type: keyword - -example: Quebec - --- - -*`geo.timezone`*:: -+ --- -The time zone of the location, such as IANA time zone name. - -type: keyword - -example: America/Argentina/Buenos_Aires - --- - -[float] -=== group - -The group fields are meant to represent groups that are relevant to the event. - - -*`group.domain`*:: -+ --- -Name of the directory the group is a member of. -For example, an LDAP or Active Directory domain name. - -type: keyword - --- - -*`group.id`*:: -+ --- -Unique identifier for the group on the system/platform. - -type: keyword - --- - -*`group.name`*:: -+ --- -Name of the group. - -type: keyword - --- - -[float] -=== hash - -The hash fields represent different bitwise hash algorithms and their values. -Field names for common hashes (e.g. MD5, SHA1) are predefined. Add fields for other hashes by lowercasing the hash algorithm name and using underscore separators as appropriate (snake case, e.g. sha3_512). -Note that this fieldset is used for common hashes that may be computed over a range of generic bytes. Entity-specific hashes such as ja3 or imphash are placed in the fieldsets to which they relate (tls and pe, respectively). - - -*`hash.md5`*:: -+ --- -MD5 hash. - -type: keyword - --- - -*`hash.sha1`*:: -+ --- -SHA1 hash. - -type: keyword - --- - -*`hash.sha256`*:: -+ --- -SHA256 hash. - -type: keyword - --- - -*`hash.sha512`*:: -+ --- -SHA512 hash. - -type: keyword - --- - -*`hash.ssdeep`*:: -+ --- -SSDEEP hash. - -type: keyword - --- - -[float] -=== host - -A host is defined as a general computing instance. -ECS host.* fields should be populated with details about the host on which the event happened, or from which the measurement was taken. Host types include hardware, virtual machines, Docker containers, and Kubernetes nodes. - - -*`host.architecture`*:: -+ --- -Operating system architecture. - -type: keyword - -example: x86_64 - --- - -*`host.cpu.usage`*:: -+ --- -Percent CPU used which is normalized by the number of CPU cores and it ranges from 0 to 1. -Scaling factor: 1000. -For example: For a two core host, this value should be the average of the two cores, between 0 and 1. - -type: scaled_float - --- - -*`host.disk.read.bytes`*:: -+ --- -The total number of bytes (gauge) read successfully (aggregated from all disks) since the last metric collection. - -type: long - --- - -*`host.disk.write.bytes`*:: -+ --- -The total number of bytes (gauge) written successfully (aggregated from all disks) since the last metric collection. - -type: long - --- - -*`host.domain`*:: -+ --- -Name of the domain of which the host is a member. -For example, on Windows this could be the host's Active Directory domain or NetBIOS domain name. For Linux this could be the domain of the host's LDAP provider. - -type: keyword - -example: CONTOSO - --- - -*`host.geo.city_name`*:: -+ --- -City name. - -type: keyword - -example: Montreal - --- - -*`host.geo.continent_code`*:: -+ --- -Two-letter code representing continent's name. - -type: keyword - -example: NA - --- - -*`host.geo.continent_name`*:: -+ --- -Name of the continent. - -type: keyword - -example: North America - --- - -*`host.geo.country_iso_code`*:: -+ --- -Country ISO code. - -type: keyword - -example: CA - --- - -*`host.geo.country_name`*:: -+ --- -Country name. - -type: keyword - -example: Canada - --- - -*`host.geo.location`*:: -+ --- -Longitude and latitude. - -type: geo_point - -example: { "lon": -73.614830, "lat": 45.505918 } - --- - -*`host.geo.name`*:: -+ --- -User-defined description of a location, at the level of granularity they care about. -Could be the name of their data centers, the floor number, if this describes a local physical entity, city names. -Not typically used in automated geolocation. - -type: keyword - -example: boston-dc - --- - -*`host.geo.postal_code`*:: -+ --- -Postal code associated with the location. -Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country. - -type: keyword - -example: 94040 - --- - -*`host.geo.region_iso_code`*:: -+ --- -Region ISO code. - -type: keyword - -example: CA-QC - --- - -*`host.geo.region_name`*:: -+ --- -Region name. - -type: keyword - -example: Quebec - --- - -*`host.geo.timezone`*:: -+ --- -The time zone of the location, such as IANA time zone name. - -type: keyword - -example: America/Argentina/Buenos_Aires - --- - -*`host.hostname`*:: -+ --- -Hostname of the host. -It normally contains what the `hostname` command returns on the host machine. - -type: keyword - --- - -*`host.id`*:: -+ --- -Unique host id. -As hostname is not always unique, use values that are meaningful in your environment. -Example: The current usage of `beat.name`. - -type: keyword - --- - -*`host.ip`*:: -+ --- -Host ip addresses. - -type: ip - --- - -*`host.mac`*:: -+ --- -Host MAC addresses. -The notation format from RFC 7042 is suggested: Each octet (that is, 8-bit byte) is represented by two [uppercase] hexadecimal digits giving the value of the octet as an unsigned integer. Successive octets are separated by a hyphen. - -type: keyword - -example: ["00-00-5E-00-53-23", "00-00-5E-00-53-24"] - --- - -*`host.name`*:: -+ --- -Name of the host. -It can contain what `hostname` returns on Unix systems, the fully qualified domain name, or a name specified by the user. The sender decides which value to use. - -type: keyword - --- - -*`host.network.egress.bytes`*:: -+ --- -The number of bytes (gauge) sent out on all network interfaces by the host since the last metric collection. - -type: long - --- - -*`host.network.egress.packets`*:: -+ --- -The number of packets (gauge) sent out on all network interfaces by the host since the last metric collection. - -type: long - --- - -*`host.network.ingress.bytes`*:: -+ --- -The number of bytes received (gauge) on all network interfaces by the host since the last metric collection. - -type: long - --- - -*`host.network.ingress.packets`*:: -+ --- -The number of packets (gauge) received on all network interfaces by the host since the last metric collection. - -type: long - --- - -*`host.os.family`*:: -+ --- -OS family (such as redhat, debian, freebsd, windows). - -type: keyword - -example: debian - --- - -*`host.os.full`*:: -+ --- -Operating system name, including the version or code name. - -type: keyword - -example: Mac OS Mojave - --- - -*`host.os.full.text`*:: -+ --- -type: match_only_text - --- - -*`host.os.kernel`*:: -+ --- -Operating system kernel version as a raw string. - -type: keyword - -example: 4.4.0-112-generic - --- - -*`host.os.name`*:: -+ --- -Operating system name, without the version. - -type: keyword - -example: Mac OS X - --- - -*`host.os.name.text`*:: -+ --- -type: match_only_text - --- - -*`host.os.platform`*:: -+ --- -Operating system platform (such centos, ubuntu, windows). - -type: keyword - -example: darwin - --- - -*`host.os.type`*:: -+ --- -Use the `os.type` field to categorize the operating system into one of the broad commercial families. -One of these following values should be used (lowercase): linux, macos, unix, windows. -If the OS you're dealing with is not in the list, the field should not be populated. Please let us know by opening an issue with ECS, to propose its addition. - -type: keyword - -example: macos - --- - -*`host.os.version`*:: -+ --- -Operating system version as a raw string. - -type: keyword - -example: 10.14.1 - --- - -*`host.type`*:: -+ --- -Type of host. -For Cloud providers this can be the machine type like `t2.medium`. If vm, this could be the container, for example, or other information meaningful in your environment. - -type: keyword - --- - -*`host.uptime`*:: -+ --- -Seconds the host has been up. - -type: long - -example: 1325 - --- - -[float] -=== http - -Fields related to HTTP activity. Use the `url` field set to store the url of the request. - - -*`http.request.body.bytes`*:: -+ --- -Size in bytes of the request body. - -type: long - -example: 887 - -format: bytes - --- - -*`http.request.body.content`*:: -+ --- -The full HTTP request body. - -type: wildcard - -example: Hello world - --- - -*`http.request.body.content.text`*:: -+ --- -type: match_only_text - --- - -*`http.request.bytes`*:: -+ --- -Total size in bytes of the request (body and headers). - -type: long - -example: 1437 - -format: bytes - --- - -*`http.request.id`*:: -+ --- -A unique identifier for each HTTP request to correlate logs between clients and servers in transactions. -The id may be contained in a non-standard HTTP header, such as `X-Request-ID` or `X-Correlation-ID`. - -type: keyword - -example: 123e4567-e89b-12d3-a456-426614174000 - --- - -*`http.request.method`*:: -+ --- -HTTP request method. -The value should retain its casing from the original event. For example, `GET`, `get`, and `GeT` are all considered valid values for this field. - -type: keyword - -example: POST - --- - -*`http.request.mime_type`*:: -+ --- -Mime type of the body of the request. -This value must only be populated based on the content of the request body, not on the `Content-Type` header. Comparing the mime type of a request with the request's Content-Type header can be helpful in detecting threats or misconfigured clients. - -type: keyword - -example: image/gif - --- - -*`http.request.referrer`*:: -+ --- -Referrer for this HTTP request. - -type: keyword - -example: https://blog.example.com/ - --- - -*`http.response.body.bytes`*:: -+ --- -Size in bytes of the response body. - -type: long - -example: 887 - -format: bytes - --- - -*`http.response.body.content`*:: -+ --- -The full HTTP response body. - -type: wildcard - -example: Hello world - --- - -*`http.response.body.content.text`*:: -+ --- -type: match_only_text - --- - -*`http.response.bytes`*:: -+ --- -Total size in bytes of the response (body and headers). - -type: long - -example: 1437 - -format: bytes - --- - -*`http.response.mime_type`*:: -+ --- -Mime type of the body of the response. -This value must only be populated based on the content of the response body, not on the `Content-Type` header. Comparing the mime type of a response with the response's Content-Type header can be helpful in detecting misconfigured servers. - -type: keyword - -example: image/gif - --- - -*`http.response.status_code`*:: -+ --- -HTTP response status code. - -type: long - -example: 404 - -format: string - --- - -*`http.version`*:: -+ --- -HTTP version. - -type: keyword - -example: 1.1 - --- - -[float] -=== interface - -The interface fields are used to record ingress and egress interface information when reported by an observer (e.g. firewall, router, load balancer) in the context of the observer handling a network connection. In the case of a single observer interface (e.g. network sensor on a span port) only the observer.ingress information should be populated. - - -*`interface.alias`*:: -+ --- -Interface alias as reported by the system, typically used in firewall implementations for e.g. inside, outside, or dmz logical interface naming. - -type: keyword - -example: outside - --- - -*`interface.id`*:: -+ --- -Interface ID as reported by an observer (typically SNMP interface ID). - -type: keyword - -example: 10 - --- - -*`interface.name`*:: -+ --- -Interface name as reported by the system. - -type: keyword - -example: eth0 - --- - -[float] -=== log - -Details about the event's logging mechanism or logging transport. -The log.* fields are typically populated with details about the logging mechanism used to create and/or transport the event. For example, syslog details belong under `log.syslog.*`. -The details specific to your event source are typically not logged under `log.*`, but rather in `event.*` or in other ECS fields. - - -*`log.file.path`*:: -+ --- -Full path to the log file this event came from, including the file name. It should include the drive letter, when appropriate. -If the event wasn't read from a log file, do not populate this field. - -type: keyword - -example: /var/log/fun-times.log - --- - -*`log.level`*:: -+ --- -Original log level of the log event. -If the source of the event provides a log level or textual severity, this is the one that goes in `log.level`. If your source doesn't specify one, you may put your event transport's severity here (e.g. Syslog severity). -Some examples are `warn`, `err`, `i`, `informational`. - -type: keyword - -example: error - --- - -*`log.logger`*:: -+ --- -The name of the logger inside an application. This is usually the name of the class which initialized the logger, or can be a custom name. - -type: keyword - -example: org.elasticsearch.bootstrap.Bootstrap - --- - -*`log.origin.file.line`*:: -+ --- -The line number of the file containing the source code which originated the log event. - -type: long - -example: 42 - --- - -*`log.origin.file.name`*:: -+ --- -The name of the file containing the source code which originated the log event. -Note that this field is not meant to capture the log file. The correct field to capture the log file is `log.file.path`. - -type: keyword - -example: Bootstrap.java - --- - -*`log.origin.function`*:: -+ --- -The name of the function or method which originated the log event. - -type: keyword - -example: init - --- - -*`log.syslog`*:: -+ --- -The Syslog metadata of the event, if the event was transmitted via Syslog. Please see RFCs 5424 or 3164. - -type: object - --- - -*`log.syslog.facility.code`*:: -+ --- -The Syslog numeric facility of the log event, if available. -According to RFCs 5424 and 3164, this value should be an integer between 0 and 23. - -type: long - -example: 23 - -format: string - --- - -*`log.syslog.facility.name`*:: -+ --- -The Syslog text-based facility of the log event, if available. - -type: keyword - -example: local7 - --- - -*`log.syslog.priority`*:: -+ --- -Syslog numeric priority of the event, if available. -According to RFCs 5424 and 3164, the priority is 8 * facility + severity. This number is therefore expected to contain a value between 0 and 191. - -type: long - -example: 135 - -format: string - --- - -*`log.syslog.severity.code`*:: -+ --- -The Syslog numeric severity of the log event, if available. -If the event source publishing via Syslog provides a different numeric severity value (e.g. firewall, IDS), your source's numeric severity should go to `event.severity`. If the event source does not specify a distinct severity, you can optionally copy the Syslog severity to `event.severity`. - -type: long - -example: 3 - --- - -*`log.syslog.severity.name`*:: -+ --- -The Syslog numeric severity of the log event, if available. -If the event source publishing via Syslog provides a different severity value (e.g. firewall, IDS), your source's text severity should go to `log.level`. If the event source does not specify a distinct severity, you can optionally copy the Syslog severity to `log.level`. - -type: keyword - -example: Error - --- - -[float] -=== network - -The network is defined as the communication path over which a host or network event happens. -The network.* fields should be populated with details about the network activity associated with an event. - - -*`network.application`*:: -+ --- -When a specific application or service is identified from network connection details (source/dest IPs, ports, certificates, or wire format), this field captures the application's or service's name. -For example, the original event identifies the network connection being from a specific web service in a `https` network connection, like `facebook` or `twitter`. -The field value must be normalized to lowercase for querying. - -type: keyword - -example: aim - --- - -*`network.bytes`*:: -+ --- -Total bytes transferred in both directions. -If `source.bytes` and `destination.bytes` are known, `network.bytes` is their sum. - -type: long - -example: 368 - -format: bytes - --- - -*`network.community_id`*:: -+ --- -A hash of source and destination IPs and ports, as well as the protocol used in a communication. This is a tool-agnostic standard to identify flows. -Learn more at https://github.com/corelight/community-id-spec. - -type: keyword - -example: 1:hO+sN4H+MG5MY/8hIrXPqc4ZQz0= - --- - -*`network.direction`*:: -+ --- -Direction of the network traffic. -Recommended values are: - * ingress - * egress - * inbound - * outbound - * internal - * external - * unknown - -When mapping events from a host-based monitoring context, populate this field from the host's point of view, using the values "ingress" or "egress". -When mapping events from a network or perimeter-based monitoring context, populate this field from the point of view of the network perimeter, using the values "inbound", "outbound", "internal" or "external". -Note that "internal" is not crossing perimeter boundaries, and is meant to describe communication between two hosts within the perimeter. Note also that "external" is meant to describe traffic between two hosts that are external to the perimeter. This could for example be useful for ISPs or VPN service providers. - -type: keyword - -example: inbound - --- - -*`network.forwarded_ip`*:: -+ --- -Host IP address when the source IP address is the proxy. - -type: ip - -example: 192.1.1.2 - --- - -*`network.iana_number`*:: -+ --- -IANA Protocol Number (https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml). Standardized list of protocols. This aligns well with NetFlow and sFlow related logs which use the IANA Protocol Number. - -type: keyword - -example: 6 - --- - -*`network.inner`*:: -+ --- -Network.inner fields are added in addition to network.vlan fields to describe the innermost VLAN when q-in-q VLAN tagging is present. Allowed fields include vlan.id and vlan.name. Inner vlan fields are typically used when sending traffic with multiple 802.1q encapsulations to a network sensor (e.g. Zeek, Wireshark.) - -type: object - --- - -*`network.inner.vlan.id`*:: -+ --- -VLAN ID as reported by the observer. - -type: keyword - -example: 10 - --- - -*`network.inner.vlan.name`*:: -+ --- -Optional VLAN name as reported by the observer. - -type: keyword - -example: outside - --- - -*`network.name`*:: -+ --- -Name given by operators to sections of their network. - -type: keyword - -example: Guest Wifi - --- - -*`network.packets`*:: -+ --- -Total packets transferred in both directions. -If `source.packets` and `destination.packets` are known, `network.packets` is their sum. - -type: long - -example: 24 - --- - -*`network.protocol`*:: -+ --- -In the OSI Model this would be the Application Layer protocol. For example, `http`, `dns`, or `ssh`. -The field value must be normalized to lowercase for querying. - -type: keyword - -example: http - --- - -*`network.transport`*:: -+ --- -Same as network.iana_number, but instead using the Keyword name of the transport layer (udp, tcp, ipv6-icmp, etc.) -The field value must be normalized to lowercase for querying. - -type: keyword - -example: tcp - --- - -*`network.type`*:: -+ --- -In the OSI Model this would be the Network Layer. ipv4, ipv6, ipsec, pim, etc -The field value must be normalized to lowercase for querying. - -type: keyword - -example: ipv4 - --- - -*`network.vlan.id`*:: -+ --- -VLAN ID as reported by the observer. - -type: keyword - -example: 10 - --- - -*`network.vlan.name`*:: -+ --- -Optional VLAN name as reported by the observer. - -type: keyword - -example: outside - --- - -[float] -=== observer - -An observer is defined as a special network, security, or application device used to detect, observe, or create network, security, or application-related events and metrics. -This could be a custom hardware appliance or a server that has been configured to run special network, security, or application software. Examples include firewalls, web proxies, intrusion detection/prevention systems, network monitoring sensors, web application firewalls, data loss prevention systems, and APM servers. The observer.* fields shall be populated with details of the system, if any, that detects, observes and/or creates a network, security, or application event or metric. Message queues and ETL components used in processing events or metrics are not considered observers in ECS. - - -*`observer.egress`*:: -+ --- -Observer.egress holds information like interface number and name, vlan, and zone information to classify egress traffic. Single armed monitoring such as a network sensor on a span port should only use observer.ingress to categorize traffic. - -type: object - --- - -*`observer.egress.interface.alias`*:: -+ --- -Interface alias as reported by the system, typically used in firewall implementations for e.g. inside, outside, or dmz logical interface naming. - -type: keyword - -example: outside - --- - -*`observer.egress.interface.id`*:: -+ --- -Interface ID as reported by an observer (typically SNMP interface ID). - -type: keyword - -example: 10 - --- - -*`observer.egress.interface.name`*:: -+ --- -Interface name as reported by the system. - -type: keyword - -example: eth0 - --- - -*`observer.egress.vlan.id`*:: -+ --- -VLAN ID as reported by the observer. - -type: keyword - -example: 10 - --- - -*`observer.egress.vlan.name`*:: -+ --- -Optional VLAN name as reported by the observer. - -type: keyword - -example: outside - --- - -*`observer.egress.zone`*:: -+ --- -Network zone of outbound traffic as reported by the observer to categorize the destination area of egress traffic, e.g. Internal, External, DMZ, HR, Legal, etc. - -type: keyword - -example: Public_Internet - --- - -*`observer.geo.city_name`*:: -+ --- -City name. - -type: keyword - -example: Montreal - --- - -*`observer.geo.continent_code`*:: -+ --- -Two-letter code representing continent's name. - -type: keyword - -example: NA - --- - -*`observer.geo.continent_name`*:: -+ --- -Name of the continent. - -type: keyword - -example: North America - --- - -*`observer.geo.country_iso_code`*:: -+ --- -Country ISO code. - -type: keyword - -example: CA - --- - -*`observer.geo.country_name`*:: -+ --- -Country name. - -type: keyword - -example: Canada - --- - -*`observer.geo.location`*:: -+ --- -Longitude and latitude. - -type: geo_point - -example: { "lon": -73.614830, "lat": 45.505918 } - --- - -*`observer.geo.name`*:: -+ --- -User-defined description of a location, at the level of granularity they care about. -Could be the name of their data centers, the floor number, if this describes a local physical entity, city names. -Not typically used in automated geolocation. - -type: keyword - -example: boston-dc - --- - -*`observer.geo.postal_code`*:: -+ --- -Postal code associated with the location. -Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country. - -type: keyword - -example: 94040 - --- - -*`observer.geo.region_iso_code`*:: -+ --- -Region ISO code. - -type: keyword - -example: CA-QC - --- - -*`observer.geo.region_name`*:: -+ --- -Region name. - -type: keyword - -example: Quebec - --- - -*`observer.geo.timezone`*:: -+ --- -The time zone of the location, such as IANA time zone name. - -type: keyword - -example: America/Argentina/Buenos_Aires - --- - -*`observer.hostname`*:: -+ --- -Hostname of the observer. - -type: keyword - --- - -*`observer.ingress`*:: -+ --- -Observer.ingress holds information like interface number and name, vlan, and zone information to classify ingress traffic. Single armed monitoring such as a network sensor on a span port should only use observer.ingress to categorize traffic. - -type: object - --- - -*`observer.ingress.interface.alias`*:: -+ --- -Interface alias as reported by the system, typically used in firewall implementations for e.g. inside, outside, or dmz logical interface naming. - -type: keyword - -example: outside - --- - -*`observer.ingress.interface.id`*:: -+ --- -Interface ID as reported by an observer (typically SNMP interface ID). - -type: keyword - -example: 10 - --- - -*`observer.ingress.interface.name`*:: -+ --- -Interface name as reported by the system. - -type: keyword - -example: eth0 - --- - -*`observer.ingress.vlan.id`*:: -+ --- -VLAN ID as reported by the observer. - -type: keyword - -example: 10 - --- - -*`observer.ingress.vlan.name`*:: -+ --- -Optional VLAN name as reported by the observer. - -type: keyword - -example: outside - --- - -*`observer.ingress.zone`*:: -+ --- -Network zone of incoming traffic as reported by the observer to categorize the source area of ingress traffic. e.g. internal, External, DMZ, HR, Legal, etc. - -type: keyword - -example: DMZ - --- - -*`observer.ip`*:: -+ --- -IP addresses of the observer. - -type: ip - --- - -*`observer.mac`*:: -+ --- -MAC addresses of the observer. -The notation format from RFC 7042 is suggested: Each octet (that is, 8-bit byte) is represented by two [uppercase] hexadecimal digits giving the value of the octet as an unsigned integer. Successive octets are separated by a hyphen. - -type: keyword - -example: ["00-00-5E-00-53-23", "00-00-5E-00-53-24"] - --- - -*`observer.name`*:: -+ --- -Custom name of the observer. -This is a name that can be given to an observer. This can be helpful for example if multiple firewalls of the same model are used in an organization. -If no custom name is needed, the field can be left empty. - -type: keyword - -example: 1_proxySG - --- - -*`observer.os.family`*:: -+ --- -OS family (such as redhat, debian, freebsd, windows). - -type: keyword - -example: debian - --- - -*`observer.os.full`*:: -+ --- -Operating system name, including the version or code name. - -type: keyword - -example: Mac OS Mojave - --- - -*`observer.os.full.text`*:: -+ --- -type: match_only_text - --- - -*`observer.os.kernel`*:: -+ --- -Operating system kernel version as a raw string. - -type: keyword - -example: 4.4.0-112-generic - --- - -*`observer.os.name`*:: -+ --- -Operating system name, without the version. - -type: keyword - -example: Mac OS X - --- - -*`observer.os.name.text`*:: -+ --- -type: match_only_text - --- - -*`observer.os.platform`*:: -+ --- -Operating system platform (such centos, ubuntu, windows). - -type: keyword - -example: darwin - --- - -*`observer.os.type`*:: -+ --- -Use the `os.type` field to categorize the operating system into one of the broad commercial families. -One of these following values should be used (lowercase): linux, macos, unix, windows. -If the OS you're dealing with is not in the list, the field should not be populated. Please let us know by opening an issue with ECS, to propose its addition. - -type: keyword - -example: macos - --- - -*`observer.os.version`*:: -+ --- -Operating system version as a raw string. - -type: keyword - -example: 10.14.1 - --- - -*`observer.product`*:: -+ --- -The product name of the observer. - -type: keyword - -example: s200 - --- - -*`observer.serial_number`*:: -+ --- -Observer serial number. - -type: keyword - --- - -*`observer.type`*:: -+ --- -The type of the observer the data is coming from. -There is no predefined list of observer types. Some examples are `forwarder`, `firewall`, `ids`, `ips`, `proxy`, `poller`, `sensor`, `APM server`. - -type: keyword - -example: firewall - --- - -*`observer.vendor`*:: -+ --- -Vendor name of the observer. - -type: keyword - -example: Symantec - --- - -*`observer.version`*:: -+ --- -Observer version. - -type: keyword - --- - -[float] -=== orchestrator - -Fields that describe the resources which container orchestrators manage or act upon. - - -*`orchestrator.api_version`*:: -+ --- -API version being used to carry out the action - -type: keyword - -example: v1beta1 - --- - -*`orchestrator.cluster.name`*:: -+ --- -Name of the cluster. - -type: keyword - --- - -*`orchestrator.cluster.url`*:: -+ --- -URL of the API used to manage the cluster. - -type: keyword - --- - -*`orchestrator.cluster.version`*:: -+ --- -The version of the cluster. - -type: keyword - --- - -*`orchestrator.namespace`*:: -+ --- -Namespace in which the action is taking place. - -type: keyword - -example: kube-system - --- - -*`orchestrator.organization`*:: -+ --- -Organization affected by the event (for multi-tenant orchestrator setups). - -type: keyword - -example: elastic - --- - -*`orchestrator.resource.name`*:: -+ --- -Name of the resource being acted upon. - -type: keyword - -example: test-pod-cdcws - --- - -*`orchestrator.resource.type`*:: -+ --- -Type of resource being acted upon. - -type: keyword - -example: service - --- - -*`orchestrator.type`*:: -+ --- -Orchestrator cluster type (e.g. kubernetes, nomad or cloudfoundry). - -type: keyword - -example: kubernetes - --- - -[float] -=== organization - -The organization fields enrich data with information about the company or entity the data is associated with. -These fields help you arrange or filter data stored in an index by one or multiple organizations. - - -*`organization.id`*:: -+ --- -Unique identifier for the organization. - -type: keyword - --- - -*`organization.name`*:: -+ --- -Organization name. - -type: keyword - --- - -*`organization.name.text`*:: -+ --- -type: match_only_text - --- - -[float] -=== os - -The OS fields contain information about the operating system. - - -*`os.family`*:: -+ --- -OS family (such as redhat, debian, freebsd, windows). - -type: keyword - -example: debian - --- - -*`os.full`*:: -+ --- -Operating system name, including the version or code name. - -type: keyword - -example: Mac OS Mojave - --- - -*`os.full.text`*:: -+ --- -type: match_only_text - --- - -*`os.kernel`*:: -+ --- -Operating system kernel version as a raw string. - -type: keyword - -example: 4.4.0-112-generic - --- - -*`os.name`*:: -+ --- -Operating system name, without the version. - -type: keyword - -example: Mac OS X - --- - -*`os.name.text`*:: -+ --- -type: match_only_text - --- - -*`os.platform`*:: -+ --- -Operating system platform (such centos, ubuntu, windows). - -type: keyword - -example: darwin - --- - -*`os.type`*:: -+ --- -Use the `os.type` field to categorize the operating system into one of the broad commercial families. -One of these following values should be used (lowercase): linux, macos, unix, windows. -If the OS you're dealing with is not in the list, the field should not be populated. Please let us know by opening an issue with ECS, to propose its addition. - -type: keyword - -example: macos - --- - -*`os.version`*:: -+ --- -Operating system version as a raw string. - -type: keyword - -example: 10.14.1 - --- - -[float] -=== package - -These fields contain information about an installed software package. It contains general information about a package, such as name, version or size. It also contains installation details, such as time or location. - - -*`package.architecture`*:: -+ --- -Package architecture. - -type: keyword - -example: x86_64 - --- - -*`package.build_version`*:: -+ --- -Additional information about the build version of the installed package. -For example use the commit SHA of a non-released package. - -type: keyword - -example: 36f4f7e89dd61b0988b12ee000b98966867710cd - --- - -*`package.checksum`*:: -+ --- -Checksum of the installed package for verification. - -type: keyword - -example: 68b329da9893e34099c7d8ad5cb9c940 - --- - -*`package.description`*:: -+ --- -Description of the package. - -type: keyword - -example: Open source programming language to build simple/reliable/efficient software. - --- - -*`package.install_scope`*:: -+ --- -Indicating how the package was installed, e.g. user-local, global. - -type: keyword - -example: global - --- - -*`package.installed`*:: -+ --- -Time when package was installed. - -type: date - --- - -*`package.license`*:: -+ --- -License under which the package was released. -Use a short name, e.g. the license identifier from SPDX License List where possible (https://spdx.org/licenses/). - -type: keyword - -example: Apache License 2.0 - --- - -*`package.name`*:: -+ --- -Package name - -type: keyword - -example: go - --- - -*`package.path`*:: -+ --- -Path where the package is installed. - -type: keyword - -example: /usr/local/Cellar/go/1.12.9/ - --- - -*`package.reference`*:: -+ --- -Home page or reference URL of the software in this package, if available. - -type: keyword - -example: https://golang.org - --- - -*`package.size`*:: -+ --- -Package size in bytes. - -type: long - -example: 62231 - -format: string - --- - -*`package.type`*:: -+ --- -Type of package. -This should contain the package file type, rather than the package manager name. Examples: rpm, dpkg, brew, npm, gem, nupkg, jar. - -type: keyword - -example: rpm - --- - -*`package.version`*:: -+ --- -Package version - -type: keyword - -example: 1.12.9 - --- - -[float] -=== pe - -These fields contain Windows Portable Executable (PE) metadata. - - -*`pe.architecture`*:: -+ --- -CPU architecture target for the file. - -type: keyword - -example: x64 - --- - -*`pe.company`*:: -+ --- -Internal company name of the file, provided at compile-time. - -type: keyword - -example: Microsoft Corporation - --- - -*`pe.description`*:: -+ --- -Internal description of the file, provided at compile-time. - -type: keyword - -example: Paint - --- - -*`pe.file_version`*:: -+ --- -Internal version of the file, provided at compile-time. - -type: keyword - -example: 6.3.9600.17415 - --- - -*`pe.imphash`*:: -+ --- -A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. -Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html. - -type: keyword - -example: 0c6803c4e922103c4dca5963aad36ddf - --- - -*`pe.original_file_name`*:: -+ --- -Internal name of the file, provided at compile-time. - -type: keyword - -example: MSPAINT.EXE - --- - -*`pe.product`*:: -+ --- -Internal product name of the file, provided at compile-time. - -type: keyword - -example: Microsoft® Windows® Operating System - --- - -[float] -=== process - -These fields contain information about a process. -These fields can help you correlate metrics information with a process id/name from a log message. The `process.pid` often stays in the metric itself and is copied to the global field for correlation. - - -*`process.args`*:: -+ --- -Array of process arguments, starting with the absolute path to the executable. -May be filtered to protect sensitive information. - -type: keyword - -example: ["/usr/bin/ssh", "-l", "user", "10.0.0.16"] - --- - -*`process.args_count`*:: -+ --- -Length of the process.args array. -This field can be useful for querying or performing bucket analysis on how many arguments were provided to start a process. More arguments may be an indication of suspicious activity. - -type: long - -example: 4 - --- - -*`process.code_signature.digest_algorithm`*:: -+ --- -The hashing algorithm used to sign the process. -This value can distinguish signatures when a file is signed multiple times by the same signer but with a different digest algorithm. - -type: keyword - -example: sha256 - --- - -*`process.code_signature.exists`*:: -+ --- -Boolean to capture if a signature is present. - -type: boolean - -example: true - --- - -*`process.code_signature.signing_id`*:: -+ --- -The identifier used to sign the process. -This is used to identify the application manufactured by a software vendor. The field is relevant to Apple *OS only. - -type: keyword - -example: com.apple.xpc.proxy - --- - -*`process.code_signature.status`*:: -+ --- -Additional information about the certificate status. -This is useful for logging cryptographic errors with the certificate validity or trust status. Leave unpopulated if the validity or trust of the certificate was unchecked. - -type: keyword - -example: ERROR_UNTRUSTED_ROOT - --- - -*`process.code_signature.subject_name`*:: -+ --- -Subject name of the code signer - -type: keyword - -example: Microsoft Corporation - --- - -*`process.code_signature.team_id`*:: -+ --- -The team identifier used to sign the process. -This is used to identify the team or vendor of a software product. The field is relevant to Apple *OS only. - -type: keyword - -example: EQHXZ8M8AV - --- - -*`process.code_signature.timestamp`*:: -+ --- -Date and time when the code signature was generated and signed. - -type: date - -example: 2021-01-01T12:10:30Z - --- - -*`process.code_signature.trusted`*:: -+ --- -Stores the trust status of the certificate chain. -Validating the trust of the certificate chain may be complicated, and this field should only be populated by tools that actively check the status. - -type: boolean - -example: true - --- - -*`process.code_signature.valid`*:: -+ --- -Boolean to capture if the digital signature is verified against the binary content. -Leave unpopulated if a certificate was unchecked. - -type: boolean - -example: true - --- - -*`process.command_line`*:: -+ --- -Full command line that started the process, including the absolute path to the executable, and all arguments. -Some arguments may be filtered to protect sensitive information. - -type: wildcard - -example: /usr/bin/ssh -l user 10.0.0.16 - --- - -*`process.command_line.text`*:: -+ --- -type: match_only_text - --- - -*`process.elf.architecture`*:: -+ --- -Machine architecture of the ELF file. - -type: keyword - -example: x86-64 - --- - -*`process.elf.byte_order`*:: -+ --- -Byte sequence of ELF file. - -type: keyword - -example: Little Endian - --- - -*`process.elf.cpu_type`*:: -+ --- -CPU type of the ELF file. - -type: keyword - -example: Intel - --- - -*`process.elf.creation_date`*:: -+ --- -Extracted when possible from the file's metadata. Indicates when it was built or compiled. It can also be faked by malware creators. - -type: date - --- - -*`process.elf.exports`*:: -+ --- -List of exported element names and types. - -type: flattened - --- - -*`process.elf.header.abi_version`*:: -+ --- -Version of the ELF Application Binary Interface (ABI). - -type: keyword - --- - -*`process.elf.header.class`*:: -+ --- -Header class of the ELF file. - -type: keyword - --- - -*`process.elf.header.data`*:: -+ --- -Data table of the ELF header. - -type: keyword - --- - -*`process.elf.header.entrypoint`*:: -+ --- -Header entrypoint of the ELF file. - -type: long - -format: string - --- - -*`process.elf.header.object_version`*:: -+ --- -"0x1" for original ELF files. - -type: keyword - --- - -*`process.elf.header.os_abi`*:: -+ --- -Application Binary Interface (ABI) of the Linux OS. - -type: keyword - --- - -*`process.elf.header.type`*:: -+ --- -Header type of the ELF file. - -type: keyword - --- - -*`process.elf.header.version`*:: -+ --- -Version of the ELF header. - -type: keyword - --- - -*`process.elf.imports`*:: -+ --- -List of imported element names and types. - -type: flattened - --- - -*`process.elf.sections`*:: -+ --- -An array containing an object for each section of the ELF file. -The keys that should be present in these objects are defined by sub-fields underneath `elf.sections.*`. - -type: nested - --- - -*`process.elf.sections.chi2`*:: -+ --- -Chi-square probability distribution of the section. - -type: long - -format: number - --- - -*`process.elf.sections.entropy`*:: -+ --- -Shannon entropy calculation from the section. - -type: long - -format: number - --- - -*`process.elf.sections.flags`*:: -+ --- -ELF Section List flags. - -type: keyword - --- - -*`process.elf.sections.name`*:: -+ --- -ELF Section List name. - -type: keyword - --- - -*`process.elf.sections.physical_offset`*:: -+ --- -ELF Section List offset. - -type: keyword - --- - -*`process.elf.sections.physical_size`*:: -+ --- -ELF Section List physical size. - -type: long - -format: bytes - --- - -*`process.elf.sections.type`*:: -+ --- -ELF Section List type. - -type: keyword - --- - -*`process.elf.sections.virtual_address`*:: -+ --- -ELF Section List virtual address. - -type: long - -format: string - --- - -*`process.elf.sections.virtual_size`*:: -+ --- -ELF Section List virtual size. - -type: long - -format: string - --- - -*`process.elf.segments`*:: -+ --- -An array containing an object for each segment of the ELF file. -The keys that should be present in these objects are defined by sub-fields underneath `elf.segments.*`. - -type: nested - --- - -*`process.elf.segments.sections`*:: -+ --- -ELF object segment sections. - -type: keyword - --- - -*`process.elf.segments.type`*:: -+ --- -ELF object segment type. - -type: keyword - --- - -*`process.elf.shared_libraries`*:: -+ --- -List of shared libraries used by this ELF object. - -type: keyword - --- - -*`process.elf.telfhash`*:: -+ --- -telfhash symbol hash for ELF file. - -type: keyword - --- - -*`process.end`*:: -+ --- -The time the process ended. - -type: date - -example: 2016-05-23T08:05:34.853Z - --- - -*`process.entity_id`*:: -+ --- -Unique identifier for the process. -The implementation of this is specified by the data source, but some examples of what could be used here are a process-generated UUID, Sysmon Process GUIDs, or a hash of some uniquely identifying components of a process. -Constructing a globally unique identifier is a common practice to mitigate PID reuse as well as to identify a specific process over time, across multiple monitored hosts. - -type: keyword - -example: c2c455d9f99375d - --- - -*`process.executable`*:: -+ --- -Absolute path to the process executable. - -type: keyword - -example: /usr/bin/ssh - --- - -*`process.executable.text`*:: -+ --- -type: match_only_text - --- - -*`process.exit_code`*:: -+ --- -The exit code of the process, if this is a termination event. -The field should be absent if there is no exit code for the event (e.g. process start). - -type: long - -example: 137 - --- - -*`process.hash.md5`*:: -+ --- -MD5 hash. - -type: keyword - --- - -*`process.hash.sha1`*:: -+ --- -SHA1 hash. - -type: keyword - --- - -*`process.hash.sha256`*:: -+ --- -SHA256 hash. - -type: keyword - --- - -*`process.hash.sha512`*:: -+ --- -SHA512 hash. - -type: keyword - --- - -*`process.hash.ssdeep`*:: -+ --- -SSDEEP hash. - -type: keyword - --- - -*`process.name`*:: -+ --- -Process name. -Sometimes called program name or similar. - -type: keyword - -example: ssh - --- - -*`process.name.text`*:: -+ --- -type: match_only_text - --- - -*`process.parent.args`*:: -+ --- -Array of process arguments, starting with the absolute path to the executable. -May be filtered to protect sensitive information. - -type: keyword - -example: ["/usr/bin/ssh", "-l", "user", "10.0.0.16"] - --- - -*`process.parent.args_count`*:: -+ --- -Length of the process.args array. -This field can be useful for querying or performing bucket analysis on how many arguments were provided to start a process. More arguments may be an indication of suspicious activity. - -type: long - -example: 4 - --- - -*`process.parent.code_signature.digest_algorithm`*:: -+ --- -The hashing algorithm used to sign the process. -This value can distinguish signatures when a file is signed multiple times by the same signer but with a different digest algorithm. - -type: keyword - -example: sha256 - --- - -*`process.parent.code_signature.exists`*:: -+ --- -Boolean to capture if a signature is present. - -type: boolean - -example: true - --- - -*`process.parent.code_signature.signing_id`*:: -+ --- -The identifier used to sign the process. -This is used to identify the application manufactured by a software vendor. The field is relevant to Apple *OS only. - -type: keyword - -example: com.apple.xpc.proxy - --- - -*`process.parent.code_signature.status`*:: -+ --- -Additional information about the certificate status. -This is useful for logging cryptographic errors with the certificate validity or trust status. Leave unpopulated if the validity or trust of the certificate was unchecked. - -type: keyword - -example: ERROR_UNTRUSTED_ROOT - --- - -*`process.parent.code_signature.subject_name`*:: -+ --- -Subject name of the code signer - -type: keyword - -example: Microsoft Corporation - --- - -*`process.parent.code_signature.team_id`*:: -+ --- -The team identifier used to sign the process. -This is used to identify the team or vendor of a software product. The field is relevant to Apple *OS only. - -type: keyword - -example: EQHXZ8M8AV - --- - -*`process.parent.code_signature.timestamp`*:: -+ --- -Date and time when the code signature was generated and signed. - -type: date - -example: 2021-01-01T12:10:30Z - --- - -*`process.parent.code_signature.trusted`*:: -+ --- -Stores the trust status of the certificate chain. -Validating the trust of the certificate chain may be complicated, and this field should only be populated by tools that actively check the status. - -type: boolean - -example: true - --- - -*`process.parent.code_signature.valid`*:: -+ --- -Boolean to capture if the digital signature is verified against the binary content. -Leave unpopulated if a certificate was unchecked. - -type: boolean - -example: true - --- - -*`process.parent.command_line`*:: -+ --- -Full command line that started the process, including the absolute path to the executable, and all arguments. -Some arguments may be filtered to protect sensitive information. - -type: wildcard - -example: /usr/bin/ssh -l user 10.0.0.16 - --- - -*`process.parent.command_line.text`*:: -+ --- -type: match_only_text - --- - -*`process.parent.elf.architecture`*:: -+ --- -Machine architecture of the ELF file. - -type: keyword - -example: x86-64 - --- - -*`process.parent.elf.byte_order`*:: -+ --- -Byte sequence of ELF file. - -type: keyword - -example: Little Endian - --- - -*`process.parent.elf.cpu_type`*:: -+ --- -CPU type of the ELF file. - -type: keyword - -example: Intel - --- - -*`process.parent.elf.creation_date`*:: -+ --- -Extracted when possible from the file's metadata. Indicates when it was built or compiled. It can also be faked by malware creators. - -type: date - --- - -*`process.parent.elf.exports`*:: -+ --- -List of exported element names and types. - -type: flattened - --- - -*`process.parent.elf.header.abi_version`*:: -+ --- -Version of the ELF Application Binary Interface (ABI). - -type: keyword - --- - -*`process.parent.elf.header.class`*:: -+ --- -Header class of the ELF file. - -type: keyword - --- - -*`process.parent.elf.header.data`*:: -+ --- -Data table of the ELF header. - -type: keyword - --- - -*`process.parent.elf.header.entrypoint`*:: -+ --- -Header entrypoint of the ELF file. - -type: long - -format: string - --- - -*`process.parent.elf.header.object_version`*:: -+ --- -"0x1" for original ELF files. - -type: keyword - --- - -*`process.parent.elf.header.os_abi`*:: -+ --- -Application Binary Interface (ABI) of the Linux OS. - -type: keyword - --- - -*`process.parent.elf.header.type`*:: -+ --- -Header type of the ELF file. - -type: keyword - --- - -*`process.parent.elf.header.version`*:: -+ --- -Version of the ELF header. - -type: keyword - --- - -*`process.parent.elf.imports`*:: -+ --- -List of imported element names and types. - -type: flattened - --- - -*`process.parent.elf.sections`*:: -+ --- -An array containing an object for each section of the ELF file. -The keys that should be present in these objects are defined by sub-fields underneath `elf.sections.*`. - -type: nested - --- - -*`process.parent.elf.sections.chi2`*:: -+ --- -Chi-square probability distribution of the section. - -type: long - -format: number - --- - -*`process.parent.elf.sections.entropy`*:: -+ --- -Shannon entropy calculation from the section. - -type: long - -format: number - --- - -*`process.parent.elf.sections.flags`*:: -+ --- -ELF Section List flags. - -type: keyword - --- - -*`process.parent.elf.sections.name`*:: -+ --- -ELF Section List name. - -type: keyword - --- - -*`process.parent.elf.sections.physical_offset`*:: -+ --- -ELF Section List offset. - -type: keyword - --- - -*`process.parent.elf.sections.physical_size`*:: -+ --- -ELF Section List physical size. - -type: long - -format: bytes - --- - -*`process.parent.elf.sections.type`*:: -+ --- -ELF Section List type. - -type: keyword - --- - -*`process.parent.elf.sections.virtual_address`*:: -+ --- -ELF Section List virtual address. - -type: long - -format: string - --- - -*`process.parent.elf.sections.virtual_size`*:: -+ --- -ELF Section List virtual size. - -type: long - -format: string - --- - -*`process.parent.elf.segments`*:: -+ --- -An array containing an object for each segment of the ELF file. -The keys that should be present in these objects are defined by sub-fields underneath `elf.segments.*`. - -type: nested - --- - -*`process.parent.elf.segments.sections`*:: -+ --- -ELF object segment sections. - -type: keyword - --- - -*`process.parent.elf.segments.type`*:: -+ --- -ELF object segment type. - -type: keyword - --- - -*`process.parent.elf.shared_libraries`*:: -+ --- -List of shared libraries used by this ELF object. - -type: keyword - --- - -*`process.parent.elf.telfhash`*:: -+ --- -telfhash symbol hash for ELF file. - -type: keyword - --- - -*`process.parent.end`*:: -+ --- -The time the process ended. - -type: date - -example: 2016-05-23T08:05:34.853Z - --- - -*`process.parent.entity_id`*:: -+ --- -Unique identifier for the process. -The implementation of this is specified by the data source, but some examples of what could be used here are a process-generated UUID, Sysmon Process GUIDs, or a hash of some uniquely identifying components of a process. -Constructing a globally unique identifier is a common practice to mitigate PID reuse as well as to identify a specific process over time, across multiple monitored hosts. - -type: keyword - -example: c2c455d9f99375d - --- - -*`process.parent.executable`*:: -+ --- -Absolute path to the process executable. - -type: keyword - -example: /usr/bin/ssh - --- - -*`process.parent.executable.text`*:: -+ --- -type: match_only_text - --- - -*`process.parent.exit_code`*:: -+ --- -The exit code of the process, if this is a termination event. -The field should be absent if there is no exit code for the event (e.g. process start). - -type: long - -example: 137 - --- - -*`process.parent.hash.md5`*:: -+ --- -MD5 hash. - -type: keyword - --- - -*`process.parent.hash.sha1`*:: -+ --- -SHA1 hash. - -type: keyword - --- - -*`process.parent.hash.sha256`*:: -+ --- -SHA256 hash. - -type: keyword - --- - -*`process.parent.hash.sha512`*:: -+ --- -SHA512 hash. - -type: keyword - --- - -*`process.parent.hash.ssdeep`*:: -+ --- -SSDEEP hash. - -type: keyword - --- - -*`process.parent.name`*:: -+ --- -Process name. -Sometimes called program name or similar. - -type: keyword - -example: ssh - --- - -*`process.parent.name.text`*:: -+ --- -type: match_only_text - --- - -*`process.parent.pe.architecture`*:: -+ --- -CPU architecture target for the file. - -type: keyword - -example: x64 - --- - -*`process.parent.pe.company`*:: -+ --- -Internal company name of the file, provided at compile-time. - -type: keyword - -example: Microsoft Corporation - --- - -*`process.parent.pe.description`*:: -+ --- -Internal description of the file, provided at compile-time. - -type: keyword - -example: Paint - --- - -*`process.parent.pe.file_version`*:: -+ --- -Internal version of the file, provided at compile-time. - -type: keyword - -example: 6.3.9600.17415 - --- - -*`process.parent.pe.imphash`*:: -+ --- -A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. -Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html. - -type: keyword - -example: 0c6803c4e922103c4dca5963aad36ddf - --- - -*`process.parent.pe.original_file_name`*:: -+ --- -Internal name of the file, provided at compile-time. - -type: keyword - -example: MSPAINT.EXE - --- - -*`process.parent.pe.product`*:: -+ --- -Internal product name of the file, provided at compile-time. - -type: keyword - -example: Microsoft® Windows® Operating System - --- - -*`process.parent.pgid`*:: -+ --- -Identifier of the group of processes the process belongs to. - -type: long - -format: string - --- - -*`process.parent.pid`*:: -+ --- -Process id. - -type: long - -example: 4242 - -format: string - --- - -*`process.parent.start`*:: -+ --- -The time the process started. - -type: date - -example: 2016-05-23T08:05:34.853Z - --- - -*`process.parent.thread.id`*:: -+ --- -Thread ID. - -type: long - -example: 4242 - -format: string - --- - -*`process.parent.thread.name`*:: -+ --- -Thread name. - -type: keyword - -example: thread-0 - --- - -*`process.parent.title`*:: -+ --- -Process title. -The proctitle, some times the same as process name. Can also be different: for example a browser setting its title to the web page currently opened. - -type: keyword - --- - -*`process.parent.title.text`*:: -+ --- -type: match_only_text - --- - -*`process.parent.uptime`*:: -+ --- -Seconds the process has been up. - -type: long - -example: 1325 - --- - -*`process.parent.working_directory`*:: -+ --- -The working directory of the process. - -type: keyword - -example: /home/alice - --- - -*`process.parent.working_directory.text`*:: -+ --- -type: match_only_text - --- - -*`process.pe.architecture`*:: -+ --- -CPU architecture target for the file. - -type: keyword - -example: x64 - --- - -*`process.pe.company`*:: -+ --- -Internal company name of the file, provided at compile-time. - -type: keyword - -example: Microsoft Corporation - --- - -*`process.pe.description`*:: -+ --- -Internal description of the file, provided at compile-time. - -type: keyword - -example: Paint - --- - -*`process.pe.file_version`*:: -+ --- -Internal version of the file, provided at compile-time. - -type: keyword - -example: 6.3.9600.17415 - --- - -*`process.pe.imphash`*:: -+ --- -A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. -Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html. - -type: keyword - -example: 0c6803c4e922103c4dca5963aad36ddf - --- - -*`process.pe.original_file_name`*:: -+ --- -Internal name of the file, provided at compile-time. - -type: keyword - -example: MSPAINT.EXE - --- - -*`process.pe.product`*:: -+ --- -Internal product name of the file, provided at compile-time. - -type: keyword - -example: Microsoft® Windows® Operating System - --- - -*`process.pgid`*:: -+ --- -Identifier of the group of processes the process belongs to. - -type: long - -format: string - --- - -*`process.pid`*:: -+ --- -Process id. - -type: long - -example: 4242 - -format: string - --- - -*`process.start`*:: -+ --- -The time the process started. - -type: date - -example: 2016-05-23T08:05:34.853Z - --- - -*`process.thread.id`*:: -+ --- -Thread ID. - -type: long - -example: 4242 - -format: string - --- - -*`process.thread.name`*:: -+ --- -Thread name. - -type: keyword - -example: thread-0 - --- - -*`process.title`*:: -+ --- -Process title. -The proctitle, some times the same as process name. Can also be different: for example a browser setting its title to the web page currently opened. - -type: keyword - --- - -*`process.title.text`*:: -+ --- -type: match_only_text - --- - -*`process.uptime`*:: -+ --- -Seconds the process has been up. - -type: long - -example: 1325 - --- - -*`process.working_directory`*:: -+ --- -The working directory of the process. - -type: keyword - -example: /home/alice - --- - -*`process.working_directory.text`*:: -+ --- -type: match_only_text - --- - -[float] -=== registry - -Fields related to Windows Registry operations. - - -*`registry.data.bytes`*:: -+ --- -Original bytes written with base64 encoding. -For Windows registry operations, such as SetValueEx and RegQueryValueEx, this corresponds to the data pointed by `lp_data`. This is optional but provides better recoverability and should be populated for REG_BINARY encoded values. - -type: keyword - -example: ZQBuAC0AVQBTAAAAZQBuAAAAAAA= - --- - -*`registry.data.strings`*:: -+ --- -Content when writing string types. -Populated as an array when writing string data to the registry. For single string registry types (REG_SZ, REG_EXPAND_SZ), this should be an array with one string. For sequences of string with REG_MULTI_SZ, this array will be variable length. For numeric data, such as REG_DWORD and REG_QWORD, this should be populated with the decimal representation (e.g `"1"`). - -type: wildcard - -example: ["C:\rta\red_ttp\bin\myapp.exe"] - --- - -*`registry.data.type`*:: -+ --- -Standard registry type for encoding contents - -type: keyword - -example: REG_SZ - --- - -*`registry.hive`*:: -+ --- -Abbreviated name for the hive. - -type: keyword - -example: HKLM - --- - -*`registry.key`*:: -+ --- -Hive-relative path of keys. - -type: keyword - -example: SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\winword.exe - --- - -*`registry.path`*:: -+ --- -Full path, including hive, key and value - -type: keyword - -example: HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\winword.exe\Debugger - --- - -*`registry.value`*:: -+ --- -Name of the value written. - -type: keyword - -example: Debugger - --- - -[float] -=== related - -This field set is meant to facilitate pivoting around a piece of data. -Some pieces of information can be seen in many places in an ECS event. To facilitate searching for them, store an array of all seen values to their corresponding field in `related.`. -A concrete example is IP addresses, which can be under host, observer, source, destination, client, server, and network.forwarded_ip. If you append all IPs to `related.ip`, you can then search for a given IP trivially, no matter where it appeared, by querying `related.ip:192.0.2.15`. - - -*`related.hash`*:: -+ --- -All the hashes seen on your event. Populating this field, then using it to search for hashes can help in situations where you're unsure what the hash algorithm is (and therefore which key name to search). - -type: keyword - --- - -*`related.hosts`*:: -+ --- -All hostnames or other host identifiers seen on your event. Example identifiers include FQDNs, domain names, workstation names, or aliases. - -type: keyword - --- - -*`related.ip`*:: -+ --- -All of the IPs seen on your event. - -type: ip - --- - -*`related.user`*:: -+ --- -All the user names or other user identifiers seen on the event. - -type: keyword - --- - -[float] -=== rule - -Rule fields are used to capture the specifics of any observer or agent rules that generate alerts or other notable events. -Examples of data sources that would populate the rule fields include: network admission control platforms, network or host IDS/IPS, network firewalls, web application firewalls, url filters, endpoint detection and response (EDR) systems, etc. - - -*`rule.author`*:: -+ --- -Name, organization, or pseudonym of the author or authors who created the rule used to generate this event. - -type: keyword - -example: ["Star-Lord"] - --- - -*`rule.category`*:: -+ --- -A categorization value keyword used by the entity using the rule for detection of this event. - -type: keyword - -example: Attempted Information Leak - --- - -*`rule.description`*:: -+ --- -The description of the rule generating the event. - -type: keyword - -example: Block requests to public DNS over HTTPS / TLS protocols - --- - -*`rule.id`*:: -+ --- -A rule ID that is unique within the scope of an agent, observer, or other entity using the rule for detection of this event. - -type: keyword - -example: 101 - --- - -*`rule.license`*:: -+ --- -Name of the license under which the rule used to generate this event is made available. - -type: keyword - -example: Apache 2.0 - --- - -*`rule.name`*:: -+ --- -The name of the rule or signature generating the event. - -type: keyword - -example: BLOCK_DNS_over_TLS - --- - -*`rule.reference`*:: -+ --- -Reference URL to additional information about the rule used to generate this event. -The URL can point to the vendor's documentation about the rule. If that's not available, it can also be a link to a more general page describing this type of alert. - -type: keyword - -example: https://en.wikipedia.org/wiki/DNS_over_TLS - --- - -*`rule.ruleset`*:: -+ --- -Name of the ruleset, policy, group, or parent category in which the rule used to generate this event is a member. - -type: keyword - -example: Standard_Protocol_Filters - --- - -*`rule.uuid`*:: -+ --- -A rule ID that is unique within the scope of a set or group of agents, observers, or other entities using the rule for detection of this event. - -type: keyword - -example: 1100110011 - --- - -*`rule.version`*:: -+ --- -The version / revision of the rule being used for analysis. - -type: keyword - -example: 1.1 - --- - -[float] -=== server - -A Server is defined as the responder in a network connection for events regarding sessions, connections, or bidirectional flow records. -For TCP events, the server is the receiver of the initial SYN packet(s) of the TCP connection. For other protocols, the server is generally the responder in the network transaction. Some systems actually use the term "responder" to refer the server in TCP connections. The server fields describe details about the system acting as the server in the network event. Server fields are usually populated in conjunction with client fields. Server fields are generally not populated for packet-level events. -Client / server representations can add semantic context to an exchange, which is helpful to visualize the data in certain situations. If your context falls in that category, you should still ensure that source and destination are filled appropriately. - - -*`server.address`*:: -+ --- -Some event server addresses are defined ambiguously. The event will sometimes list an IP, a domain or a unix socket. You should always store the raw address in the `.address` field. -Then it should be duplicated to `.ip` or `.domain`, depending on which one it is. - -type: keyword - --- - -*`server.as.number`*:: -+ --- -Unique number allocated to the autonomous system. The autonomous system number (ASN) uniquely identifies each network on the Internet. - -type: long - -example: 15169 - --- - -*`server.as.organization.name`*:: -+ --- -Organization name. - -type: keyword - -example: Google LLC - --- - -*`server.as.organization.name.text`*:: -+ --- -type: match_only_text - --- - -*`server.bytes`*:: -+ --- -Bytes sent from the server to the client. - -type: long - -example: 184 - -format: bytes - --- - -*`server.domain`*:: -+ --- -The domain name of the server system. -This value may be a host name, a fully qualified domain name, or another host naming format. The value may derive from the original event or be added from enrichment. - -type: keyword - -example: foo.example.com - --- - -*`server.geo.city_name`*:: -+ --- -City name. - -type: keyword - -example: Montreal - --- - -*`server.geo.continent_code`*:: -+ --- -Two-letter code representing continent's name. - -type: keyword - -example: NA - --- - -*`server.geo.continent_name`*:: -+ --- -Name of the continent. - -type: keyword - -example: North America - --- - -*`server.geo.country_iso_code`*:: -+ --- -Country ISO code. - -type: keyword - -example: CA - --- - -*`server.geo.country_name`*:: -+ --- -Country name. - -type: keyword - -example: Canada - --- - -*`server.geo.location`*:: -+ --- -Longitude and latitude. - -type: geo_point - -example: { "lon": -73.614830, "lat": 45.505918 } - --- - -*`server.geo.name`*:: -+ --- -User-defined description of a location, at the level of granularity they care about. -Could be the name of their data centers, the floor number, if this describes a local physical entity, city names. -Not typically used in automated geolocation. - -type: keyword - -example: boston-dc - --- - -*`server.geo.postal_code`*:: -+ --- -Postal code associated with the location. -Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country. - -type: keyword - -example: 94040 - --- - -*`server.geo.region_iso_code`*:: -+ --- -Region ISO code. - -type: keyword - -example: CA-QC - --- - -*`server.geo.region_name`*:: -+ --- -Region name. - -type: keyword - -example: Quebec - --- - -*`server.geo.timezone`*:: -+ --- -The time zone of the location, such as IANA time zone name. - -type: keyword - -example: America/Argentina/Buenos_Aires - --- - -*`server.ip`*:: -+ --- -IP address of the server (IPv4 or IPv6). - -type: ip - --- - -*`server.mac`*:: -+ --- -MAC address of the server. -The notation format from RFC 7042 is suggested: Each octet (that is, 8-bit byte) is represented by two [uppercase] hexadecimal digits giving the value of the octet as an unsigned integer. Successive octets are separated by a hyphen. - -type: keyword - -example: 00-00-5E-00-53-23 - --- - -*`server.nat.ip`*:: -+ --- -Translated ip of destination based NAT sessions (e.g. internet to private DMZ) -Typically used with load balancers, firewalls, or routers. - -type: ip - --- - -*`server.nat.port`*:: -+ --- -Translated port of destination based NAT sessions (e.g. internet to private DMZ) -Typically used with load balancers, firewalls, or routers. - -type: long - -format: string - --- - -*`server.packets`*:: -+ --- -Packets sent from the server to the client. - -type: long - -example: 12 - --- - -*`server.port`*:: -+ --- -Port of the server. - -type: long - -format: string - --- - -*`server.registered_domain`*:: -+ --- -The highest registered server domain, stripped of the subdomain. -For example, the registered domain for "foo.example.com" is "example.com". -This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk". - -type: keyword - -example: example.com - --- - -*`server.subdomain`*:: -+ --- -The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. -For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period. - -type: keyword - -example: east - --- - -*`server.top_level_domain`*:: -+ --- -The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". -This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk". - -type: keyword - -example: co.uk - --- - -*`server.user.domain`*:: -+ --- -Name of the directory the user is a member of. -For example, an LDAP or Active Directory domain name. - -type: keyword - --- - -*`server.user.email`*:: -+ --- -User email address. - -type: keyword - --- - -*`server.user.full_name`*:: -+ --- -User's full name, if available. - -type: keyword - -example: Albert Einstein - --- - -*`server.user.full_name.text`*:: -+ --- -type: match_only_text - --- - -*`server.user.group.domain`*:: -+ --- -Name of the directory the group is a member of. -For example, an LDAP or Active Directory domain name. - -type: keyword - --- - -*`server.user.group.id`*:: -+ --- -Unique identifier for the group on the system/platform. - -type: keyword - --- - -*`server.user.group.name`*:: -+ --- -Name of the group. - -type: keyword - --- - -*`server.user.hash`*:: -+ --- -Unique user hash to correlate information for a user in anonymized form. -Useful if `user.id` or `user.name` contain confidential information and cannot be used. - -type: keyword - --- - -*`server.user.id`*:: -+ --- -Unique identifier of the user. - -type: keyword - -example: S-1-5-21-202424912787-2692429404-2351956786-1000 - --- - -*`server.user.name`*:: -+ --- -Short name or login of the user. - -type: keyword - -example: a.einstein - --- - -*`server.user.name.text`*:: -+ --- -type: match_only_text - --- - -*`server.user.roles`*:: -+ --- -Array of user roles at the time of the event. - -type: keyword - -example: ["kibana_admin", "reporting_user"] - --- - -[float] -=== service - -The service fields describe the service for or from which the data was collected. -These fields help you find and correlate logs for a specific service and version. - - -*`service.address`*:: -+ --- -Address where data about this service was collected from. -This should be a URI, network address (ipv4:port or [ipv6]:port) or a resource path (sockets). - -type: keyword - -example: 172.26.0.2:5432 - --- - -*`service.environment`*:: -+ --- -Identifies the environment where the service is running. -If the same service runs in different environments (production, staging, QA, development, etc.), the environment can identify other instances of the same service. Can also group services and applications from the same environment. - -type: keyword - -example: production - --- - -*`service.ephemeral_id`*:: -+ --- -Ephemeral identifier of this service (if one exists). -This id normally changes across restarts, but `service.id` does not. - -type: keyword - -example: 8a4f500f - --- - -*`service.id`*:: -+ --- -Unique identifier of the running service. If the service is comprised of many nodes, the `service.id` should be the same for all nodes. -This id should uniquely identify the service. This makes it possible to correlate logs and metrics for one specific service, no matter which particular node emitted the event. -Note that if you need to see the events from one specific host of the service, you should filter on that `host.name` or `host.id` instead. - -type: keyword - -example: d37e5ebfe0ae6c4972dbe9f0174a1637bb8247f6 - --- - -*`service.name`*:: -+ --- -Name of the service data is collected from. -The name of the service is normally user given. This allows for distributed services that run on multiple hosts to correlate the related instances based on the name. -In the case of Elasticsearch the `service.name` could contain the cluster name. For Beats the `service.name` is by default a copy of the `service.type` field if no name is specified. - -type: keyword - -example: elasticsearch-metrics - --- - -*`service.node.name`*:: -+ --- -Name of a service node. -This allows for two nodes of the same service running on the same host to be differentiated. Therefore, `service.node.name` should typically be unique across nodes of a given service. -In the case of Elasticsearch, the `service.node.name` could contain the unique node name within the Elasticsearch cluster. In cases where the service doesn't have the concept of a node name, the host name or container name can be used to distinguish running instances that make up this service. If those do not provide uniqueness (e.g. multiple instances of the service running on the same host) - the node name can be manually set. - -type: keyword - -example: instance-0000000016 - --- - -*`service.origin.address`*:: -+ --- -Address where data about this service was collected from. -This should be a URI, network address (ipv4:port or [ipv6]:port) or a resource path (sockets). - -type: keyword - -example: 172.26.0.2:5432 - --- - -*`service.origin.environment`*:: -+ --- -Identifies the environment where the service is running. -If the same service runs in different environments (production, staging, QA, development, etc.), the environment can identify other instances of the same service. Can also group services and applications from the same environment. - -type: keyword - -example: production - --- - -*`service.origin.ephemeral_id`*:: -+ --- -Ephemeral identifier of this service (if one exists). -This id normally changes across restarts, but `service.id` does not. - -type: keyword - -example: 8a4f500f - --- - -*`service.origin.id`*:: -+ --- -Unique identifier of the running service. If the service is comprised of many nodes, the `service.id` should be the same for all nodes. -This id should uniquely identify the service. This makes it possible to correlate logs and metrics for one specific service, no matter which particular node emitted the event. -Note that if you need to see the events from one specific host of the service, you should filter on that `host.name` or `host.id` instead. - -type: keyword - -example: d37e5ebfe0ae6c4972dbe9f0174a1637bb8247f6 - --- - -*`service.origin.name`*:: -+ --- -Name of the service data is collected from. -The name of the service is normally user given. This allows for distributed services that run on multiple hosts to correlate the related instances based on the name. -In the case of Elasticsearch the `service.name` could contain the cluster name. For Beats the `service.name` is by default a copy of the `service.type` field if no name is specified. - -type: keyword - -example: elasticsearch-metrics - --- - -*`service.origin.node.name`*:: -+ --- -Name of a service node. -This allows for two nodes of the same service running on the same host to be differentiated. Therefore, `service.node.name` should typically be unique across nodes of a given service. -In the case of Elasticsearch, the `service.node.name` could contain the unique node name within the Elasticsearch cluster. In cases where the service doesn't have the concept of a node name, the host name or container name can be used to distinguish running instances that make up this service. If those do not provide uniqueness (e.g. multiple instances of the service running on the same host) - the node name can be manually set. - -type: keyword - -example: instance-0000000016 - --- - -*`service.origin.state`*:: -+ --- -Current state of the service. - -type: keyword - --- - -*`service.origin.type`*:: -+ --- -The type of the service data is collected from. -The type can be used to group and correlate logs and metrics from one service type. -Example: If logs or metrics are collected from Elasticsearch, `service.type` would be `elasticsearch`. - -type: keyword - -example: elasticsearch - --- - -*`service.origin.version`*:: -+ --- -Version of the service the data was collected from. -This allows to look at a data set only for a specific version of a service. - -type: keyword - -example: 3.2.4 - --- - -*`service.state`*:: -+ --- -Current state of the service. - -type: keyword - --- - -*`service.target.address`*:: -+ --- -Address where data about this service was collected from. -This should be a URI, network address (ipv4:port or [ipv6]:port) or a resource path (sockets). - -type: keyword - -example: 172.26.0.2:5432 - --- - -*`service.target.environment`*:: -+ --- -Identifies the environment where the service is running. -If the same service runs in different environments (production, staging, QA, development, etc.), the environment can identify other instances of the same service. Can also group services and applications from the same environment. - -type: keyword - -example: production - --- - -*`service.target.ephemeral_id`*:: -+ --- -Ephemeral identifier of this service (if one exists). -This id normally changes across restarts, but `service.id` does not. - -type: keyword - -example: 8a4f500f - --- - -*`service.target.id`*:: -+ --- -Unique identifier of the running service. If the service is comprised of many nodes, the `service.id` should be the same for all nodes. -This id should uniquely identify the service. This makes it possible to correlate logs and metrics for one specific service, no matter which particular node emitted the event. -Note that if you need to see the events from one specific host of the service, you should filter on that `host.name` or `host.id` instead. - -type: keyword - -example: d37e5ebfe0ae6c4972dbe9f0174a1637bb8247f6 - --- - -*`service.target.name`*:: -+ --- -Name of the service data is collected from. -The name of the service is normally user given. This allows for distributed services that run on multiple hosts to correlate the related instances based on the name. -In the case of Elasticsearch the `service.name` could contain the cluster name. For Beats the `service.name` is by default a copy of the `service.type` field if no name is specified. - -type: keyword - -example: elasticsearch-metrics - --- - -*`service.target.node.name`*:: -+ --- -Name of a service node. -This allows for two nodes of the same service running on the same host to be differentiated. Therefore, `service.node.name` should typically be unique across nodes of a given service. -In the case of Elasticsearch, the `service.node.name` could contain the unique node name within the Elasticsearch cluster. In cases where the service doesn't have the concept of a node name, the host name or container name can be used to distinguish running instances that make up this service. If those do not provide uniqueness (e.g. multiple instances of the service running on the same host) - the node name can be manually set. - -type: keyword - -example: instance-0000000016 - --- - -*`service.target.state`*:: -+ --- -Current state of the service. - -type: keyword - --- - -*`service.target.type`*:: -+ --- -The type of the service data is collected from. -The type can be used to group and correlate logs and metrics from one service type. -Example: If logs or metrics are collected from Elasticsearch, `service.type` would be `elasticsearch`. - -type: keyword - -example: elasticsearch - --- - -*`service.target.version`*:: -+ --- -Version of the service the data was collected from. -This allows to look at a data set only for a specific version of a service. - -type: keyword - -example: 3.2.4 - --- - -*`service.type`*:: -+ --- -The type of the service data is collected from. -The type can be used to group and correlate logs and metrics from one service type. -Example: If logs or metrics are collected from Elasticsearch, `service.type` would be `elasticsearch`. - -type: keyword - -example: elasticsearch - --- - -*`service.version`*:: -+ --- -Version of the service the data was collected from. -This allows to look at a data set only for a specific version of a service. - -type: keyword - -example: 3.2.4 - --- - -[float] -=== source - -Source fields capture details about the sender of a network exchange/packet. These fields are populated from a network event, packet, or other event containing details of a network transaction. -Source fields are usually populated in conjunction with destination fields. The source and destination fields are considered the baseline and should always be filled if an event contains source and destination details from a network transaction. If the event also contains identification of the client and server roles, then the client and server fields should also be populated. - - -*`source.address`*:: -+ --- -Some event source addresses are defined ambiguously. The event will sometimes list an IP, a domain or a unix socket. You should always store the raw address in the `.address` field. -Then it should be duplicated to `.ip` or `.domain`, depending on which one it is. - -type: keyword - --- - -*`source.as.number`*:: -+ --- -Unique number allocated to the autonomous system. The autonomous system number (ASN) uniquely identifies each network on the Internet. - -type: long - -example: 15169 - --- - -*`source.as.organization.name`*:: -+ --- -Organization name. - -type: keyword - -example: Google LLC - --- - -*`source.as.organization.name.text`*:: -+ --- -type: match_only_text - --- - -*`source.bytes`*:: -+ --- -Bytes sent from the source to the destination. - -type: long - -example: 184 - -format: bytes - --- - -*`source.domain`*:: -+ --- -The domain name of the source system. -This value may be a host name, a fully qualified domain name, or another host naming format. The value may derive from the original event or be added from enrichment. - -type: keyword - -example: foo.example.com - --- - -*`source.geo.city_name`*:: -+ --- -City name. - -type: keyword - -example: Montreal - --- - -*`source.geo.continent_code`*:: -+ --- -Two-letter code representing continent's name. - -type: keyword - -example: NA - --- - -*`source.geo.continent_name`*:: -+ --- -Name of the continent. - -type: keyword - -example: North America - --- - -*`source.geo.country_iso_code`*:: -+ --- -Country ISO code. - -type: keyword - -example: CA - --- - -*`source.geo.country_name`*:: -+ --- -Country name. - -type: keyword - -example: Canada - --- - -*`source.geo.location`*:: -+ --- -Longitude and latitude. - -type: geo_point - -example: { "lon": -73.614830, "lat": 45.505918 } - --- - -*`source.geo.name`*:: -+ --- -User-defined description of a location, at the level of granularity they care about. -Could be the name of their data centers, the floor number, if this describes a local physical entity, city names. -Not typically used in automated geolocation. - -type: keyword - -example: boston-dc - --- - -*`source.geo.postal_code`*:: -+ --- -Postal code associated with the location. -Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country. - -type: keyword - -example: 94040 - --- - -*`source.geo.region_iso_code`*:: -+ --- -Region ISO code. - -type: keyword - -example: CA-QC - --- - -*`source.geo.region_name`*:: -+ --- -Region name. - -type: keyword - -example: Quebec - --- - -*`source.geo.timezone`*:: -+ --- -The time zone of the location, such as IANA time zone name. - -type: keyword - -example: America/Argentina/Buenos_Aires - --- - -*`source.ip`*:: -+ --- -IP address of the source (IPv4 or IPv6). - -type: ip - --- - -*`source.mac`*:: -+ --- -MAC address of the source. -The notation format from RFC 7042 is suggested: Each octet (that is, 8-bit byte) is represented by two [uppercase] hexadecimal digits giving the value of the octet as an unsigned integer. Successive octets are separated by a hyphen. - -type: keyword - -example: 00-00-5E-00-53-23 - --- - -*`source.nat.ip`*:: -+ --- -Translated ip of source based NAT sessions (e.g. internal client to internet) -Typically connections traversing load balancers, firewalls, or routers. - -type: ip - --- - -*`source.nat.port`*:: -+ --- -Translated port of source based NAT sessions. (e.g. internal client to internet) -Typically used with load balancers, firewalls, or routers. - -type: long - -format: string - --- - -*`source.packets`*:: -+ --- -Packets sent from the source to the destination. - -type: long - -example: 12 - --- - -*`source.port`*:: -+ --- -Port of the source. - -type: long - -format: string - --- - -*`source.registered_domain`*:: -+ --- -The highest registered source domain, stripped of the subdomain. -For example, the registered domain for "foo.example.com" is "example.com". -This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk". - -type: keyword - -example: example.com - --- - -*`source.subdomain`*:: -+ --- -The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. -For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period. - -type: keyword - -example: east - --- - -*`source.top_level_domain`*:: -+ --- -The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". -This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk". - -type: keyword - -example: co.uk - --- - -*`source.user.domain`*:: -+ --- -Name of the directory the user is a member of. -For example, an LDAP or Active Directory domain name. - -type: keyword - --- - -*`source.user.email`*:: -+ --- -User email address. - -type: keyword - --- - -*`source.user.full_name`*:: -+ --- -User's full name, if available. - -type: keyword - -example: Albert Einstein - --- - -*`source.user.full_name.text`*:: -+ --- -type: match_only_text - --- - -*`source.user.group.domain`*:: -+ --- -Name of the directory the group is a member of. -For example, an LDAP or Active Directory domain name. - -type: keyword - --- - -*`source.user.group.id`*:: -+ --- -Unique identifier for the group on the system/platform. - -type: keyword - --- - -*`source.user.group.name`*:: -+ --- -Name of the group. - -type: keyword - --- - -*`source.user.hash`*:: -+ --- -Unique user hash to correlate information for a user in anonymized form. -Useful if `user.id` or `user.name` contain confidential information and cannot be used. - -type: keyword - --- - -*`source.user.id`*:: -+ --- -Unique identifier of the user. - -type: keyword - -example: S-1-5-21-202424912787-2692429404-2351956786-1000 - --- - -*`source.user.name`*:: -+ --- -Short name or login of the user. - -type: keyword - -example: a.einstein - --- - -*`source.user.name.text`*:: -+ --- -type: match_only_text - --- - -*`source.user.roles`*:: -+ --- -Array of user roles at the time of the event. - -type: keyword - -example: ["kibana_admin", "reporting_user"] - --- - -[float] -=== threat - -Fields to classify events and alerts according to a threat taxonomy such as the MITRE ATT&CK® framework. -These fields are for users to classify alerts from all of their sources (e.g. IDS, NGFW, etc.) within a common taxonomy. The threat.tactic.* fields are meant to capture the high level category of the threat (e.g. "impact"). The threat.technique.* fields are meant to capture which kind of approach is used by this detected threat, to accomplish the goal (e.g. "endpoint denial of service"). - - -*`threat.enrichments`*:: -+ --- -A list of associated indicators objects enriching the event, and the context of that association/enrichment. - -type: nested - --- - -*`threat.enrichments.indicator`*:: -+ --- -Object containing associated indicators enriching the event. - -type: object - --- - -*`threat.enrichments.indicator.as.number`*:: -+ --- -Unique number allocated to the autonomous system. The autonomous system number (ASN) uniquely identifies each network on the Internet. - -type: long - -example: 15169 - --- - -*`threat.enrichments.indicator.as.organization.name`*:: -+ --- -Organization name. - -type: keyword - -example: Google LLC - --- - -*`threat.enrichments.indicator.as.organization.name.text`*:: -+ --- -type: match_only_text - --- - -*`threat.enrichments.indicator.confidence`*:: -+ --- -Identifies the vendor-neutral confidence rating using the None/Low/Medium/High scale defined in Appendix A of the STIX 2.1 framework. Vendor-specific confidence scales may be added as custom fields. -Expected values are: - * Not Specified - * None - * Low - * Medium - * High - -type: keyword - -example: Medium - --- - -*`threat.enrichments.indicator.description`*:: -+ --- -Describes the type of action conducted by the threat. - -type: keyword - -example: IP x.x.x.x was observed delivering the Angler EK. - --- - -*`threat.enrichments.indicator.email.address`*:: -+ --- -Identifies a threat indicator as an email address (irrespective of direction). - -type: keyword - -example: phish@example.com - --- - -*`threat.enrichments.indicator.file.accessed`*:: -+ --- -Last time the file was accessed. -Note that not all filesystems keep track of access time. - -type: date - --- - -*`threat.enrichments.indicator.file.attributes`*:: -+ --- -Array of file attributes. -Attributes names will vary by platform. Here's a non-exhaustive list of values that are expected in this field: archive, compressed, directory, encrypted, execute, hidden, read, readonly, system, write. - -type: keyword - -example: ["readonly", "system"] - --- - -*`threat.enrichments.indicator.file.code_signature.digest_algorithm`*:: -+ --- -The hashing algorithm used to sign the process. -This value can distinguish signatures when a file is signed multiple times by the same signer but with a different digest algorithm. - -type: keyword - -example: sha256 - --- - -*`threat.enrichments.indicator.file.code_signature.exists`*:: -+ --- -Boolean to capture if a signature is present. - -type: boolean - -example: true - --- - -*`threat.enrichments.indicator.file.code_signature.signing_id`*:: -+ --- -The identifier used to sign the process. -This is used to identify the application manufactured by a software vendor. The field is relevant to Apple *OS only. - -type: keyword - -example: com.apple.xpc.proxy - --- - -*`threat.enrichments.indicator.file.code_signature.status`*:: -+ --- -Additional information about the certificate status. -This is useful for logging cryptographic errors with the certificate validity or trust status. Leave unpopulated if the validity or trust of the certificate was unchecked. - -type: keyword - -example: ERROR_UNTRUSTED_ROOT - --- - -*`threat.enrichments.indicator.file.code_signature.subject_name`*:: -+ --- -Subject name of the code signer - -type: keyword - -example: Microsoft Corporation - --- - -*`threat.enrichments.indicator.file.code_signature.team_id`*:: -+ --- -The team identifier used to sign the process. -This is used to identify the team or vendor of a software product. The field is relevant to Apple *OS only. - -type: keyword - -example: EQHXZ8M8AV - --- - -*`threat.enrichments.indicator.file.code_signature.timestamp`*:: -+ --- -Date and time when the code signature was generated and signed. - -type: date - -example: 2021-01-01T12:10:30Z - --- - -*`threat.enrichments.indicator.file.code_signature.trusted`*:: -+ --- -Stores the trust status of the certificate chain. -Validating the trust of the certificate chain may be complicated, and this field should only be populated by tools that actively check the status. - -type: boolean - -example: true - --- - -*`threat.enrichments.indicator.file.code_signature.valid`*:: -+ --- -Boolean to capture if the digital signature is verified against the binary content. -Leave unpopulated if a certificate was unchecked. - -type: boolean - -example: true - --- - -*`threat.enrichments.indicator.file.created`*:: -+ --- -File creation time. -Note that not all filesystems store the creation time. - -type: date - --- - -*`threat.enrichments.indicator.file.ctime`*:: -+ --- -Last time the file attributes or metadata changed. -Note that changes to the file content will update `mtime`. This implies `ctime` will be adjusted at the same time, since `mtime` is an attribute of the file. - -type: date - --- - -*`threat.enrichments.indicator.file.device`*:: -+ --- -Device that is the source of the file. - -type: keyword - -example: sda - --- - -*`threat.enrichments.indicator.file.directory`*:: -+ --- -Directory where the file is located. It should include the drive letter, when appropriate. - -type: keyword - -example: /home/alice - --- - -*`threat.enrichments.indicator.file.drive_letter`*:: -+ --- -Drive letter where the file is located. This field is only relevant on Windows. -The value should be uppercase, and not include the colon. - -type: keyword - -example: C - --- - -*`threat.enrichments.indicator.file.elf.architecture`*:: -+ --- -Machine architecture of the ELF file. - -type: keyword - -example: x86-64 - --- - -*`threat.enrichments.indicator.file.elf.byte_order`*:: -+ --- -Byte sequence of ELF file. - -type: keyword - -example: Little Endian - --- - -*`threat.enrichments.indicator.file.elf.cpu_type`*:: -+ --- -CPU type of the ELF file. - -type: keyword - -example: Intel - --- - -*`threat.enrichments.indicator.file.elf.creation_date`*:: -+ --- -Extracted when possible from the file's metadata. Indicates when it was built or compiled. It can also be faked by malware creators. - -type: date - --- - -*`threat.enrichments.indicator.file.elf.exports`*:: -+ --- -List of exported element names and types. - -type: flattened - --- - -*`threat.enrichments.indicator.file.elf.header.abi_version`*:: -+ --- -Version of the ELF Application Binary Interface (ABI). - -type: keyword - --- - -*`threat.enrichments.indicator.file.elf.header.class`*:: -+ --- -Header class of the ELF file. - -type: keyword - --- - -*`threat.enrichments.indicator.file.elf.header.data`*:: -+ --- -Data table of the ELF header. - -type: keyword - --- - -*`threat.enrichments.indicator.file.elf.header.entrypoint`*:: -+ --- -Header entrypoint of the ELF file. - -type: long - -format: string - --- - -*`threat.enrichments.indicator.file.elf.header.object_version`*:: -+ --- -"0x1" for original ELF files. - -type: keyword - --- - -*`threat.enrichments.indicator.file.elf.header.os_abi`*:: -+ --- -Application Binary Interface (ABI) of the Linux OS. - -type: keyword - --- - -*`threat.enrichments.indicator.file.elf.header.type`*:: -+ --- -Header type of the ELF file. - -type: keyword - --- - -*`threat.enrichments.indicator.file.elf.header.version`*:: -+ --- -Version of the ELF header. - -type: keyword - --- - -*`threat.enrichments.indicator.file.elf.imports`*:: -+ --- -List of imported element names and types. - -type: flattened - --- - -*`threat.enrichments.indicator.file.elf.sections`*:: -+ --- -An array containing an object for each section of the ELF file. -The keys that should be present in these objects are defined by sub-fields underneath `elf.sections.*`. - -type: nested - --- - -*`threat.enrichments.indicator.file.elf.sections.chi2`*:: -+ --- -Chi-square probability distribution of the section. - -type: long - -format: number - --- - -*`threat.enrichments.indicator.file.elf.sections.entropy`*:: -+ --- -Shannon entropy calculation from the section. - -type: long - -format: number - --- - -*`threat.enrichments.indicator.file.elf.sections.flags`*:: -+ --- -ELF Section List flags. - -type: keyword - --- - -*`threat.enrichments.indicator.file.elf.sections.name`*:: -+ --- -ELF Section List name. - -type: keyword - --- - -*`threat.enrichments.indicator.file.elf.sections.physical_offset`*:: -+ --- -ELF Section List offset. - -type: keyword - --- - -*`threat.enrichments.indicator.file.elf.sections.physical_size`*:: -+ --- -ELF Section List physical size. - -type: long - -format: bytes - --- - -*`threat.enrichments.indicator.file.elf.sections.type`*:: -+ --- -ELF Section List type. - -type: keyword - --- - -*`threat.enrichments.indicator.file.elf.sections.virtual_address`*:: -+ --- -ELF Section List virtual address. - -type: long - -format: string - --- - -*`threat.enrichments.indicator.file.elf.sections.virtual_size`*:: -+ --- -ELF Section List virtual size. - -type: long - -format: string - --- - -*`threat.enrichments.indicator.file.elf.segments`*:: -+ --- -An array containing an object for each segment of the ELF file. -The keys that should be present in these objects are defined by sub-fields underneath `elf.segments.*`. - -type: nested - --- - -*`threat.enrichments.indicator.file.elf.segments.sections`*:: -+ --- -ELF object segment sections. - -type: keyword - --- - -*`threat.enrichments.indicator.file.elf.segments.type`*:: -+ --- -ELF object segment type. - -type: keyword - --- - -*`threat.enrichments.indicator.file.elf.shared_libraries`*:: -+ --- -List of shared libraries used by this ELF object. - -type: keyword - --- - -*`threat.enrichments.indicator.file.elf.telfhash`*:: -+ --- -telfhash symbol hash for ELF file. - -type: keyword - --- - -*`threat.enrichments.indicator.file.extension`*:: -+ --- -File extension, excluding the leading dot. -Note that when the file name has multiple extensions (example.tar.gz), only the last one should be captured ("gz", not "tar.gz"). - -type: keyword - -example: png - --- - -*`threat.enrichments.indicator.file.fork_name`*:: -+ --- -A fork is additional data associated with a filesystem object. -On Linux, a resource fork is used to store additional data with a filesystem object. A file always has at least one fork for the data portion, and additional forks may exist. -On NTFS, this is analogous to an Alternate Data Stream (ADS), and the default data stream for a file is just called $DATA. Zone.Identifier is commonly used by Windows to track contents downloaded from the Internet. An ADS is typically of the form: `C:\path\to\filename.extension:some_fork_name`, and `some_fork_name` is the value that should populate `fork_name`. `filename.extension` should populate `file.name`, and `extension` should populate `file.extension`. The full path, `file.path`, will include the fork name. - -type: keyword - -example: Zone.Identifer - --- - -*`threat.enrichments.indicator.file.gid`*:: -+ --- -Primary group ID (GID) of the file. - -type: keyword - -example: 1001 - --- - -*`threat.enrichments.indicator.file.group`*:: -+ --- -Primary group name of the file. - -type: keyword - -example: alice - --- - -*`threat.enrichments.indicator.file.hash.md5`*:: -+ --- -MD5 hash. - -type: keyword - --- - -*`threat.enrichments.indicator.file.hash.sha1`*:: -+ --- -SHA1 hash. - -type: keyword - --- - -*`threat.enrichments.indicator.file.hash.sha256`*:: -+ --- -SHA256 hash. - -type: keyword - --- - -*`threat.enrichments.indicator.file.hash.sha512`*:: -+ --- -SHA512 hash. - -type: keyword - --- - -*`threat.enrichments.indicator.file.hash.ssdeep`*:: -+ --- -SSDEEP hash. - -type: keyword - --- - -*`threat.enrichments.indicator.file.inode`*:: -+ --- -Inode representing the file in the filesystem. - -type: keyword - -example: 256383 - --- - -*`threat.enrichments.indicator.file.mime_type`*:: -+ --- -MIME type should identify the format of the file or stream of bytes using https://www.iana.org/assignments/media-types/media-types.xhtml[IANA official types], where possible. When more than one type is applicable, the most specific type should be used. - -type: keyword - --- - -*`threat.enrichments.indicator.file.mode`*:: -+ --- -Mode of the file in octal representation. - -type: keyword - -example: 0640 - --- - -*`threat.enrichments.indicator.file.mtime`*:: -+ --- -Last time the file content was modified. - -type: date - --- - -*`threat.enrichments.indicator.file.name`*:: -+ --- -Name of the file including the extension, without the directory. - -type: keyword - -example: example.png - --- - -*`threat.enrichments.indicator.file.owner`*:: -+ --- -File owner's username. - -type: keyword - -example: alice - --- - -*`threat.enrichments.indicator.file.path`*:: -+ --- -Full path to the file, including the file name. It should include the drive letter, when appropriate. - -type: keyword - -example: /home/alice/example.png - --- - -*`threat.enrichments.indicator.file.path.text`*:: -+ --- -type: match_only_text - --- - -*`threat.enrichments.indicator.file.pe.architecture`*:: -+ --- -CPU architecture target for the file. - -type: keyword - -example: x64 - --- - -*`threat.enrichments.indicator.file.pe.company`*:: -+ --- -Internal company name of the file, provided at compile-time. - -type: keyword - -example: Microsoft Corporation - --- - -*`threat.enrichments.indicator.file.pe.description`*:: -+ --- -Internal description of the file, provided at compile-time. - -type: keyword - -example: Paint - --- - -*`threat.enrichments.indicator.file.pe.file_version`*:: -+ --- -Internal version of the file, provided at compile-time. - -type: keyword - -example: 6.3.9600.17415 - --- - -*`threat.enrichments.indicator.file.pe.imphash`*:: -+ --- -A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. -Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html. - -type: keyword - -example: 0c6803c4e922103c4dca5963aad36ddf - --- - -*`threat.enrichments.indicator.file.pe.original_file_name`*:: -+ --- -Internal name of the file, provided at compile-time. - -type: keyword - -example: MSPAINT.EXE - --- - -*`threat.enrichments.indicator.file.pe.product`*:: -+ --- -Internal product name of the file, provided at compile-time. - -type: keyword - -example: Microsoft® Windows® Operating System - --- - -*`threat.enrichments.indicator.file.size`*:: -+ --- -File size in bytes. -Only relevant when `file.type` is "file". - -type: long - -example: 16384 - --- - -*`threat.enrichments.indicator.file.target_path`*:: -+ --- -Target path for symlinks. - -type: keyword - --- - -*`threat.enrichments.indicator.file.target_path.text`*:: -+ --- -type: match_only_text - --- - -*`threat.enrichments.indicator.file.type`*:: -+ --- -File type (file, dir, or symlink). - -type: keyword - -example: file - --- - -*`threat.enrichments.indicator.file.uid`*:: -+ --- -The user ID (UID) or security identifier (SID) of the file owner. - -type: keyword - -example: 1001 - --- - -*`threat.enrichments.indicator.file.x509.alternative_names`*:: -+ --- -List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses. - -type: keyword - -example: *.elastic.co - --- - -*`threat.enrichments.indicator.file.x509.issuer.common_name`*:: -+ --- -List of common name (CN) of issuing certificate authority. - -type: keyword - -example: Example SHA2 High Assurance Server CA - --- - -*`threat.enrichments.indicator.file.x509.issuer.country`*:: -+ --- -List of country (C) codes - -type: keyword - -example: US - --- - -*`threat.enrichments.indicator.file.x509.issuer.distinguished_name`*:: -+ --- -Distinguished name (DN) of issuing certificate authority. - -type: keyword - -example: C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA - --- - -*`threat.enrichments.indicator.file.x509.issuer.locality`*:: -+ --- -List of locality names (L) - -type: keyword - -example: Mountain View - --- - -*`threat.enrichments.indicator.file.x509.issuer.organization`*:: -+ --- -List of organizations (O) of issuing certificate authority. - -type: keyword - -example: Example Inc - --- - -*`threat.enrichments.indicator.file.x509.issuer.organizational_unit`*:: -+ --- -List of organizational units (OU) of issuing certificate authority. - -type: keyword - -example: www.example.com - --- - -*`threat.enrichments.indicator.file.x509.issuer.state_or_province`*:: -+ --- -List of state or province names (ST, S, or P) - -type: keyword - -example: California - --- - -*`threat.enrichments.indicator.file.x509.not_after`*:: -+ --- -Time at which the certificate is no longer considered valid. - -type: date - -example: 2020-07-16 03:15:39+00:00 - --- - -*`threat.enrichments.indicator.file.x509.not_before`*:: -+ --- -Time at which the certificate is first considered valid. - -type: date - -example: 2019-08-16 01:40:25+00:00 - --- - -*`threat.enrichments.indicator.file.x509.public_key_algorithm`*:: -+ --- -Algorithm used to generate the public key. - -type: keyword - -example: RSA - --- - -*`threat.enrichments.indicator.file.x509.public_key_curve`*:: -+ --- -The curve used by the elliptic curve public key algorithm. This is algorithm specific. - -type: keyword - -example: nistp521 - --- - -*`threat.enrichments.indicator.file.x509.public_key_exponent`*:: -+ --- -Exponent used to derive the public key. This is algorithm specific. - -type: long - -example: 65537 - -Field is not indexed. - --- - -*`threat.enrichments.indicator.file.x509.public_key_size`*:: -+ --- -The size of the public key space in bits. - -type: long - -example: 2048 - --- - -*`threat.enrichments.indicator.file.x509.serial_number`*:: -+ --- -Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters. - -type: keyword - -example: 55FBB9C7DEBF09809D12CCAA - --- - -*`threat.enrichments.indicator.file.x509.signature_algorithm`*:: -+ --- -Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353. - -type: keyword - -example: SHA256-RSA - --- - -*`threat.enrichments.indicator.file.x509.subject.common_name`*:: -+ --- -List of common names (CN) of subject. - -type: keyword - -example: shared.global.example.net - --- - -*`threat.enrichments.indicator.file.x509.subject.country`*:: -+ --- -List of country (C) code - -type: keyword - -example: US - --- - -*`threat.enrichments.indicator.file.x509.subject.distinguished_name`*:: -+ --- -Distinguished name (DN) of the certificate subject entity. - -type: keyword - -example: C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net - --- - -*`threat.enrichments.indicator.file.x509.subject.locality`*:: -+ --- -List of locality names (L) - -type: keyword - -example: San Francisco - --- - -*`threat.enrichments.indicator.file.x509.subject.organization`*:: -+ --- -List of organizations (O) of subject. - -type: keyword - -example: Example, Inc. - --- - -*`threat.enrichments.indicator.file.x509.subject.organizational_unit`*:: -+ --- -List of organizational units (OU) of subject. - -type: keyword - --- - -*`threat.enrichments.indicator.file.x509.subject.state_or_province`*:: -+ --- -List of state or province names (ST, S, or P) - -type: keyword - -example: California - --- - -*`threat.enrichments.indicator.file.x509.version_number`*:: -+ --- -Version of x509 format. - -type: keyword - -example: 3 - --- - -*`threat.enrichments.indicator.first_seen`*:: -+ --- -The date and time when intelligence source first reported sighting this indicator. - -type: date - -example: 2020-11-05T17:25:47.000Z - --- - -*`threat.enrichments.indicator.geo.city_name`*:: -+ --- -City name. - -type: keyword - -example: Montreal - --- - -*`threat.enrichments.indicator.geo.continent_code`*:: -+ --- -Two-letter code representing continent's name. - -type: keyword - -example: NA - --- - -*`threat.enrichments.indicator.geo.continent_name`*:: -+ --- -Name of the continent. - -type: keyword - -example: North America - --- - -*`threat.enrichments.indicator.geo.country_iso_code`*:: -+ --- -Country ISO code. - -type: keyword - -example: CA - --- - -*`threat.enrichments.indicator.geo.country_name`*:: -+ --- -Country name. - -type: keyword - -example: Canada - --- - -*`threat.enrichments.indicator.geo.location`*:: -+ --- -Longitude and latitude. - -type: geo_point - -example: { "lon": -73.614830, "lat": 45.505918 } - --- - -*`threat.enrichments.indicator.geo.name`*:: -+ --- -User-defined description of a location, at the level of granularity they care about. -Could be the name of their data centers, the floor number, if this describes a local physical entity, city names. -Not typically used in automated geolocation. - -type: keyword - -example: boston-dc - --- - -*`threat.enrichments.indicator.geo.postal_code`*:: -+ --- -Postal code associated with the location. -Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country. - -type: keyword - -example: 94040 - --- - -*`threat.enrichments.indicator.geo.region_iso_code`*:: -+ --- -Region ISO code. - -type: keyword - -example: CA-QC - --- - -*`threat.enrichments.indicator.geo.region_name`*:: -+ --- -Region name. - -type: keyword - -example: Quebec - --- - -*`threat.enrichments.indicator.geo.timezone`*:: -+ --- -The time zone of the location, such as IANA time zone name. - -type: keyword - -example: America/Argentina/Buenos_Aires - --- - -*`threat.enrichments.indicator.ip`*:: -+ --- -Identifies a threat indicator as an IP address (irrespective of direction). - -type: ip - -example: 1.2.3.4 - --- - -*`threat.enrichments.indicator.last_seen`*:: -+ --- -The date and time when intelligence source last reported sighting this indicator. - -type: date - -example: 2020-11-05T17:25:47.000Z - --- - -*`threat.enrichments.indicator.marking.tlp`*:: -+ --- -Traffic Light Protocol sharing markings. Recommended values are: - * WHITE - * GREEN - * AMBER - * RED - -type: keyword - -example: White - --- - -*`threat.enrichments.indicator.modified_at`*:: -+ --- -The date and time when intelligence source last modified information for this indicator. - -type: date - -example: 2020-11-05T17:25:47.000Z - --- - -*`threat.enrichments.indicator.port`*:: -+ --- -Identifies a threat indicator as a port number (irrespective of direction). - -type: long - -example: 443 - --- - -*`threat.enrichments.indicator.provider`*:: -+ --- -The name of the indicator's provider. - -type: keyword - -example: lrz_urlhaus - --- - -*`threat.enrichments.indicator.reference`*:: -+ --- -Reference URL linking to additional information about this indicator. - -type: keyword - -example: https://system.example.com/indicator/0001234 - --- - -*`threat.enrichments.indicator.registry.data.bytes`*:: -+ --- -Original bytes written with base64 encoding. -For Windows registry operations, such as SetValueEx and RegQueryValueEx, this corresponds to the data pointed by `lp_data`. This is optional but provides better recoverability and should be populated for REG_BINARY encoded values. - -type: keyword - -example: ZQBuAC0AVQBTAAAAZQBuAAAAAAA= - --- - -*`threat.enrichments.indicator.registry.data.strings`*:: -+ --- -Content when writing string types. -Populated as an array when writing string data to the registry. For single string registry types (REG_SZ, REG_EXPAND_SZ), this should be an array with one string. For sequences of string with REG_MULTI_SZ, this array will be variable length. For numeric data, such as REG_DWORD and REG_QWORD, this should be populated with the decimal representation (e.g `"1"`). - -type: wildcard - -example: ["C:\rta\red_ttp\bin\myapp.exe"] - --- - -*`threat.enrichments.indicator.registry.data.type`*:: -+ --- -Standard registry type for encoding contents - -type: keyword - -example: REG_SZ - --- - -*`threat.enrichments.indicator.registry.hive`*:: -+ --- -Abbreviated name for the hive. - -type: keyword - -example: HKLM - --- - -*`threat.enrichments.indicator.registry.key`*:: -+ --- -Hive-relative path of keys. - -type: keyword - -example: SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\winword.exe - --- - -*`threat.enrichments.indicator.registry.path`*:: -+ --- -Full path, including hive, key and value - -type: keyword - -example: HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\winword.exe\Debugger - --- - -*`threat.enrichments.indicator.registry.value`*:: -+ --- -Name of the value written. - -type: keyword - -example: Debugger - --- - -*`threat.enrichments.indicator.scanner_stats`*:: -+ --- -Count of AV/EDR vendors that successfully detected malicious file or URL. - -type: long - -example: 4 - --- - -*`threat.enrichments.indicator.sightings`*:: -+ --- -Number of times this indicator was observed conducting threat activity. - -type: long - -example: 20 - --- - -*`threat.enrichments.indicator.type`*:: -+ --- -Type of indicator as represented by Cyber Observable in STIX 2.0. Recommended values: - * autonomous-system - * artifact - * directory - * domain-name - * email-addr - * file - * ipv4-addr - * ipv6-addr - * mac-addr - * mutex - * port - * process - * software - * url - * user-account - * windows-registry-key - * x509-certificate - -type: keyword - -example: ipv4-addr - --- - -*`threat.enrichments.indicator.url.domain`*:: -+ --- -Domain of the url, such as "www.elastic.co". -In some cases a URL may refer to an IP and/or port directly, without a domain name. In this case, the IP address would go to the `domain` field. -If the URL contains a literal IPv6 address enclosed by `[` and `]` (IETF RFC 2732), the `[` and `]` characters should also be captured in the `domain` field. - -type: keyword - -example: www.elastic.co - --- - -*`threat.enrichments.indicator.url.extension`*:: -+ --- -The field contains the file extension from the original request url, excluding the leading dot. -The file extension is only set if it exists, as not every url has a file extension. -The leading period must not be included. For example, the value must be "png", not ".png". -Note that when the file name has multiple extensions (example.tar.gz), only the last one should be captured ("gz", not "tar.gz"). - -type: keyword - -example: png - --- - -*`threat.enrichments.indicator.url.fragment`*:: -+ --- -Portion of the url after the `#`, such as "top". -The `#` is not part of the fragment. - -type: keyword - --- - -*`threat.enrichments.indicator.url.full`*:: -+ --- -If full URLs are important to your use case, they should be stored in `url.full`, whether this field is reconstructed or present in the event source. - -type: wildcard - -example: https://www.elastic.co:443/search?q=elasticsearch#top - --- - -*`threat.enrichments.indicator.url.full.text`*:: -+ --- -type: match_only_text - --- - -*`threat.enrichments.indicator.url.original`*:: -+ --- -Unmodified original url as seen in the event source. -Note that in network monitoring, the observed URL may be a full URL, whereas in access logs, the URL is often just represented as a path. -This field is meant to represent the URL as it was observed, complete or not. - -type: wildcard - -example: https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch - --- - -*`threat.enrichments.indicator.url.original.text`*:: -+ --- -type: match_only_text - --- - -*`threat.enrichments.indicator.url.password`*:: -+ --- -Password of the request. - -type: keyword - --- - -*`threat.enrichments.indicator.url.path`*:: -+ --- -Path of the request, such as "/search". - -type: wildcard - --- - -*`threat.enrichments.indicator.url.port`*:: -+ --- -Port of the request, such as 443. - -type: long - -example: 443 - -format: string - --- - -*`threat.enrichments.indicator.url.query`*:: -+ --- -The query field describes the query string of the request, such as "q=elasticsearch". -The `?` is excluded from the query string. If a URL contains no `?`, there is no query field. If there is a `?` but no query, the query field exists with an empty string. The `exists` query can be used to differentiate between the two cases. - -type: keyword - --- - -*`threat.enrichments.indicator.url.registered_domain`*:: -+ --- -The highest registered url domain, stripped of the subdomain. -For example, the registered domain for "foo.example.com" is "example.com". -This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk". - -type: keyword - -example: example.com - --- - -*`threat.enrichments.indicator.url.scheme`*:: -+ --- -Scheme of the request, such as "https". -Note: The `:` is not part of the scheme. - -type: keyword - -example: https - --- - -*`threat.enrichments.indicator.url.subdomain`*:: -+ --- -The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. -For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period. - -type: keyword - -example: east - --- - -*`threat.enrichments.indicator.url.top_level_domain`*:: -+ --- -The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". -This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk". - -type: keyword - -example: co.uk - --- - -*`threat.enrichments.indicator.url.username`*:: -+ --- -Username of the request. - -type: keyword - --- - -*`threat.enrichments.indicator.x509.alternative_names`*:: -+ --- -List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses. - -type: keyword - -example: *.elastic.co - --- - -*`threat.enrichments.indicator.x509.issuer.common_name`*:: -+ --- -List of common name (CN) of issuing certificate authority. - -type: keyword - -example: Example SHA2 High Assurance Server CA - --- - -*`threat.enrichments.indicator.x509.issuer.country`*:: -+ --- -List of country (C) codes - -type: keyword - -example: US - --- - -*`threat.enrichments.indicator.x509.issuer.distinguished_name`*:: -+ --- -Distinguished name (DN) of issuing certificate authority. - -type: keyword - -example: C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA - --- - -*`threat.enrichments.indicator.x509.issuer.locality`*:: -+ --- -List of locality names (L) - -type: keyword - -example: Mountain View - --- - -*`threat.enrichments.indicator.x509.issuer.organization`*:: -+ --- -List of organizations (O) of issuing certificate authority. - -type: keyword - -example: Example Inc - --- - -*`threat.enrichments.indicator.x509.issuer.organizational_unit`*:: -+ --- -List of organizational units (OU) of issuing certificate authority. - -type: keyword - -example: www.example.com - --- - -*`threat.enrichments.indicator.x509.issuer.state_or_province`*:: -+ --- -List of state or province names (ST, S, or P) - -type: keyword - -example: California - --- - -*`threat.enrichments.indicator.x509.not_after`*:: -+ --- -Time at which the certificate is no longer considered valid. - -type: date - -example: 2020-07-16 03:15:39+00:00 - --- - -*`threat.enrichments.indicator.x509.not_before`*:: -+ --- -Time at which the certificate is first considered valid. - -type: date - -example: 2019-08-16 01:40:25+00:00 - --- - -*`threat.enrichments.indicator.x509.public_key_algorithm`*:: -+ --- -Algorithm used to generate the public key. - -type: keyword - -example: RSA - --- - -*`threat.enrichments.indicator.x509.public_key_curve`*:: -+ --- -The curve used by the elliptic curve public key algorithm. This is algorithm specific. - -type: keyword - -example: nistp521 - --- - -*`threat.enrichments.indicator.x509.public_key_exponent`*:: -+ --- -Exponent used to derive the public key. This is algorithm specific. - -type: long - -example: 65537 - -Field is not indexed. - --- - -*`threat.enrichments.indicator.x509.public_key_size`*:: -+ --- -The size of the public key space in bits. - -type: long - -example: 2048 - --- - -*`threat.enrichments.indicator.x509.serial_number`*:: -+ --- -Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters. - -type: keyword - -example: 55FBB9C7DEBF09809D12CCAA - --- - -*`threat.enrichments.indicator.x509.signature_algorithm`*:: -+ --- -Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353. - -type: keyword - -example: SHA256-RSA - --- - -*`threat.enrichments.indicator.x509.subject.common_name`*:: -+ --- -List of common names (CN) of subject. - -type: keyword - -example: shared.global.example.net - --- - -*`threat.enrichments.indicator.x509.subject.country`*:: -+ --- -List of country (C) code - -type: keyword - -example: US - --- - -*`threat.enrichments.indicator.x509.subject.distinguished_name`*:: -+ --- -Distinguished name (DN) of the certificate subject entity. - -type: keyword - -example: C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net - --- - -*`threat.enrichments.indicator.x509.subject.locality`*:: -+ --- -List of locality names (L) - -type: keyword - -example: San Francisco - --- - -*`threat.enrichments.indicator.x509.subject.organization`*:: -+ --- -List of organizations (O) of subject. - -type: keyword - -example: Example, Inc. - --- - -*`threat.enrichments.indicator.x509.subject.organizational_unit`*:: -+ --- -List of organizational units (OU) of subject. - -type: keyword - --- - -*`threat.enrichments.indicator.x509.subject.state_or_province`*:: -+ --- -List of state or province names (ST, S, or P) - -type: keyword - -example: California - --- - -*`threat.enrichments.indicator.x509.version_number`*:: -+ --- -Version of x509 format. - -type: keyword - -example: 3 - --- - -*`threat.enrichments.matched.atomic`*:: -+ --- -Identifies the atomic indicator value that matched a local environment endpoint or network event. - -type: keyword - -example: bad-domain.com - --- - -*`threat.enrichments.matched.field`*:: -+ --- -Identifies the field of the atomic indicator that matched a local environment endpoint or network event. - -type: keyword - -example: file.hash.sha256 - --- - -*`threat.enrichments.matched.id`*:: -+ --- -Identifies the _id of the indicator document enriching the event. - -type: keyword - -example: ff93aee5-86a1-4a61-b0e6-0cdc313d01b5 - --- - -*`threat.enrichments.matched.index`*:: -+ --- -Identifies the _index of the indicator document enriching the event. - -type: keyword - -example: filebeat-8.0.0-2021.05.23-000011 - --- - -*`threat.enrichments.matched.type`*:: -+ --- -Identifies the type of match that caused the event to be enriched with the given indicator - -type: keyword - -example: indicator_match_rule - --- - -*`threat.framework`*:: -+ --- -Name of the threat framework used to further categorize and classify the tactic and technique of the reported threat. Framework classification can be provided by detecting systems, evaluated at ingest time, or retrospectively tagged to events. - -type: keyword - -example: MITRE ATT&CK - --- - -*`threat.group.alias`*:: -+ --- -The alias(es) of the group for a set of related intrusion activity that are tracked by a common name in the security community. -While not required, you can use a MITRE ATT&CK® group alias(es). - -type: keyword - -example: [ "Magecart Group 6" ] - --- - -*`threat.group.id`*:: -+ --- -The id of the group for a set of related intrusion activity that are tracked by a common name in the security community. -While not required, you can use a MITRE ATT&CK® group id. - -type: keyword - -example: G0037 - --- - -*`threat.group.name`*:: -+ --- -The name of the group for a set of related intrusion activity that are tracked by a common name in the security community. -While not required, you can use a MITRE ATT&CK® group name. - -type: keyword - -example: FIN6 - --- - -*`threat.group.reference`*:: -+ --- -The reference URL of the group for a set of related intrusion activity that are tracked by a common name in the security community. -While not required, you can use a MITRE ATT&CK® group reference URL. - -type: keyword - -example: https://attack.mitre.org/groups/G0037/ - --- - -*`threat.indicator.as.number`*:: -+ --- -Unique number allocated to the autonomous system. The autonomous system number (ASN) uniquely identifies each network on the Internet. - -type: long - -example: 15169 - --- - -*`threat.indicator.as.organization.name`*:: -+ --- -Organization name. - -type: keyword - -example: Google LLC - --- - -*`threat.indicator.as.organization.name.text`*:: -+ --- -type: match_only_text - --- - -*`threat.indicator.confidence`*:: -+ --- -Identifies the vendor-neutral confidence rating using the None/Low/Medium/High scale defined in Appendix A of the STIX 2.1 framework. Vendor-specific confidence scales may be added as custom fields. -Expected values are: - * Not Specified - * None - * Low - * Medium - * High - -type: keyword - -example: Medium - --- - -*`threat.indicator.description`*:: -+ --- -Describes the type of action conducted by the threat. - -type: keyword - -example: IP x.x.x.x was observed delivering the Angler EK. - --- - -*`threat.indicator.email.address`*:: -+ --- -Identifies a threat indicator as an email address (irrespective of direction). - -type: keyword - -example: phish@example.com - --- - -*`threat.indicator.file.accessed`*:: -+ --- -Last time the file was accessed. -Note that not all filesystems keep track of access time. - -type: date - --- - -*`threat.indicator.file.attributes`*:: -+ --- -Array of file attributes. -Attributes names will vary by platform. Here's a non-exhaustive list of values that are expected in this field: archive, compressed, directory, encrypted, execute, hidden, read, readonly, system, write. - -type: keyword - -example: ["readonly", "system"] - --- - -*`threat.indicator.file.code_signature.digest_algorithm`*:: -+ --- -The hashing algorithm used to sign the process. -This value can distinguish signatures when a file is signed multiple times by the same signer but with a different digest algorithm. - -type: keyword - -example: sha256 - --- - -*`threat.indicator.file.code_signature.exists`*:: -+ --- -Boolean to capture if a signature is present. - -type: boolean - -example: true - --- - -*`threat.indicator.file.code_signature.signing_id`*:: -+ --- -The identifier used to sign the process. -This is used to identify the application manufactured by a software vendor. The field is relevant to Apple *OS only. - -type: keyword - -example: com.apple.xpc.proxy - --- - -*`threat.indicator.file.code_signature.status`*:: -+ --- -Additional information about the certificate status. -This is useful for logging cryptographic errors with the certificate validity or trust status. Leave unpopulated if the validity or trust of the certificate was unchecked. - -type: keyword - -example: ERROR_UNTRUSTED_ROOT - --- - -*`threat.indicator.file.code_signature.subject_name`*:: -+ --- -Subject name of the code signer - -type: keyword - -example: Microsoft Corporation - --- - -*`threat.indicator.file.code_signature.team_id`*:: -+ --- -The team identifier used to sign the process. -This is used to identify the team or vendor of a software product. The field is relevant to Apple *OS only. - -type: keyword - -example: EQHXZ8M8AV - --- - -*`threat.indicator.file.code_signature.timestamp`*:: -+ --- -Date and time when the code signature was generated and signed. - -type: date - -example: 2021-01-01T12:10:30Z - --- - -*`threat.indicator.file.code_signature.trusted`*:: -+ --- -Stores the trust status of the certificate chain. -Validating the trust of the certificate chain may be complicated, and this field should only be populated by tools that actively check the status. - -type: boolean - -example: true - --- - -*`threat.indicator.file.code_signature.valid`*:: -+ --- -Boolean to capture if the digital signature is verified against the binary content. -Leave unpopulated if a certificate was unchecked. - -type: boolean - -example: true - --- - -*`threat.indicator.file.created`*:: -+ --- -File creation time. -Note that not all filesystems store the creation time. - -type: date - --- - -*`threat.indicator.file.ctime`*:: -+ --- -Last time the file attributes or metadata changed. -Note that changes to the file content will update `mtime`. This implies `ctime` will be adjusted at the same time, since `mtime` is an attribute of the file. - -type: date - --- - -*`threat.indicator.file.device`*:: -+ --- -Device that is the source of the file. - -type: keyword - -example: sda - --- - -*`threat.indicator.file.directory`*:: -+ --- -Directory where the file is located. It should include the drive letter, when appropriate. - -type: keyword - -example: /home/alice - --- - -*`threat.indicator.file.drive_letter`*:: -+ --- -Drive letter where the file is located. This field is only relevant on Windows. -The value should be uppercase, and not include the colon. - -type: keyword - -example: C - --- - -*`threat.indicator.file.elf.architecture`*:: -+ --- -Machine architecture of the ELF file. - -type: keyword - -example: x86-64 - --- - -*`threat.indicator.file.elf.byte_order`*:: -+ --- -Byte sequence of ELF file. - -type: keyword - -example: Little Endian - --- - -*`threat.indicator.file.elf.cpu_type`*:: -+ --- -CPU type of the ELF file. - -type: keyword - -example: Intel - --- - -*`threat.indicator.file.elf.creation_date`*:: -+ --- -Extracted when possible from the file's metadata. Indicates when it was built or compiled. It can also be faked by malware creators. - -type: date - --- - -*`threat.indicator.file.elf.exports`*:: -+ --- -List of exported element names and types. - -type: flattened - --- - -*`threat.indicator.file.elf.header.abi_version`*:: -+ --- -Version of the ELF Application Binary Interface (ABI). - -type: keyword - --- - -*`threat.indicator.file.elf.header.class`*:: -+ --- -Header class of the ELF file. - -type: keyword - --- - -*`threat.indicator.file.elf.header.data`*:: -+ --- -Data table of the ELF header. - -type: keyword - --- - -*`threat.indicator.file.elf.header.entrypoint`*:: -+ --- -Header entrypoint of the ELF file. - -type: long - -format: string - --- - -*`threat.indicator.file.elf.header.object_version`*:: -+ --- -"0x1" for original ELF files. - -type: keyword - --- - -*`threat.indicator.file.elf.header.os_abi`*:: -+ --- -Application Binary Interface (ABI) of the Linux OS. - -type: keyword - --- - -*`threat.indicator.file.elf.header.type`*:: -+ --- -Header type of the ELF file. - -type: keyword - --- - -*`threat.indicator.file.elf.header.version`*:: -+ --- -Version of the ELF header. - -type: keyword - --- - -*`threat.indicator.file.elf.imports`*:: -+ --- -List of imported element names and types. - -type: flattened - --- - -*`threat.indicator.file.elf.sections`*:: -+ --- -An array containing an object for each section of the ELF file. -The keys that should be present in these objects are defined by sub-fields underneath `elf.sections.*`. - -type: nested - --- - -*`threat.indicator.file.elf.sections.chi2`*:: -+ --- -Chi-square probability distribution of the section. - -type: long - -format: number - --- - -*`threat.indicator.file.elf.sections.entropy`*:: -+ --- -Shannon entropy calculation from the section. - -type: long - -format: number - --- - -*`threat.indicator.file.elf.sections.flags`*:: -+ --- -ELF Section List flags. - -type: keyword - --- - -*`threat.indicator.file.elf.sections.name`*:: -+ --- -ELF Section List name. - -type: keyword - --- - -*`threat.indicator.file.elf.sections.physical_offset`*:: -+ --- -ELF Section List offset. - -type: keyword - --- - -*`threat.indicator.file.elf.sections.physical_size`*:: -+ --- -ELF Section List physical size. - -type: long - -format: bytes - --- - -*`threat.indicator.file.elf.sections.type`*:: -+ --- -ELF Section List type. - -type: keyword - --- - -*`threat.indicator.file.elf.sections.virtual_address`*:: -+ --- -ELF Section List virtual address. - -type: long - -format: string - --- - -*`threat.indicator.file.elf.sections.virtual_size`*:: -+ --- -ELF Section List virtual size. - -type: long - -format: string - --- - -*`threat.indicator.file.elf.segments`*:: -+ --- -An array containing an object for each segment of the ELF file. -The keys that should be present in these objects are defined by sub-fields underneath `elf.segments.*`. - -type: nested - --- - -*`threat.indicator.file.elf.segments.sections`*:: -+ --- -ELF object segment sections. - -type: keyword - --- - -*`threat.indicator.file.elf.segments.type`*:: -+ --- -ELF object segment type. - -type: keyword - --- - -*`threat.indicator.file.elf.shared_libraries`*:: -+ --- -List of shared libraries used by this ELF object. - -type: keyword - --- - -*`threat.indicator.file.elf.telfhash`*:: -+ --- -telfhash symbol hash for ELF file. - -type: keyword - --- - -*`threat.indicator.file.extension`*:: -+ --- -File extension, excluding the leading dot. -Note that when the file name has multiple extensions (example.tar.gz), only the last one should be captured ("gz", not "tar.gz"). - -type: keyword - -example: png - --- - -*`threat.indicator.file.fork_name`*:: -+ --- -A fork is additional data associated with a filesystem object. -On Linux, a resource fork is used to store additional data with a filesystem object. A file always has at least one fork for the data portion, and additional forks may exist. -On NTFS, this is analogous to an Alternate Data Stream (ADS), and the default data stream for a file is just called $DATA. Zone.Identifier is commonly used by Windows to track contents downloaded from the Internet. An ADS is typically of the form: `C:\path\to\filename.extension:some_fork_name`, and `some_fork_name` is the value that should populate `fork_name`. `filename.extension` should populate `file.name`, and `extension` should populate `file.extension`. The full path, `file.path`, will include the fork name. - -type: keyword - -example: Zone.Identifer - --- - -*`threat.indicator.file.gid`*:: -+ --- -Primary group ID (GID) of the file. - -type: keyword - -example: 1001 - --- - -*`threat.indicator.file.group`*:: -+ --- -Primary group name of the file. - -type: keyword - -example: alice - --- - -*`threat.indicator.file.hash.md5`*:: -+ --- -MD5 hash. - -type: keyword - --- - -*`threat.indicator.file.hash.sha1`*:: -+ --- -SHA1 hash. - -type: keyword - --- - -*`threat.indicator.file.hash.sha256`*:: -+ --- -SHA256 hash. - -type: keyword - --- - -*`threat.indicator.file.hash.sha512`*:: -+ --- -SHA512 hash. - -type: keyword - --- - -*`threat.indicator.file.hash.ssdeep`*:: -+ --- -SSDEEP hash. - -type: keyword - --- - -*`threat.indicator.file.inode`*:: -+ --- -Inode representing the file in the filesystem. - -type: keyword - -example: 256383 - --- - -*`threat.indicator.file.mime_type`*:: -+ --- -MIME type should identify the format of the file or stream of bytes using https://www.iana.org/assignments/media-types/media-types.xhtml[IANA official types], where possible. When more than one type is applicable, the most specific type should be used. - -type: keyword - --- - -*`threat.indicator.file.mode`*:: -+ --- -Mode of the file in octal representation. - -type: keyword - -example: 0640 - --- - -*`threat.indicator.file.mtime`*:: -+ --- -Last time the file content was modified. - -type: date - --- - -*`threat.indicator.file.name`*:: -+ --- -Name of the file including the extension, without the directory. - -type: keyword - -example: example.png - --- - -*`threat.indicator.file.owner`*:: -+ --- -File owner's username. - -type: keyword - -example: alice - --- - -*`threat.indicator.file.path`*:: -+ --- -Full path to the file, including the file name. It should include the drive letter, when appropriate. - -type: keyword - -example: /home/alice/example.png - --- - -*`threat.indicator.file.path.text`*:: -+ --- -type: match_only_text - --- - -*`threat.indicator.file.pe.architecture`*:: -+ --- -CPU architecture target for the file. - -type: keyword - -example: x64 - --- - -*`threat.indicator.file.pe.company`*:: -+ --- -Internal company name of the file, provided at compile-time. - -type: keyword - -example: Microsoft Corporation - --- - -*`threat.indicator.file.pe.description`*:: -+ --- -Internal description of the file, provided at compile-time. - -type: keyword - -example: Paint - --- - -*`threat.indicator.file.pe.file_version`*:: -+ --- -Internal version of the file, provided at compile-time. - -type: keyword - -example: 6.3.9600.17415 - --- - -*`threat.indicator.file.pe.imphash`*:: -+ --- -A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. -Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html. - -type: keyword - -example: 0c6803c4e922103c4dca5963aad36ddf - --- - -*`threat.indicator.file.pe.original_file_name`*:: -+ --- -Internal name of the file, provided at compile-time. - -type: keyword - -example: MSPAINT.EXE - --- - -*`threat.indicator.file.pe.product`*:: -+ --- -Internal product name of the file, provided at compile-time. - -type: keyword - -example: Microsoft® Windows® Operating System - --- - -*`threat.indicator.file.size`*:: -+ --- -File size in bytes. -Only relevant when `file.type` is "file". - -type: long - -example: 16384 - --- - -*`threat.indicator.file.target_path`*:: -+ --- -Target path for symlinks. - -type: keyword - --- - -*`threat.indicator.file.target_path.text`*:: -+ --- -type: match_only_text - --- - -*`threat.indicator.file.type`*:: -+ --- -File type (file, dir, or symlink). - -type: keyword - -example: file - --- - -*`threat.indicator.file.uid`*:: -+ --- -The user ID (UID) or security identifier (SID) of the file owner. - -type: keyword - -example: 1001 - --- - -*`threat.indicator.file.x509.alternative_names`*:: -+ --- -List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses. - -type: keyword - -example: *.elastic.co - --- - -*`threat.indicator.file.x509.issuer.common_name`*:: -+ --- -List of common name (CN) of issuing certificate authority. - -type: keyword - -example: Example SHA2 High Assurance Server CA - --- - -*`threat.indicator.file.x509.issuer.country`*:: -+ --- -List of country (C) codes - -type: keyword - -example: US - --- - -*`threat.indicator.file.x509.issuer.distinguished_name`*:: -+ --- -Distinguished name (DN) of issuing certificate authority. - -type: keyword - -example: C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA - --- - -*`threat.indicator.file.x509.issuer.locality`*:: -+ --- -List of locality names (L) - -type: keyword - -example: Mountain View - --- - -*`threat.indicator.file.x509.issuer.organization`*:: -+ --- -List of organizations (O) of issuing certificate authority. - -type: keyword - -example: Example Inc - --- - -*`threat.indicator.file.x509.issuer.organizational_unit`*:: -+ --- -List of organizational units (OU) of issuing certificate authority. - -type: keyword - -example: www.example.com - --- - -*`threat.indicator.file.x509.issuer.state_or_province`*:: -+ --- -List of state or province names (ST, S, or P) - -type: keyword - -example: California - --- - -*`threat.indicator.file.x509.not_after`*:: -+ --- -Time at which the certificate is no longer considered valid. - -type: date - -example: 2020-07-16 03:15:39+00:00 - --- - -*`threat.indicator.file.x509.not_before`*:: -+ --- -Time at which the certificate is first considered valid. - -type: date - -example: 2019-08-16 01:40:25+00:00 - --- - -*`threat.indicator.file.x509.public_key_algorithm`*:: -+ --- -Algorithm used to generate the public key. - -type: keyword - -example: RSA - --- - -*`threat.indicator.file.x509.public_key_curve`*:: -+ --- -The curve used by the elliptic curve public key algorithm. This is algorithm specific. - -type: keyword - -example: nistp521 - --- - -*`threat.indicator.file.x509.public_key_exponent`*:: -+ --- -Exponent used to derive the public key. This is algorithm specific. - -type: long - -example: 65537 - -Field is not indexed. - --- - -*`threat.indicator.file.x509.public_key_size`*:: -+ --- -The size of the public key space in bits. - -type: long - -example: 2048 - --- - -*`threat.indicator.file.x509.serial_number`*:: -+ --- -Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters. - -type: keyword - -example: 55FBB9C7DEBF09809D12CCAA - --- - -*`threat.indicator.file.x509.signature_algorithm`*:: -+ --- -Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353. - -type: keyword - -example: SHA256-RSA - --- - -*`threat.indicator.file.x509.subject.common_name`*:: -+ --- -List of common names (CN) of subject. - -type: keyword - -example: shared.global.example.net - --- - -*`threat.indicator.file.x509.subject.country`*:: -+ --- -List of country (C) code - -type: keyword - -example: US - --- - -*`threat.indicator.file.x509.subject.distinguished_name`*:: -+ --- -Distinguished name (DN) of the certificate subject entity. - -type: keyword - -example: C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net - --- - -*`threat.indicator.file.x509.subject.locality`*:: -+ --- -List of locality names (L) - -type: keyword - -example: San Francisco - --- - -*`threat.indicator.file.x509.subject.organization`*:: -+ --- -List of organizations (O) of subject. - -type: keyword - -example: Example, Inc. - --- - -*`threat.indicator.file.x509.subject.organizational_unit`*:: -+ --- -List of organizational units (OU) of subject. - -type: keyword - --- - -*`threat.indicator.file.x509.subject.state_or_province`*:: -+ --- -List of state or province names (ST, S, or P) - -type: keyword - -example: California - --- - -*`threat.indicator.file.x509.version_number`*:: -+ --- -Version of x509 format. - -type: keyword - -example: 3 - --- - -*`threat.indicator.first_seen`*:: -+ --- -The date and time when intelligence source first reported sighting this indicator. - -type: date - -example: 2020-11-05T17:25:47.000Z - --- - -*`threat.indicator.geo.city_name`*:: -+ --- -City name. - -type: keyword - -example: Montreal - --- - -*`threat.indicator.geo.continent_code`*:: -+ --- -Two-letter code representing continent's name. - -type: keyword - -example: NA - --- - -*`threat.indicator.geo.continent_name`*:: -+ --- -Name of the continent. - -type: keyword - -example: North America - --- - -*`threat.indicator.geo.country_iso_code`*:: -+ --- -Country ISO code. - -type: keyword - -example: CA - --- - -*`threat.indicator.geo.country_name`*:: -+ --- -Country name. - -type: keyword - -example: Canada - --- - -*`threat.indicator.geo.location`*:: -+ --- -Longitude and latitude. - -type: geo_point - -example: { "lon": -73.614830, "lat": 45.505918 } - --- - -*`threat.indicator.geo.name`*:: -+ --- -User-defined description of a location, at the level of granularity they care about. -Could be the name of their data centers, the floor number, if this describes a local physical entity, city names. -Not typically used in automated geolocation. - -type: keyword - -example: boston-dc - --- - -*`threat.indicator.geo.postal_code`*:: -+ --- -Postal code associated with the location. -Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country. - -type: keyword - -example: 94040 - --- - -*`threat.indicator.geo.region_iso_code`*:: -+ --- -Region ISO code. - -type: keyword - -example: CA-QC - --- - -*`threat.indicator.geo.region_name`*:: -+ --- -Region name. - -type: keyword - -example: Quebec - --- - -*`threat.indicator.geo.timezone`*:: -+ --- -The time zone of the location, such as IANA time zone name. - -type: keyword - -example: America/Argentina/Buenos_Aires - --- - -*`threat.indicator.ip`*:: -+ --- -Identifies a threat indicator as an IP address (irrespective of direction). - -type: ip - -example: 1.2.3.4 - --- - -*`threat.indicator.last_seen`*:: -+ --- -The date and time when intelligence source last reported sighting this indicator. - -type: date - -example: 2020-11-05T17:25:47.000Z - --- - -*`threat.indicator.marking.tlp`*:: -+ --- -Traffic Light Protocol sharing markings. -Recommended values are: - * WHITE - * GREEN - * AMBER - * RED - -type: keyword - -example: WHITE - --- - -*`threat.indicator.modified_at`*:: -+ --- -The date and time when intelligence source last modified information for this indicator. - -type: date - -example: 2020-11-05T17:25:47.000Z - --- - -*`threat.indicator.port`*:: -+ --- -Identifies a threat indicator as a port number (irrespective of direction). - -type: long - -example: 443 - --- - -*`threat.indicator.provider`*:: -+ --- -The name of the indicator's provider. - -type: keyword - -example: lrz_urlhaus - --- - -*`threat.indicator.reference`*:: -+ --- -Reference URL linking to additional information about this indicator. - -type: keyword - -example: https://system.example.com/indicator/0001234 - --- - -*`threat.indicator.registry.data.bytes`*:: -+ --- -Original bytes written with base64 encoding. -For Windows registry operations, such as SetValueEx and RegQueryValueEx, this corresponds to the data pointed by `lp_data`. This is optional but provides better recoverability and should be populated for REG_BINARY encoded values. - -type: keyword - -example: ZQBuAC0AVQBTAAAAZQBuAAAAAAA= - --- - -*`threat.indicator.registry.data.strings`*:: -+ --- -Content when writing string types. -Populated as an array when writing string data to the registry. For single string registry types (REG_SZ, REG_EXPAND_SZ), this should be an array with one string. For sequences of string with REG_MULTI_SZ, this array will be variable length. For numeric data, such as REG_DWORD and REG_QWORD, this should be populated with the decimal representation (e.g `"1"`). - -type: wildcard - -example: ["C:\rta\red_ttp\bin\myapp.exe"] - --- - -*`threat.indicator.registry.data.type`*:: -+ --- -Standard registry type for encoding contents - -type: keyword - -example: REG_SZ - --- - -*`threat.indicator.registry.hive`*:: -+ --- -Abbreviated name for the hive. - -type: keyword - -example: HKLM - --- - -*`threat.indicator.registry.key`*:: -+ --- -Hive-relative path of keys. - -type: keyword - -example: SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\winword.exe - --- - -*`threat.indicator.registry.path`*:: -+ --- -Full path, including hive, key and value - -type: keyword - -example: HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\winword.exe\Debugger - --- - -*`threat.indicator.registry.value`*:: -+ --- -Name of the value written. - -type: keyword - -example: Debugger - --- - -*`threat.indicator.scanner_stats`*:: -+ --- -Count of AV/EDR vendors that successfully detected malicious file or URL. - -type: long - -example: 4 - --- - -*`threat.indicator.sightings`*:: -+ --- -Number of times this indicator was observed conducting threat activity. - -type: long - -example: 20 - --- - -*`threat.indicator.type`*:: -+ --- -Type of indicator as represented by Cyber Observable in STIX 2.0. -Recommended values: - * autonomous-system - * artifact - * directory - * domain-name - * email-addr - * file - * ipv4-addr - * ipv6-addr - * mac-addr - * mutex - * port - * process - * software - * url - * user-account - * windows-registry-key - * x509-certificate - -type: keyword - -example: ipv4-addr - --- - -*`threat.indicator.url.domain`*:: -+ --- -Domain of the url, such as "www.elastic.co". -In some cases a URL may refer to an IP and/or port directly, without a domain name. In this case, the IP address would go to the `domain` field. -If the URL contains a literal IPv6 address enclosed by `[` and `]` (IETF RFC 2732), the `[` and `]` characters should also be captured in the `domain` field. - -type: keyword - -example: www.elastic.co - --- - -*`threat.indicator.url.extension`*:: -+ --- -The field contains the file extension from the original request url, excluding the leading dot. -The file extension is only set if it exists, as not every url has a file extension. -The leading period must not be included. For example, the value must be "png", not ".png". -Note that when the file name has multiple extensions (example.tar.gz), only the last one should be captured ("gz", not "tar.gz"). - -type: keyword - -example: png - --- - -*`threat.indicator.url.fragment`*:: -+ --- -Portion of the url after the `#`, such as "top". -The `#` is not part of the fragment. - -type: keyword - --- - -*`threat.indicator.url.full`*:: -+ --- -If full URLs are important to your use case, they should be stored in `url.full`, whether this field is reconstructed or present in the event source. - -type: wildcard - -example: https://www.elastic.co:443/search?q=elasticsearch#top - --- - -*`threat.indicator.url.full.text`*:: -+ --- -type: match_only_text - --- - -*`threat.indicator.url.original`*:: -+ --- -Unmodified original url as seen in the event source. -Note that in network monitoring, the observed URL may be a full URL, whereas in access logs, the URL is often just represented as a path. -This field is meant to represent the URL as it was observed, complete or not. - -type: wildcard - -example: https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch - --- - -*`threat.indicator.url.original.text`*:: -+ --- -type: match_only_text - --- - -*`threat.indicator.url.password`*:: -+ --- -Password of the request. - -type: keyword - --- - -*`threat.indicator.url.path`*:: -+ --- -Path of the request, such as "/search". - -type: wildcard - --- - -*`threat.indicator.url.port`*:: -+ --- -Port of the request, such as 443. - -type: long - -example: 443 - -format: string - --- - -*`threat.indicator.url.query`*:: -+ --- -The query field describes the query string of the request, such as "q=elasticsearch". -The `?` is excluded from the query string. If a URL contains no `?`, there is no query field. If there is a `?` but no query, the query field exists with an empty string. The `exists` query can be used to differentiate between the two cases. - -type: keyword - --- - -*`threat.indicator.url.registered_domain`*:: -+ --- -The highest registered url domain, stripped of the subdomain. -For example, the registered domain for "foo.example.com" is "example.com". -This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk". - -type: keyword - -example: example.com - --- - -*`threat.indicator.url.scheme`*:: -+ --- -Scheme of the request, such as "https". -Note: The `:` is not part of the scheme. - -type: keyword - -example: https - --- - -*`threat.indicator.url.subdomain`*:: -+ --- -The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. -For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period. - -type: keyword - -example: east - --- - -*`threat.indicator.url.top_level_domain`*:: -+ --- -The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". -This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk". - -type: keyword - -example: co.uk - --- - -*`threat.indicator.url.username`*:: -+ --- -Username of the request. - -type: keyword - --- - -*`threat.indicator.x509.alternative_names`*:: -+ --- -List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses. - -type: keyword - -example: *.elastic.co - --- - -*`threat.indicator.x509.issuer.common_name`*:: -+ --- -List of common name (CN) of issuing certificate authority. - -type: keyword - -example: Example SHA2 High Assurance Server CA - --- - -*`threat.indicator.x509.issuer.country`*:: -+ --- -List of country (C) codes - -type: keyword - -example: US - --- - -*`threat.indicator.x509.issuer.distinguished_name`*:: -+ --- -Distinguished name (DN) of issuing certificate authority. - -type: keyword - -example: C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA - --- - -*`threat.indicator.x509.issuer.locality`*:: -+ --- -List of locality names (L) - -type: keyword - -example: Mountain View - --- - -*`threat.indicator.x509.issuer.organization`*:: -+ --- -List of organizations (O) of issuing certificate authority. - -type: keyword - -example: Example Inc - --- - -*`threat.indicator.x509.issuer.organizational_unit`*:: -+ --- -List of organizational units (OU) of issuing certificate authority. - -type: keyword - -example: www.example.com - --- - -*`threat.indicator.x509.issuer.state_or_province`*:: -+ --- -List of state or province names (ST, S, or P) - -type: keyword - -example: California - --- - -*`threat.indicator.x509.not_after`*:: -+ --- -Time at which the certificate is no longer considered valid. - -type: date - -example: 2020-07-16 03:15:39+00:00 - --- - -*`threat.indicator.x509.not_before`*:: -+ --- -Time at which the certificate is first considered valid. - -type: date - -example: 2019-08-16 01:40:25+00:00 - --- - -*`threat.indicator.x509.public_key_algorithm`*:: -+ --- -Algorithm used to generate the public key. - -type: keyword - -example: RSA - --- - -*`threat.indicator.x509.public_key_curve`*:: -+ --- -The curve used by the elliptic curve public key algorithm. This is algorithm specific. - -type: keyword - -example: nistp521 - --- - -*`threat.indicator.x509.public_key_exponent`*:: -+ --- -Exponent used to derive the public key. This is algorithm specific. - -type: long - -example: 65537 - -Field is not indexed. - --- - -*`threat.indicator.x509.public_key_size`*:: -+ --- -The size of the public key space in bits. - -type: long - -example: 2048 - --- - -*`threat.indicator.x509.serial_number`*:: -+ --- -Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters. - -type: keyword - -example: 55FBB9C7DEBF09809D12CCAA - --- - -*`threat.indicator.x509.signature_algorithm`*:: -+ --- -Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353. - -type: keyword - -example: SHA256-RSA - --- - -*`threat.indicator.x509.subject.common_name`*:: -+ --- -List of common names (CN) of subject. - -type: keyword - -example: shared.global.example.net - --- - -*`threat.indicator.x509.subject.country`*:: -+ --- -List of country (C) code - -type: keyword - -example: US - --- - -*`threat.indicator.x509.subject.distinguished_name`*:: -+ --- -Distinguished name (DN) of the certificate subject entity. - -type: keyword - -example: C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net - --- - -*`threat.indicator.x509.subject.locality`*:: -+ --- -List of locality names (L) - -type: keyword - -example: San Francisco - --- - -*`threat.indicator.x509.subject.organization`*:: -+ --- -List of organizations (O) of subject. - -type: keyword - -example: Example, Inc. - --- - -*`threat.indicator.x509.subject.organizational_unit`*:: -+ --- -List of organizational units (OU) of subject. - -type: keyword - --- - -*`threat.indicator.x509.subject.state_or_province`*:: -+ --- -List of state or province names (ST, S, or P) - -type: keyword - -example: California - --- - -*`threat.indicator.x509.version_number`*:: -+ --- -Version of x509 format. - -type: keyword - -example: 3 - --- - -*`threat.software.alias`*:: -+ --- -The alias(es) of the software for a set of related intrusion activity that are tracked by a common name in the security community. -While not required, you can use a MITRE ATT&CK® associated software description. - -type: keyword - -example: [ "X-Agent" ] - --- - -*`threat.software.id`*:: -+ --- -The id of the software used by this threat to conduct behavior commonly modeled using MITRE ATT&CK®. -While not required, you can use a MITRE ATT&CK® software id. - -type: keyword - -example: S0552 - --- - -*`threat.software.name`*:: -+ --- -The name of the software used by this threat to conduct behavior commonly modeled using MITRE ATT&CK®. -While not required, you can use a MITRE ATT&CK® software name. - -type: keyword - -example: AdFind - --- - -*`threat.software.platforms`*:: -+ --- -The platforms of the software used by this threat to conduct behavior commonly modeled using MITRE ATT&CK®. -Recommended Values: - * AWS - * Azure - * Azure AD - * GCP - * Linux - * macOS - * Network - * Office 365 - * SaaS - * Windows - -While not required, you can use a MITRE ATT&CK® software platforms. - -type: keyword - -example: [ "Windows" ] - --- - -*`threat.software.reference`*:: -+ --- -The reference URL of the software used by this threat to conduct behavior commonly modeled using MITRE ATT&CK®. -While not required, you can use a MITRE ATT&CK® software reference URL. - -type: keyword - -example: https://attack.mitre.org/software/S0552/ - --- - -*`threat.software.type`*:: -+ --- -The type of software used by this threat to conduct behavior commonly modeled using MITRE ATT&CK®. -Recommended values - * Malware - * Tool - - While not required, you can use a MITRE ATT&CK® software type. - -type: keyword - -example: Tool - --- - -*`threat.tactic.id`*:: -+ --- -The id of tactic used by this threat. You can use a MITRE ATT&CK® tactic, for example. (ex. https://attack.mitre.org/tactics/TA0002/ ) - -type: keyword - -example: TA0002 - --- - -*`threat.tactic.name`*:: -+ --- -Name of the type of tactic used by this threat. You can use a MITRE ATT&CK® tactic, for example. (ex. https://attack.mitre.org/tactics/TA0002/) - -type: keyword - -example: Execution - --- - -*`threat.tactic.reference`*:: -+ --- -The reference url of tactic used by this threat. You can use a MITRE ATT&CK® tactic, for example. (ex. https://attack.mitre.org/tactics/TA0002/ ) - -type: keyword - -example: https://attack.mitre.org/tactics/TA0002/ - --- - -*`threat.technique.id`*:: -+ --- -The id of technique used by this threat. You can use a MITRE ATT&CK® technique, for example. (ex. https://attack.mitre.org/techniques/T1059/) - -type: keyword - -example: T1059 - --- - -*`threat.technique.name`*:: -+ --- -The name of technique used by this threat. You can use a MITRE ATT&CK® technique, for example. (ex. https://attack.mitre.org/techniques/T1059/) - -type: keyword - -example: Command and Scripting Interpreter - --- - -*`threat.technique.name.text`*:: -+ --- -type: match_only_text - --- - -*`threat.technique.reference`*:: -+ --- -The reference url of technique used by this threat. You can use a MITRE ATT&CK® technique, for example. (ex. https://attack.mitre.org/techniques/T1059/) - -type: keyword - -example: https://attack.mitre.org/techniques/T1059/ - --- - -*`threat.technique.subtechnique.id`*:: -+ --- -The full id of subtechnique used by this threat. You can use a MITRE ATT&CK® subtechnique, for example. (ex. https://attack.mitre.org/techniques/T1059/001/) - -type: keyword - -example: T1059.001 - --- - -*`threat.technique.subtechnique.name`*:: -+ --- -The name of subtechnique used by this threat. You can use a MITRE ATT&CK® subtechnique, for example. (ex. https://attack.mitre.org/techniques/T1059/001/) - -type: keyword - -example: PowerShell - --- - -*`threat.technique.subtechnique.name.text`*:: -+ --- -type: match_only_text - --- - -*`threat.technique.subtechnique.reference`*:: -+ --- -The reference url of subtechnique used by this threat. You can use a MITRE ATT&CK® subtechnique, for example. (ex. https://attack.mitre.org/techniques/T1059/001/) - -type: keyword - -example: https://attack.mitre.org/techniques/T1059/001/ - --- - -[float] -=== tls - -Fields related to a TLS connection. These fields focus on the TLS protocol itself and intentionally avoids in-depth analysis of the related x.509 certificate files. - - -*`tls.cipher`*:: -+ --- -String indicating the cipher used during the current connection. - -type: keyword - -example: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - --- - -*`tls.client.certificate`*:: -+ --- -PEM-encoded stand-alone certificate offered by the client. This is usually mutually-exclusive of `client.certificate_chain` since this value also exists in that list. - -type: keyword - -example: MII... - --- - -*`tls.client.certificate_chain`*:: -+ --- -Array of PEM-encoded certificates that make up the certificate chain offered by the client. This is usually mutually-exclusive of `client.certificate` since that value should be the first certificate in the chain. - -type: keyword - -example: ["MII...", "MII..."] - --- - -*`tls.client.hash.md5`*:: -+ --- -Certificate fingerprint using the MD5 digest of DER-encoded version of certificate offered by the client. For consistency with other hash values, this value should be formatted as an uppercase hash. - -type: keyword - -example: 0F76C7F2C55BFD7D8E8B8F4BFBF0C9EC - --- - -*`tls.client.hash.sha1`*:: -+ --- -Certificate fingerprint using the SHA1 digest of DER-encoded version of certificate offered by the client. For consistency with other hash values, this value should be formatted as an uppercase hash. - -type: keyword - -example: 9E393D93138888D288266C2D915214D1D1CCEB2A - --- - -*`tls.client.hash.sha256`*:: -+ --- -Certificate fingerprint using the SHA256 digest of DER-encoded version of certificate offered by the client. For consistency with other hash values, this value should be formatted as an uppercase hash. - -type: keyword - -example: 0687F666A054EF17A08E2F2162EAB4CBC0D265E1D7875BE74BF3C712CA92DAF0 - --- - -*`tls.client.issuer`*:: -+ --- -Distinguished name of subject of the issuer of the x.509 certificate presented by the client. - -type: keyword - -example: CN=Example Root CA, OU=Infrastructure Team, DC=example, DC=com - --- - -*`tls.client.ja3`*:: -+ --- -A hash that identifies clients based on how they perform an SSL/TLS handshake. - -type: keyword - -example: d4e5b18d6b55c71272893221c96ba240 - --- - -*`tls.client.not_after`*:: -+ --- -Date/Time indicating when client certificate is no longer considered valid. - -type: date - -example: 2021-01-01T00:00:00.000Z - --- - -*`tls.client.not_before`*:: -+ --- -Date/Time indicating when client certificate is first considered valid. - -type: date - -example: 1970-01-01T00:00:00.000Z - --- - -*`tls.client.server_name`*:: -+ --- -Also called an SNI, this tells the server which hostname to which the client is attempting to connect to. When this value is available, it should get copied to `destination.domain`. - -type: keyword - -example: www.elastic.co - --- - -*`tls.client.subject`*:: -+ --- -Distinguished name of subject of the x.509 certificate presented by the client. - -type: keyword - -example: CN=myclient, OU=Documentation Team, DC=example, DC=com - --- - -*`tls.client.supported_ciphers`*:: -+ --- -Array of ciphers offered by the client during the client hello. - -type: keyword - -example: ["TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "..."] - --- - -*`tls.client.x509.alternative_names`*:: -+ --- -List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses. - -type: keyword - -example: *.elastic.co - --- - -*`tls.client.x509.issuer.common_name`*:: -+ --- -List of common name (CN) of issuing certificate authority. - -type: keyword - -example: Example SHA2 High Assurance Server CA - --- - -*`tls.client.x509.issuer.country`*:: -+ --- -List of country (C) codes - -type: keyword - -example: US - --- - -*`tls.client.x509.issuer.distinguished_name`*:: -+ --- -Distinguished name (DN) of issuing certificate authority. - -type: keyword - -example: C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA - --- - -*`tls.client.x509.issuer.locality`*:: -+ --- -List of locality names (L) - -type: keyword - -example: Mountain View - --- - -*`tls.client.x509.issuer.organization`*:: -+ --- -List of organizations (O) of issuing certificate authority. - -type: keyword - -example: Example Inc - --- - -*`tls.client.x509.issuer.organizational_unit`*:: -+ --- -List of organizational units (OU) of issuing certificate authority. - -type: keyword - -example: www.example.com - --- - -*`tls.client.x509.issuer.state_or_province`*:: -+ --- -List of state or province names (ST, S, or P) - -type: keyword - -example: California - --- - -*`tls.client.x509.not_after`*:: -+ --- -Time at which the certificate is no longer considered valid. - -type: date - -example: 2020-07-16 03:15:39+00:00 - --- - -*`tls.client.x509.not_before`*:: -+ --- -Time at which the certificate is first considered valid. - -type: date - -example: 2019-08-16 01:40:25+00:00 - --- - -*`tls.client.x509.public_key_algorithm`*:: -+ --- -Algorithm used to generate the public key. - -type: keyword - -example: RSA - --- - -*`tls.client.x509.public_key_curve`*:: -+ --- -The curve used by the elliptic curve public key algorithm. This is algorithm specific. - -type: keyword - -example: nistp521 - --- - -*`tls.client.x509.public_key_exponent`*:: -+ --- -Exponent used to derive the public key. This is algorithm specific. - -type: long - -example: 65537 - -Field is not indexed. - --- - -*`tls.client.x509.public_key_size`*:: -+ --- -The size of the public key space in bits. - -type: long - -example: 2048 - --- - -*`tls.client.x509.serial_number`*:: -+ --- -Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters. - -type: keyword - -example: 55FBB9C7DEBF09809D12CCAA - --- - -*`tls.client.x509.signature_algorithm`*:: -+ --- -Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353. - -type: keyword - -example: SHA256-RSA - --- - -*`tls.client.x509.subject.common_name`*:: -+ --- -List of common names (CN) of subject. - -type: keyword - -example: shared.global.example.net - --- - -*`tls.client.x509.subject.country`*:: -+ --- -List of country (C) code - -type: keyword - -example: US - --- - -*`tls.client.x509.subject.distinguished_name`*:: -+ --- -Distinguished name (DN) of the certificate subject entity. - -type: keyword - -example: C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net - --- - -*`tls.client.x509.subject.locality`*:: -+ --- -List of locality names (L) - -type: keyword - -example: San Francisco - --- - -*`tls.client.x509.subject.organization`*:: -+ --- -List of organizations (O) of subject. - -type: keyword - -example: Example, Inc. - --- - -*`tls.client.x509.subject.organizational_unit`*:: -+ --- -List of organizational units (OU) of subject. - -type: keyword - --- - -*`tls.client.x509.subject.state_or_province`*:: -+ --- -List of state or province names (ST, S, or P) - -type: keyword - -example: California - --- - -*`tls.client.x509.version_number`*:: -+ --- -Version of x509 format. - -type: keyword - -example: 3 - --- - -*`tls.curve`*:: -+ --- -String indicating the curve used for the given cipher, when applicable. - -type: keyword - -example: secp256r1 - --- - -*`tls.established`*:: -+ --- -Boolean flag indicating if the TLS negotiation was successful and transitioned to an encrypted tunnel. - -type: boolean - --- - -*`tls.next_protocol`*:: -+ --- -String indicating the protocol being tunneled. Per the values in the IANA registry (https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids), this string should be lower case. - -type: keyword - -example: http/1.1 - --- - -*`tls.resumed`*:: -+ --- -Boolean flag indicating if this TLS connection was resumed from an existing TLS negotiation. - -type: boolean - --- - -*`tls.server.certificate`*:: -+ --- -PEM-encoded stand-alone certificate offered by the server. This is usually mutually-exclusive of `server.certificate_chain` since this value also exists in that list. - -type: keyword - -example: MII... - --- - -*`tls.server.certificate_chain`*:: -+ --- -Array of PEM-encoded certificates that make up the certificate chain offered by the server. This is usually mutually-exclusive of `server.certificate` since that value should be the first certificate in the chain. - -type: keyword - -example: ["MII...", "MII..."] - --- - -*`tls.server.hash.md5`*:: -+ --- -Certificate fingerprint using the MD5 digest of DER-encoded version of certificate offered by the server. For consistency with other hash values, this value should be formatted as an uppercase hash. - -type: keyword - -example: 0F76C7F2C55BFD7D8E8B8F4BFBF0C9EC - --- - -*`tls.server.hash.sha1`*:: -+ --- -Certificate fingerprint using the SHA1 digest of DER-encoded version of certificate offered by the server. For consistency with other hash values, this value should be formatted as an uppercase hash. - -type: keyword - -example: 9E393D93138888D288266C2D915214D1D1CCEB2A - --- - -*`tls.server.hash.sha256`*:: -+ --- -Certificate fingerprint using the SHA256 digest of DER-encoded version of certificate offered by the server. For consistency with other hash values, this value should be formatted as an uppercase hash. - -type: keyword - -example: 0687F666A054EF17A08E2F2162EAB4CBC0D265E1D7875BE74BF3C712CA92DAF0 - --- - -*`tls.server.issuer`*:: -+ --- -Subject of the issuer of the x.509 certificate presented by the server. - -type: keyword - -example: CN=Example Root CA, OU=Infrastructure Team, DC=example, DC=com - --- - -*`tls.server.ja3s`*:: -+ --- -A hash that identifies servers based on how they perform an SSL/TLS handshake. - -type: keyword - -example: 394441ab65754e2207b1e1b457b3641d - --- - -*`tls.server.not_after`*:: -+ --- -Timestamp indicating when server certificate is no longer considered valid. - -type: date - -example: 2021-01-01T00:00:00.000Z - --- - -*`tls.server.not_before`*:: -+ --- -Timestamp indicating when server certificate is first considered valid. - -type: date - -example: 1970-01-01T00:00:00.000Z - --- - -*`tls.server.subject`*:: -+ --- -Subject of the x.509 certificate presented by the server. - -type: keyword - -example: CN=www.example.com, OU=Infrastructure Team, DC=example, DC=com - --- - -*`tls.server.x509.alternative_names`*:: -+ --- -List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses. - -type: keyword - -example: *.elastic.co - --- - -*`tls.server.x509.issuer.common_name`*:: -+ --- -List of common name (CN) of issuing certificate authority. - -type: keyword - -example: Example SHA2 High Assurance Server CA - --- - -*`tls.server.x509.issuer.country`*:: -+ --- -List of country (C) codes - -type: keyword - -example: US - --- - -*`tls.server.x509.issuer.distinguished_name`*:: -+ --- -Distinguished name (DN) of issuing certificate authority. - -type: keyword - -example: C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA - --- - -*`tls.server.x509.issuer.locality`*:: -+ --- -List of locality names (L) - -type: keyword - -example: Mountain View - --- - -*`tls.server.x509.issuer.organization`*:: -+ --- -List of organizations (O) of issuing certificate authority. - -type: keyword - -example: Example Inc - --- - -*`tls.server.x509.issuer.organizational_unit`*:: -+ --- -List of organizational units (OU) of issuing certificate authority. - -type: keyword - -example: www.example.com - --- - -*`tls.server.x509.issuer.state_or_province`*:: -+ --- -List of state or province names (ST, S, or P) - -type: keyword - -example: California - --- - -*`tls.server.x509.not_after`*:: -+ --- -Time at which the certificate is no longer considered valid. - -type: date - -example: 2020-07-16 03:15:39+00:00 - --- - -*`tls.server.x509.not_before`*:: -+ --- -Time at which the certificate is first considered valid. - -type: date - -example: 2019-08-16 01:40:25+00:00 - --- - -*`tls.server.x509.public_key_algorithm`*:: -+ --- -Algorithm used to generate the public key. - -type: keyword - -example: RSA - --- - -*`tls.server.x509.public_key_curve`*:: -+ --- -The curve used by the elliptic curve public key algorithm. This is algorithm specific. - -type: keyword - -example: nistp521 - --- - -*`tls.server.x509.public_key_exponent`*:: -+ --- -Exponent used to derive the public key. This is algorithm specific. - -type: long - -example: 65537 - -Field is not indexed. - --- - -*`tls.server.x509.public_key_size`*:: -+ --- -The size of the public key space in bits. - -type: long - -example: 2048 - --- - -*`tls.server.x509.serial_number`*:: -+ --- -Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters. - -type: keyword - -example: 55FBB9C7DEBF09809D12CCAA - --- - -*`tls.server.x509.signature_algorithm`*:: -+ --- -Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353. - -type: keyword - -example: SHA256-RSA - --- - -*`tls.server.x509.subject.common_name`*:: -+ --- -List of common names (CN) of subject. - -type: keyword - -example: shared.global.example.net - --- - -*`tls.server.x509.subject.country`*:: -+ --- -List of country (C) code - -type: keyword - -example: US - --- - -*`tls.server.x509.subject.distinguished_name`*:: -+ --- -Distinguished name (DN) of the certificate subject entity. - -type: keyword - -example: C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net - --- - -*`tls.server.x509.subject.locality`*:: -+ --- -List of locality names (L) - -type: keyword - -example: San Francisco - --- - -*`tls.server.x509.subject.organization`*:: -+ --- -List of organizations (O) of subject. - -type: keyword - -example: Example, Inc. - --- - -*`tls.server.x509.subject.organizational_unit`*:: -+ --- -List of organizational units (OU) of subject. - -type: keyword - --- - -*`tls.server.x509.subject.state_or_province`*:: -+ --- -List of state or province names (ST, S, or P) - -type: keyword - -example: California - --- - -*`tls.server.x509.version_number`*:: -+ --- -Version of x509 format. - -type: keyword - -example: 3 - --- - -*`tls.version`*:: -+ --- -Numeric part of the version parsed from the original string. - -type: keyword - -example: 1.2 - --- - -*`tls.version_protocol`*:: -+ --- -Normalized lowercase protocol name parsed from original string. - -type: keyword - -example: tls - --- - -*`span.id`*:: -+ --- -Unique identifier of the span within the scope of its trace. -A span represents an operation within a transaction, such as a request to another service, or a database query. - -type: keyword - -example: 3ff9a8981b7ccd5a - --- - -*`trace.id`*:: -+ --- -Unique identifier of the trace. -A trace groups multiple events like transactions that belong together. For example, a user request handled by multiple inter-connected services. - -type: keyword - -example: 4bf92f3577b34da6a3ce929d0e0e4736 - --- - -*`transaction.id`*:: -+ --- -Unique identifier of the transaction within the scope of its trace. -A transaction is the highest level of work measured within a service, such as a request to a server. - -type: keyword - -example: 00f067aa0ba902b7 - --- - -[float] -=== url - -URL fields provide support for complete or partial URLs, and supports the breaking down into scheme, domain, path, and so on. - - -*`url.domain`*:: -+ --- -Domain of the url, such as "www.elastic.co". -In some cases a URL may refer to an IP and/or port directly, without a domain name. In this case, the IP address would go to the `domain` field. -If the URL contains a literal IPv6 address enclosed by `[` and `]` (IETF RFC 2732), the `[` and `]` characters should also be captured in the `domain` field. - -type: keyword - -example: www.elastic.co - --- - -*`url.extension`*:: -+ --- -The field contains the file extension from the original request url, excluding the leading dot. -The file extension is only set if it exists, as not every url has a file extension. -The leading period must not be included. For example, the value must be "png", not ".png". -Note that when the file name has multiple extensions (example.tar.gz), only the last one should be captured ("gz", not "tar.gz"). - -type: keyword - -example: png - --- - -*`url.fragment`*:: -+ --- -Portion of the url after the `#`, such as "top". -The `#` is not part of the fragment. - -type: keyword - --- - -*`url.full`*:: -+ --- -If full URLs are important to your use case, they should be stored in `url.full`, whether this field is reconstructed or present in the event source. - -type: wildcard - -example: https://www.elastic.co:443/search?q=elasticsearch#top - --- - -*`url.full.text`*:: -+ --- -type: match_only_text - --- - -*`url.original`*:: -+ --- -Unmodified original url as seen in the event source. -Note that in network monitoring, the observed URL may be a full URL, whereas in access logs, the URL is often just represented as a path. -This field is meant to represent the URL as it was observed, complete or not. - -type: wildcard - -example: https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch - --- - -*`url.original.text`*:: -+ --- -type: match_only_text - --- - -*`url.password`*:: -+ --- -Password of the request. - -type: keyword - --- - -*`url.path`*:: -+ --- -Path of the request, such as "/search". - -type: wildcard - --- - -*`url.port`*:: -+ --- -Port of the request, such as 443. - -type: long - -example: 443 - -format: string - --- - -*`url.query`*:: -+ --- -The query field describes the query string of the request, such as "q=elasticsearch". -The `?` is excluded from the query string. If a URL contains no `?`, there is no query field. If there is a `?` but no query, the query field exists with an empty string. The `exists` query can be used to differentiate between the two cases. - -type: keyword - --- - -*`url.registered_domain`*:: -+ --- -The highest registered url domain, stripped of the subdomain. -For example, the registered domain for "foo.example.com" is "example.com". -This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk". - -type: keyword - -example: example.com - --- - -*`url.scheme`*:: -+ --- -Scheme of the request, such as "https". -Note: The `:` is not part of the scheme. - -type: keyword - -example: https - --- - -*`url.subdomain`*:: -+ --- -The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. -For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period. - -type: keyword - -example: east - --- - -*`url.top_level_domain`*:: -+ --- -The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". -This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk". - -type: keyword - -example: co.uk - --- - -*`url.username`*:: -+ --- -Username of the request. - -type: keyword - --- - -[float] -=== user - -The user fields describe information about the user that is relevant to the event. -Fields can have one entry or multiple entries. If a user has more than one id, provide an array that includes all of them. - - -*`user.changes.domain`*:: -+ --- -Name of the directory the user is a member of. -For example, an LDAP or Active Directory domain name. - -type: keyword - --- - -*`user.changes.email`*:: -+ --- -User email address. - -type: keyword - --- - -*`user.changes.full_name`*:: -+ --- -User's full name, if available. - -type: keyword - -example: Albert Einstein - --- - -*`user.changes.full_name.text`*:: -+ --- -type: match_only_text - --- - -*`user.changes.group.domain`*:: -+ --- -Name of the directory the group is a member of. -For example, an LDAP or Active Directory domain name. - -type: keyword - --- - -*`user.changes.group.id`*:: -+ --- -Unique identifier for the group on the system/platform. - -type: keyword - --- - -*`user.changes.group.name`*:: -+ --- -Name of the group. - -type: keyword - --- - -*`user.changes.hash`*:: -+ --- -Unique user hash to correlate information for a user in anonymized form. -Useful if `user.id` or `user.name` contain confidential information and cannot be used. - -type: keyword - --- - -*`user.changes.id`*:: -+ --- -Unique identifier of the user. - -type: keyword - -example: S-1-5-21-202424912787-2692429404-2351956786-1000 - --- - -*`user.changes.name`*:: -+ --- -Short name or login of the user. - -type: keyword - -example: a.einstein - --- - -*`user.changes.name.text`*:: -+ --- -type: match_only_text - --- - -*`user.changes.roles`*:: -+ --- -Array of user roles at the time of the event. - -type: keyword - -example: ["kibana_admin", "reporting_user"] - --- - -*`user.domain`*:: -+ --- -Name of the directory the user is a member of. -For example, an LDAP or Active Directory domain name. - -type: keyword - --- - -*`user.effective.domain`*:: -+ --- -Name of the directory the user is a member of. -For example, an LDAP or Active Directory domain name. - -type: keyword - --- - -*`user.effective.email`*:: -+ --- -User email address. - -type: keyword - --- - -*`user.effective.full_name`*:: -+ --- -User's full name, if available. - -type: keyword - -example: Albert Einstein - --- - -*`user.effective.full_name.text`*:: -+ --- -type: match_only_text - --- - -*`user.effective.group.domain`*:: -+ --- -Name of the directory the group is a member of. -For example, an LDAP or Active Directory domain name. - -type: keyword - --- - -*`user.effective.group.id`*:: -+ --- -Unique identifier for the group on the system/platform. - -type: keyword - --- - -*`user.effective.group.name`*:: -+ --- -Name of the group. - -type: keyword - --- - -*`user.effective.hash`*:: -+ --- -Unique user hash to correlate information for a user in anonymized form. -Useful if `user.id` or `user.name` contain confidential information and cannot be used. - -type: keyword - --- - -*`user.effective.id`*:: -+ --- -Unique identifier of the user. - -type: keyword - -example: S-1-5-21-202424912787-2692429404-2351956786-1000 - --- - -*`user.effective.name`*:: -+ --- -Short name or login of the user. - -type: keyword - -example: a.einstein - --- - -*`user.effective.name.text`*:: -+ --- -type: match_only_text - --- - -*`user.effective.roles`*:: -+ --- -Array of user roles at the time of the event. - -type: keyword - -example: ["kibana_admin", "reporting_user"] - --- - -*`user.email`*:: -+ --- -User email address. - -type: keyword - --- - -*`user.full_name`*:: -+ --- -User's full name, if available. - -type: keyword - -example: Albert Einstein - --- - -*`user.full_name.text`*:: -+ --- -type: match_only_text - --- - -*`user.group.domain`*:: -+ --- -Name of the directory the group is a member of. -For example, an LDAP or Active Directory domain name. - -type: keyword - --- - -*`user.group.id`*:: -+ --- -Unique identifier for the group on the system/platform. - -type: keyword - --- - -*`user.group.name`*:: -+ --- -Name of the group. - -type: keyword - --- - -*`user.hash`*:: -+ --- -Unique user hash to correlate information for a user in anonymized form. -Useful if `user.id` or `user.name` contain confidential information and cannot be used. - -type: keyword - --- - -*`user.id`*:: -+ --- -Unique identifier of the user. - -type: keyword - -example: S-1-5-21-202424912787-2692429404-2351956786-1000 - --- - -*`user.name`*:: -+ --- -Short name or login of the user. - -type: keyword - -example: a.einstein - --- - -*`user.name.text`*:: -+ --- -type: match_only_text - --- - -*`user.roles`*:: -+ --- -Array of user roles at the time of the event. - -type: keyword - -example: ["kibana_admin", "reporting_user"] - --- - -*`user.target.domain`*:: -+ --- -Name of the directory the user is a member of. -For example, an LDAP or Active Directory domain name. - -type: keyword - --- - -*`user.target.email`*:: -+ --- -User email address. - -type: keyword - --- - -*`user.target.full_name`*:: -+ --- -User's full name, if available. - -type: keyword - -example: Albert Einstein - --- - -*`user.target.full_name.text`*:: -+ --- -type: match_only_text - --- - -*`user.target.group.domain`*:: -+ --- -Name of the directory the group is a member of. -For example, an LDAP or Active Directory domain name. - -type: keyword - --- - -*`user.target.group.id`*:: -+ --- -Unique identifier for the group on the system/platform. - -type: keyword - --- - -*`user.target.group.name`*:: -+ --- -Name of the group. - -type: keyword - --- - -*`user.target.hash`*:: -+ --- -Unique user hash to correlate information for a user in anonymized form. -Useful if `user.id` or `user.name` contain confidential information and cannot be used. - -type: keyword - --- - -*`user.target.id`*:: -+ --- -Unique identifier of the user. - -type: keyword - -example: S-1-5-21-202424912787-2692429404-2351956786-1000 - --- - -*`user.target.name`*:: -+ --- -Short name or login of the user. - -type: keyword - -example: a.einstein - --- - -*`user.target.name.text`*:: -+ --- -type: match_only_text - --- - -*`user.target.roles`*:: -+ --- -Array of user roles at the time of the event. - -type: keyword - -example: ["kibana_admin", "reporting_user"] - --- - -[float] -=== user_agent - -The user_agent fields normally come from a browser request. -They often show up in web service logs coming from the parsed user agent string. - - -*`user_agent.device.name`*:: -+ --- -Name of the device. - -type: keyword - -example: iPhone - --- - -*`user_agent.name`*:: -+ --- -Name of the user agent. - -type: keyword - -example: Safari - --- - -*`user_agent.original`*:: -+ --- -Unparsed user_agent string. - -type: keyword - -example: Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1 - --- - -*`user_agent.original.text`*:: -+ --- -type: match_only_text - --- - -*`user_agent.os.family`*:: -+ --- -OS family (such as redhat, debian, freebsd, windows). - -type: keyword - -example: debian - --- - -*`user_agent.os.full`*:: -+ --- -Operating system name, including the version or code name. - -type: keyword - -example: Mac OS Mojave - --- - -*`user_agent.os.full.text`*:: -+ --- -type: match_only_text - --- - -*`user_agent.os.kernel`*:: -+ --- -Operating system kernel version as a raw string. - -type: keyword - -example: 4.4.0-112-generic - --- - -*`user_agent.os.name`*:: -+ --- -Operating system name, without the version. - -type: keyword - -example: Mac OS X - --- - -*`user_agent.os.name.text`*:: -+ --- -type: match_only_text - --- - -*`user_agent.os.platform`*:: -+ --- -Operating system platform (such centos, ubuntu, windows). - -type: keyword - -example: darwin - --- - -*`user_agent.os.type`*:: -+ --- -Use the `os.type` field to categorize the operating system into one of the broad commercial families. -One of these following values should be used (lowercase): linux, macos, unix, windows. -If the OS you're dealing with is not in the list, the field should not be populated. Please let us know by opening an issue with ECS, to propose its addition. - -type: keyword - -example: macos - --- - -*`user_agent.os.version`*:: -+ --- -Operating system version as a raw string. - -type: keyword - -example: 10.14.1 - --- - -*`user_agent.version`*:: -+ --- -Version of the user agent. - -type: keyword - -example: 12.0 - --- - -[float] -=== vlan - -The VLAN fields are used to identify 802.1q tag(s) of a packet, as well as ingress and egress VLAN associations of an observer in relation to a specific packet or connection. -Network.vlan fields are used to record a single VLAN tag, or the outer tag in the case of q-in-q encapsulations, for a packet or connection as observed, typically provided by a network sensor (e.g. Zeek, Wireshark) passively reporting on traffic. -Network.inner VLAN fields are used to report inner q-in-q 802.1q tags (multiple 802.1q encapsulations) as observed, typically provided by a network sensor (e.g. Zeek, Wireshark) passively reporting on traffic. Network.inner VLAN fields should only be used in addition to network.vlan fields to indicate q-in-q tagging. -Observer.ingress and observer.egress VLAN values are used to record observer specific information when observer events contain discrete ingress and egress VLAN information, typically provided by firewalls, routers, or load balancers. - - -*`vlan.id`*:: -+ --- -VLAN ID as reported by the observer. - -type: keyword - -example: 10 - --- - -*`vlan.name`*:: -+ --- -Optional VLAN name as reported by the observer. - -type: keyword - -example: outside - --- - -[float] -=== vulnerability - -The vulnerability fields describe information about a vulnerability that is relevant to an event. - - -*`vulnerability.category`*:: -+ --- -The type of system or architecture that the vulnerability affects. These may be platform-specific (for example, Debian or SUSE) or general (for example, Database or Firewall). For example (https://qualysguard.qualys.com/qwebhelp/fo_portal/knowledgebase/vulnerability_categories.htm[Qualys vulnerability categories]) -This field must be an array. - -type: keyword - -example: ["Firewall"] - --- - -*`vulnerability.classification`*:: -+ --- -The classification of the vulnerability scoring system. For example (https://www.first.org/cvss/) - -type: keyword - -example: CVSS - --- - -*`vulnerability.description`*:: -+ --- -The description of the vulnerability that provides additional context of the vulnerability. For example (https://cve.mitre.org/about/faqs.html#cve_entry_descriptions_created[Common Vulnerabilities and Exposure CVE description]) - -type: keyword - -example: In macOS before 2.12.6, there is a vulnerability in the RPC... - --- - -*`vulnerability.description.text`*:: -+ --- -type: match_only_text - --- - -*`vulnerability.enumeration`*:: -+ --- -The type of identifier used for this vulnerability. For example (https://cve.mitre.org/about/) - -type: keyword - -example: CVE - --- - -*`vulnerability.id`*:: -+ --- -The identification (ID) is the number portion of a vulnerability entry. It includes a unique identification number for the vulnerability. For example (https://cve.mitre.org/about/faqs.html#what_is_cve_id)[Common Vulnerabilities and Exposure CVE ID] - -type: keyword - -example: CVE-2019-00001 - --- - -*`vulnerability.reference`*:: -+ --- -A resource that provides additional information, context, and mitigations for the identified vulnerability. - -type: keyword - -example: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-6111 - --- - -*`vulnerability.report_id`*:: -+ --- -The report or scan identification number. - -type: keyword - -example: 20191018.0001 - --- - -*`vulnerability.scanner.vendor`*:: -+ --- -The name of the vulnerability scanner vendor. - -type: keyword - -example: Tenable - --- - -*`vulnerability.score.base`*:: -+ --- -Scores can range from 0.0 to 10.0, with 10.0 being the most severe. -Base scores cover an assessment for exploitability metrics (attack vector, complexity, privileges, and user interaction), impact metrics (confidentiality, integrity, and availability), and scope. For example (https://www.first.org/cvss/specification-document) - -type: float - -example: 5.5 - --- - -*`vulnerability.score.environmental`*:: -+ --- -Scores can range from 0.0 to 10.0, with 10.0 being the most severe. -Environmental scores cover an assessment for any modified Base metrics, confidentiality, integrity, and availability requirements. For example (https://www.first.org/cvss/specification-document) - -type: float - -example: 5.5 - --- - -*`vulnerability.score.temporal`*:: -+ --- -Scores can range from 0.0 to 10.0, with 10.0 being the most severe. -Temporal scores cover an assessment for code maturity, remediation level, and confidence. For example (https://www.first.org/cvss/specification-document) - -type: float - --- - -*`vulnerability.score.version`*:: -+ --- -The National Vulnerability Database (NVD) provides qualitative severity rankings of "Low", "Medium", and "High" for CVSS v2.0 base score ranges in addition to the severity ratings for CVSS v3.0 as they are defined in the CVSS v3.0 specification. -CVSS is owned and managed by FIRST.Org, Inc. (FIRST), a US-based non-profit organization, whose mission is to help computer security incident response teams across the world. For example (https://nvd.nist.gov/vuln-metrics/cvss) - -type: keyword - -example: 2.0 - --- - -*`vulnerability.severity`*:: -+ --- -The severity of the vulnerability can help with metrics and internal prioritization regarding remediation. For example (https://nvd.nist.gov/vuln-metrics/cvss) - -type: keyword - -example: Critical - --- - -[float] -=== x509 - -This implements the common core fields for x509 certificates. This information is likely logged with TLS sessions, digital signatures found in executable binaries, S/MIME information in email bodies, or analysis of files on disk. -When the certificate relates to a file, use the fields at `file.x509`. When hashes of the DER-encoded certificate are available, the `hash` data set should be populated as well (e.g. `file.hash.sha256`). -Events that contain certificate information about network connections, should use the x509 fields under the relevant TLS fields: `tls.server.x509` and/or `tls.client.x509`. - - -*`x509.alternative_names`*:: -+ --- -List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses. - -type: keyword - -example: *.elastic.co - --- - -*`x509.issuer.common_name`*:: -+ --- -List of common name (CN) of issuing certificate authority. - -type: keyword - -example: Example SHA2 High Assurance Server CA - --- - -*`x509.issuer.country`*:: -+ --- -List of country (C) codes - -type: keyword - -example: US - --- - -*`x509.issuer.distinguished_name`*:: -+ --- -Distinguished name (DN) of issuing certificate authority. - -type: keyword - -example: C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA - --- - -*`x509.issuer.locality`*:: -+ --- -List of locality names (L) - -type: keyword - -example: Mountain View - --- - -*`x509.issuer.organization`*:: -+ --- -List of organizations (O) of issuing certificate authority. - -type: keyword - -example: Example Inc - --- - -*`x509.issuer.organizational_unit`*:: -+ --- -List of organizational units (OU) of issuing certificate authority. - -type: keyword - -example: www.example.com - --- - -*`x509.issuer.state_or_province`*:: -+ --- -List of state or province names (ST, S, or P) - -type: keyword - -example: California - --- - -*`x509.not_after`*:: -+ --- -Time at which the certificate is no longer considered valid. - -type: date - -example: 2020-07-16 03:15:39+00:00 - --- - -*`x509.not_before`*:: -+ --- -Time at which the certificate is first considered valid. - -type: date - -example: 2019-08-16 01:40:25+00:00 - --- - -*`x509.public_key_algorithm`*:: -+ --- -Algorithm used to generate the public key. - -type: keyword - -example: RSA - --- - -*`x509.public_key_curve`*:: -+ --- -The curve used by the elliptic curve public key algorithm. This is algorithm specific. - -type: keyword - -example: nistp521 - --- - -*`x509.public_key_exponent`*:: -+ --- -Exponent used to derive the public key. This is algorithm specific. - -type: long - -example: 65537 - -Field is not indexed. - --- - -*`x509.public_key_size`*:: -+ --- -The size of the public key space in bits. - -type: long - -example: 2048 - --- - -*`x509.serial_number`*:: -+ --- -Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters. - -type: keyword - -example: 55FBB9C7DEBF09809D12CCAA - --- - -*`x509.signature_algorithm`*:: -+ --- -Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353. - -type: keyword - -example: SHA256-RSA - --- - -*`x509.subject.common_name`*:: -+ --- -List of common names (CN) of subject. - -type: keyword - -example: shared.global.example.net - --- - -*`x509.subject.country`*:: -+ --- -List of country (C) code - -type: keyword - -example: US - --- - -*`x509.subject.distinguished_name`*:: -+ --- -Distinguished name (DN) of the certificate subject entity. - -type: keyword - -example: C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net - --- - -*`x509.subject.locality`*:: -+ --- -List of locality names (L) - -type: keyword - -example: San Francisco - --- - -*`x509.subject.organization`*:: -+ --- -List of organizations (O) of subject. - -type: keyword - -example: Example, Inc. - --- - -*`x509.subject.organizational_unit`*:: -+ --- -List of organizational units (OU) of subject. - -type: keyword - --- - -*`x509.subject.state_or_province`*:: -+ --- -List of state or province names (ST, S, or P) - -type: keyword - -example: California - --- - -*`x509.version_number`*:: -+ --- -Version of x509 format. - -type: keyword - -example: 3 - --- - -[[exported-fields-functionbeat]] -== Functionbeat fields - -None - -[[exported-fields-host-processor]] -== Host fields - -Info collected for the host machine. - - - - -*`host.containerized`*:: -+ --- -If the host is a container. - - -type: boolean - --- - -*`host.os.build`*:: -+ --- -OS build information. - - -type: keyword - -example: 18D109 - --- - -*`host.os.codename`*:: -+ --- -OS codename, if any. - - -type: keyword - -example: stretch - --- - -[[exported-fields-jolokia-autodiscover]] -== Jolokia Discovery autodiscover provider fields - -Metadata from Jolokia Discovery added by the jolokia provider. - - - -*`jolokia.agent.version`*:: -+ --- -Version number of jolokia agent. - - -type: keyword - --- - -*`jolokia.agent.id`*:: -+ --- -Each agent has a unique id which can be either provided during startup of the agent in form of a configuration parameter or being autodetected. If autodected, the id has several parts: The IP, the process id, hashcode of the agent and its type. - - -type: keyword - --- - -*`jolokia.server.product`*:: -+ --- -The container product if detected. - - -type: keyword - --- - -*`jolokia.server.version`*:: -+ --- -The container's version (if detected). - - -type: keyword - --- - -*`jolokia.server.vendor`*:: -+ --- -The vendor of the container the agent is running in. - - -type: keyword - --- - -*`jolokia.url`*:: -+ --- -The URL how this agent can be contacted. - - -type: keyword - --- - -*`jolokia.secured`*:: -+ --- -Whether the agent was configured for authentication or not. - - -type: boolean - --- - -[[exported-fields-kubernetes-processor]] -== Kubernetes fields - -Kubernetes metadata added by the kubernetes processor - - - - -*`kubernetes.pod.name`*:: -+ --- -Kubernetes pod name - - -type: keyword - --- - -*`kubernetes.pod.uid`*:: -+ --- -Kubernetes Pod UID - - -type: keyword - --- - -*`kubernetes.pod.ip`*:: -+ --- -Kubernetes Pod IP - - -type: ip - --- - -*`kubernetes.namespace`*:: -+ --- -Kubernetes namespace - - -type: keyword - --- - -*`kubernetes.node.name`*:: -+ --- -Kubernetes node name - - -type: keyword - --- - -*`kubernetes.node.hostname`*:: -+ --- -Kubernetes hostname as reported by the node’s kernel - - -type: keyword - --- - -*`kubernetes.labels.*`*:: -+ --- -Kubernetes labels map - - -type: object - --- - -*`kubernetes.annotations.*`*:: -+ --- -Kubernetes annotations map - - -type: object - --- - -*`kubernetes.selectors.*`*:: -+ --- -Kubernetes selectors map - - -type: object - --- - -*`kubernetes.replicaset.name`*:: -+ --- -Kubernetes replicaset name - - -type: keyword - --- - -*`kubernetes.deployment.name`*:: -+ --- -Kubernetes deployment name - - -type: keyword - --- - -*`kubernetes.statefulset.name`*:: -+ --- -Kubernetes statefulset name - - -type: keyword - --- - -*`kubernetes.container.name`*:: -+ --- -Kubernetes container name (different than the name from the runtime) - - -type: keyword - --- - -[[exported-fields-process]] -== Process fields - -Process metadata fields - - - - -*`process.exe`*:: -+ --- -type: alias - -alias to: process.executable - --- - -[float] -=== owner - -Process owner information. - - -*`process.owner.id`*:: -+ --- -Unique identifier of the user. - -type: keyword - --- - -*`process.owner.name`*:: -+ --- -Short name or login of the user. - -type: keyword - -example: albert - --- - -*`process.owner.name.text`*:: -+ --- -type: text - --- - -:edit_url!: \ No newline at end of file diff --git a/x-pack/functionbeat/docs/filtering.asciidoc b/x-pack/functionbeat/docs/filtering.asciidoc deleted file mode 100644 index c22366c0ee7a..000000000000 --- a/x-pack/functionbeat/docs/filtering.asciidoc +++ /dev/null @@ -1,30 +0,0 @@ -[[filtering-and-enhancing-data]] -[role="xpack"] -== Filter and enhance data with processors - -++++ -Processors -++++ - -Your use case might require only a subset of the data exported by {beatname_uc}, -or you might need to enhance the exported data (for example, by adding -metadata). {beatname_uc} provides a couple of options for filtering and -enhancing exported data. - -You can specify a <<{beatname_lc}-filter_pattern,`filter_pattern`>> to match the -data you want to send. This approach may reduce execution costs because the -function running {beatname_uc} only executes if there is data that matches the -pattern. - -Another approach (the one described here) is to define processors. - - -[float] -[[using-processors]] -=== Processors - -include::{libbeat-dir}/processors.asciidoc[] - -:processor-scope: function -include::{libbeat-dir}/processors-using.asciidoc[] -:processor-scope!: diff --git a/x-pack/functionbeat/docs/general-options.asciidoc b/x-pack/functionbeat/docs/general-options.asciidoc deleted file mode 100644 index 5b21951bcfd9..000000000000 --- a/x-pack/functionbeat/docs/general-options.asciidoc +++ /dev/null @@ -1,13 +0,0 @@ -[[configuration-general-options]] -[role="xpack"] -== Configure general settings - -++++ -General settings -++++ - -You can specify settings in the +{beatname_lc}.yml+ config file to control the -general behavior of {beatname_uc}. - -include::{libbeat-dir}/generalconfig.asciidoc[] - diff --git a/x-pack/functionbeat/docs/getting-started.asciidoc b/x-pack/functionbeat/docs/getting-started.asciidoc deleted file mode 100644 index adbf4ec67174..000000000000 --- a/x-pack/functionbeat/docs/getting-started.asciidoc +++ /dev/null @@ -1,167 +0,0 @@ -[id="{beatname_lc}-installation-configuration"] -[role="xpack"] -== {beatname_uc} quick start: installation and configuration - -++++ -Quick start: installation and configuration -++++ - -This guide describes how to get started quickly monitoring data from your cloud -services. You'll learn how to: - - -* download the {beatname_uc} distribution -* configure details about the cloud functions you want to deploy, including the -services to monitor and triggers -* deploy the cloud functions to your serverless environment -* collect data from cloud services and ship it to the {stack} -* visualize the data in {kib} - -[float] -[[install]] -=== Step 1: Download {beatname_uc} - -The {beatname_uc} distribution contains the command line tools, configuration -file, and binary code required to run {beatname_uc} in your serverless -environment. - -To download and extract the package, use the commands that work with your -system. - -include::{libbeat-dir}/tab-widgets/install-linux-mac-win-short-widget.asciidoc[] - -The commands shown are for AMD platforms, but ARM packages are also available. -Refer to the https://www.elastic.co/downloads/beats/{beatname_lc}[download page] -for the full list of available packages. - -[float] -[[set-connection]] -=== Step 2: Connect to the {stack} - -include::{libbeat-dir}/shared/connecting-to-es.asciidoc[] - -[float] -[[configuration]] -=== Step 3: Configure cloud functions - -Before deploying {beatname_uc} to your cloud provider, you need to specify -details about the cloud functions that you want to deploy, including the -function name and type, and the triggers that will cause the function to -execute. - -In +{beatname_lc}.yml+, configure the functions that you want to deploy. The -configuration settings vary depending on the type of function and cloud provider -you're using. This section provides a an AWS example configuration. - -This example configures a function called `cloudwatch` that collects events from -CloudWatch Logs. When a message is sent to the specified log group, the cloud -function executes and sends message events to the configured output: - -["source","sh",subs="attributes"] -------------------------------------------------------------------------------------- -{beatname_lc}.provider.aws.endpoint: "s3.amazonaws.com" -{beatname_lc}.provider.aws.deploy_bucket: "functionbeat-deploy" <1> -{beatname_lc}.provider.aws.functions: - - name: cloudwatch <2> - enabled: true - type: cloudwatch_logs - description: "lambda function for cloudwatch logs" - triggers: - - log_group_name: /aws/lambda/my-lambda-function -------------------------------------------------------------------------------------- -<1> A unique name for the S3 bucket to which the functions will be -uploaded. -<2> Details about the function you want to deploy, including the name of the -function, the type of service to monitor, and the log groups that trigger the -function. - -See <> for more examples. - -include::{libbeat-dir}/shared/config-check.asciidoc[] - -[float] -[[setup-assets]] -=== Step 4: Set up assets - -{beatname_uc} comes with predefined assets for parsing, indexing, and -visualizing your data. To load these assets: - -. Make sure the user specified in +{beatname_lc}.yml+ is -<>. - -. From the installation directory, run: -+ --- -include::{libbeat-dir}/tab-widgets/setup-linux-mac-win-widget.asciidoc[] --- -+ -`-e` is optional and sends output to standard error instead of the configured log output. - -This step loads the recommended {ref}/index-templates.html[index template] for writing to {es}. - -[TIP] -===== -A connection to {es} (or {ess}) is required to set up the initial -environment. If you're using a different output, such as {ls}, see -<>. -===== - -[float] -[id="{beatname_lc}-deploying"] -[role="xpack"] -=== Step 5: Deploy {beatname_uc} - -To deploy {beatname_uc} functions to your cloud provider, either use the -{beatname_uc} manager, as described here, or <>. - -TIP: If you change the configuration after deploying the function, use -the <> to update your deployment. - -[float] -[[deploy-to-aws]] -==== Deploy to AWS - -. Make sure you have the credentials required to authenticate with AWS. You can -set environment variables that contain your credentials: -+ --- -include::tab-widgets/credentials-aws-widget.asciidoc[] --- -+ -Set `AWS_DEFAULT_REGION` to the region where your services are running. - -. Make sure the user has the permissions required to deploy and run the -function. For more information, see <>. - -. Deploy the cloud functions. -+ -For example, the following command deploys a function called `cloudwatch`: -+ --- -include::tab-widgets/deploy-aws-widget.asciidoc[] --- -+ -The function is deployed to AWS and ready to send log events to the configured -output. -+ -If deployment fails, see <> for help troubleshooting. - -:fnexample!: - -[float] -[[view-data]] -=== Step 6: View your data in {kib} - -There are currently no example dashboards available for {beatname_uc}. - -To learn how to view and explore your data, see the -_{kibana-ref}/index.html[{kib} User Guide]_. - -[float] -=== What's next? - -Now that you have your cloud data streaming into {es}, learn how to unify your -logs, metrics, uptime, and application performance data. - -include::{libbeat-dir}/shared/obs-apps.asciidoc[] diff --git a/x-pack/functionbeat/docs/howto/howto.asciidoc b/x-pack/functionbeat/docs/howto/howto.asciidoc deleted file mode 100644 index f116bc57d0c2..000000000000 --- a/x-pack/functionbeat/docs/howto/howto.asciidoc +++ /dev/null @@ -1,42 +0,0 @@ -[[howto-guides]] -[role="xpack"] -= How to guides - -[partintro] --- -Learn how to perform common {beatname_uc} configuration tasks. - -* <<{beatname_lc}-template>> -* <> -* <<{beatname_lc}-geoip>> -* <> -* <> -* <> - - --- - -[role="xpack"] -include::{libbeat-dir}/howto/load-index-templates.asciidoc[] - -[role="xpack"] -include::{libbeat-dir}/howto/change-index-name.asciidoc[] - -[role="xpack"] -include::{libbeat-dir}/shared-geoip.asciidoc[] - -:standalone: -[role="xpack"] -include::{libbeat-dir}/shared-env-vars.asciidoc[] -:standalone!: - -[role="xpack"] -include::{libbeat-dir}/shared-config-ingest.asciidoc[] - -:standalone: -[role="xpack"] -include::{libbeat-dir}/yaml.asciidoc[] -:standalone!: - - - diff --git a/x-pack/functionbeat/docs/iam-permissions.asciidoc b/x-pack/functionbeat/docs/iam-permissions.asciidoc deleted file mode 100644 index 606f3c792392..000000000000 --- a/x-pack/functionbeat/docs/iam-permissions.asciidoc +++ /dev/null @@ -1,134 +0,0 @@ -[[iam-permissions]] -[role="xpack"] -=== IAM permissions required to deploy {beatname_uc} - -++++ -IAM permissions required for deployment -++++ - -This section describes the minimum privileges or roles required to deploy -functions to your cloud provider. - -[[iam-permissions-aws]] -==== Permissions required by AWS - -The list of required permissions depends on the type of events that you are -collecting. Here are some example policies that grant the required privileges. - -[[iam-permissions-cloudwatch]] -===== CloudWatch logs - -The following policy grants the permissions required to deploy and run a Lambda -function that collects events from CloudWatch logs. - -[source,yaml] ----- -{ - "Version": "2012-10-17", - "Statement": [ - { - "Sid": "VisualEditor0", - "Effect": "Allow", - "Action": [ - "cloudformation:CreateStack", - "cloudformation:DeleteStack", - "cloudformation:DescribeStacks", - "cloudformation:DescribeStackEvents", - "cloudformation:DescribeStackResources", - "cloudformation:GetTemplate", - "cloudformation:UpdateStack", - "cloudformation:ValidateTemplate", - "iam:CreateRole", - "iam:DeleteRole", - "iam:DeleteRolePolicy", - "iam:GetRole", - "iam:GetRolePolicy", - "iam:PassRole", - "iam:PutRolePolicy", - "lambda:AddPermission", - "lambda:CreateFunction", - "lambda:DeleteFunction", - "lambda:GetFunction", - "lambda:GetFunctionConfiguration", - "lambda:PutFunctionConcurrency", - "lambda:RemovePermission", - "lambda:UpdateFunctionCode", - "lambda:UpdateFunctionConfiguration", - "logs:CreateLogGroup", - "logs:DeleteLogGroup", - "logs:DeleteSubscriptionFilter", - "logs:DescribeLogGroups", - "logs:PutSubscriptionFilter", - "s3:CreateBucket", - "s3:DeleteObject", - "s3:ListBucket", - "s3:PutObject", - "s3:GetObject", - "ec2:DescribeSecurityGroups", - "ec2:DescribeSubnets", - "ec2:DescribeVpcs" - ], - "Resource": "*" - } - ] -} ----- - -[[iam-permissions-sqs-kinesis]] -===== SQS and Kinesis - -The following policy grants the permissions required to deploy and run a Lambda -function that reads from SQS queues or Kinesis data streams. - -[source,yaml] ----- -{ - "Version": "2012-10-17", - "Statement": [ - { - "Sid": "VisualEditor0", - "Effect": "Allow", - "Action": [ - "cloudformation:CreateStack", - "cloudformation:DeleteStack", - "cloudformation:DescribeStacks", - "cloudformation:DescribeStackEvents", - "cloudformation:DescribeStackResources", - "cloudformation:GetTemplate", - "cloudformation:UpdateStack", - "cloudformation:ValidateTemplate", - "iam:CreateRole", - "iam:DeleteRole", - "iam:DeleteRolePolicy", - "iam:GetRole", - "iam:GetRolePolicy", - "iam:PassRole", - "iam:PutRolePolicy", - "lambda:AddPermission", - "lambda:CreateFunction", - "lambda:CreateEventSourceMapping", - "lambda:DeleteFunction", - "lambda:DeleteEventSourceMapping", - "lambda:GetEventSourceMapping", - "lambda:GetFunction", - "lambda:GetFunctionConfiguration", - "lambda:PutFunctionConcurrency", - "lambda:RemovePermission", - "lambda:UpdateFunctionCode", - "lambda:UpdateFunctionConfiguration", - "logs:DescribeLogGroups", - "logs:CreateLogGroup", - "s3:CreateBucket", - "s3:DeleteObject", - "s3:ListBucket", - "s3:PutObject", - "s3:GetObject", - "ec2:DescribeSecurityGroups", - "ec2:DescribeSubnets", - "ec2:DescribeVpcs" - ], - "Resource": "*" - } - ] -} ----- diff --git a/x-pack/functionbeat/docs/images/coordinate-map.png b/x-pack/functionbeat/docs/images/coordinate-map.png deleted file mode 100644 index 8ac69fe747cf..000000000000 Binary files a/x-pack/functionbeat/docs/images/coordinate-map.png and /dev/null differ diff --git a/x-pack/functionbeat/docs/images/diagram-functionbeat-architecture.svg b/x-pack/functionbeat/docs/images/diagram-functionbeat-architecture.svg deleted file mode 100644 index f6d973d35fb2..000000000000 --- a/x-pack/functionbeat/docs/images/diagram-functionbeat-architecture.svg +++ /dev/null @@ -1,568 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/x-pack/functionbeat/docs/images/functionbeat-pipeline-cloudwatchlogs.png b/x-pack/functionbeat/docs/images/functionbeat-pipeline-cloudwatchlogs.png deleted file mode 100644 index d020044eb98a..000000000000 Binary files a/x-pack/functionbeat/docs/images/functionbeat-pipeline-cloudwatchlogs.png and /dev/null differ diff --git a/x-pack/functionbeat/docs/images/functionbeat-pipeline-sqs.png b/x-pack/functionbeat/docs/images/functionbeat-pipeline-sqs.png deleted file mode 100644 index 85ce2764369e..000000000000 Binary files a/x-pack/functionbeat/docs/images/functionbeat-pipeline-sqs.png and /dev/null differ diff --git a/x-pack/functionbeat/docs/index.asciidoc b/x-pack/functionbeat/docs/index.asciidoc deleted file mode 100644 index 3ab8578a0bc2..000000000000 --- a/x-pack/functionbeat/docs/index.asciidoc +++ /dev/null @@ -1,64 +0,0 @@ -= Functionbeat Reference - -:libbeat-dir: {docdir}/../../../libbeat/docs - -include::{libbeat-dir}/version.asciidoc[] - -include::{asciidoc-dir}/../../shared/versions/stack/{source_branch}.asciidoc[] - -include::{asciidoc-dir}/../../shared/attributes.asciidoc[] - -:beatname_lc: functionbeat -:beatname_uc: Functionbeat -:beatname_pkg: {beatname_lc} -:github_repo_name: beats -:discuss_forum: beats/{beatname_lc} -:beat_default_index_prefix: {beatname_lc} -:has_ml_jobs: no -:libbeat-docs: Beats Platform Reference -:cloudformation-ref: https://aws.amazon.com/cloudformation/[AWS CloudFormation] -:no_kafka_output: -:no_redis_output: -:no_file_output: -:requires_xpack: -:serverless: -:mac_os: -:win_os: -:linux_os: -:no_cache_processor: -:no_dashboards: -:no_repos: -:no_decode_cef_processor: -:no_decode_csv_fields_processor: -:no_parse_aws_vpc_flow_log_processor: -:no_script_processor: -:no_timestamp_processor: -:no_keystore: -:no_add_session_metadata_processor: - -include::{libbeat-dir}/shared-beats-attributes.asciidoc[] - -include::./overview.asciidoc[] - -include::./getting-started.asciidoc[] - -include::./setting-up-running.asciidoc[] - -include::./configuring-howto.asciidoc[] - -include::{docdir}/howto/howto.asciidoc[] - -[role="xpack"] -include::./fields.asciidoc[] - -[role="xpack"] -include::{libbeat-dir}/monitoring/monitoring-beats.asciidoc[] - -[role="xpack"] -include::{libbeat-dir}/shared-securing-beat.asciidoc[] - -include::./troubleshooting.asciidoc[] - -include::./faq.asciidoc[] - - diff --git a/x-pack/functionbeat/docs/overview.asciidoc b/x-pack/functionbeat/docs/overview.asciidoc deleted file mode 100644 index 456b9795ce7a..000000000000 --- a/x-pack/functionbeat/docs/overview.asciidoc +++ /dev/null @@ -1,99 +0,0 @@ -[id="{beatname_lc}-overview"] -[role="xpack"] -== {beatname_uc} overview - -IMPORTANT: Beginning with version 8.10.4 the {beatname_uc} documentation is no longer being updated. -We recommend instead to use {esf-ref}[{esf}] to ships logs from your AWS environment to Elastic. - -{beatname_uc} is an Elastic https://www.elastic.co/beats[Beat] that you -deploy as a function in your serverless environment to collect data from cloud -services and ship it to the {stack}. - -Version {version} supports deploying {beatname_uc} as an AWS Lambda service. It -responds to triggers defined for the following event sources: - -* https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/WhatIsCloudWatchLogs.html[Amazon CloudWatch Logs] -* https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/welcome.html[Amazon Simple Queue Service (SQS)] -* https://docs.aws.amazon.com/kinesis/latest/APIReference/Welcome.html[Amazon Kinesis] - -image::./images/diagram-functionbeat-architecture.svg["{beatname_uc} collects events generated by cloud services"] - -include::{libbeat-dir}/shared-libbeat-description.asciidoc[] - -The following sections explore some common use cases for {beatname_uc}: - -* <> -* <> - -*Want to ship logs from Google Cloud?* Use our Google Cloud Dataflow templates -to ship Google Pub/Sub and Google Cloud Storage logs directly from the Google -Cloud Console. To learn more, refer to -{observability-guide}/gcp-dataflow.html[GCP Dataflow templates]. - -[float] -[[monitor-cloud-deployments]] -=== Monitor cloud deployments - -You can deploy {beatname_uc} on your serverless environment to collect logs and -metrics generated by cloud services and stream the data to the {stack} for -centralized analytics. - -[float] -==== Monitor AWS services with CloudWatch logs - -You can deploy {beatname_uc} as a Lambda function on AWS to receive events from -a Cloudwatch Log group, extract and structure the relevant fields, then stream -the events to {es}. - -The processing pipeline for this use case typically looks like this: - -. {beatname_uc} runs as a Lambda function on AWS and reads the data stream from -a Cloudwatch Log group. - -. {beats} processors, such as <> and <>, -filter and structure the events. - -. Optional {ref}/ingest.html[ingest pipelines] in {es} further enhance the -data. - -. The structured events are indexed into an {es} cluster. - -image::./images/functionbeat-pipeline-cloudwatchlogs.png["{beatname_uc} collects events generated by CloudWatch logs"] - -///// -The following is commented out until this architecture is fully enabled: -If you have multiple instances of CloudWatch logs and want to centralize your -logging environment in Amazon Kinesis, you can send the logs to Kinesis, then -use {beatname_uc} to receive events from Kinesis, process them, and then stream -them to {es} for further analysis. -///// - -[float] -[[event-drive-processing]] -=== Perform event-driven processing - -You can use {beatname_uc} to implement event-driven processing workflows with -cloud messaging queues and the {stack}. {beatname_uc} responds to event triggers -from AWS Kinesis and SQS. - -[float] -==== Analyze application data from SQS - -For applications that send JSON-encoded events to an SQS queue, {beatname_uc} -can listen for, ingest, and decode JSON events prior to -shipping them to {es}, where you can analyze the streaming data. - -The processing pipeline for this use case typically looks like this: - -. {beatname_uc} runs as a serverless shipper and listens to an SQS queue for -application events. - -. The {beats} <> processor -decodes JSON strings and replaces them with valid JSON objects. - -. Optional {ref}/ingest.html[ingest pipelines] in {es} further enhance the -data. - -. The events are indexed into an {es} cluster. - -image::./images/functionbeat-pipeline-sqs.png["{beatname_uc} application events triggered by SQS"] diff --git a/x-pack/functionbeat/docs/page_header.html b/x-pack/functionbeat/docs/page_header.html deleted file mode 100644 index 5c1aaf1ba115..000000000000 --- a/x-pack/functionbeat/docs/page_header.html +++ /dev/null @@ -1,3 +0,0 @@ -Functionbeat reached End of Support on October 18, 2023. You must consider -moving your deployments to the more versatile and efficient Elastic Serverless -Forwarder. diff --git a/x-pack/functionbeat/docs/setting-up-running.asciidoc b/x-pack/functionbeat/docs/setting-up-running.asciidoc deleted file mode 100644 index 823bbbd40672..000000000000 --- a/x-pack/functionbeat/docs/setting-up-running.asciidoc +++ /dev/null @@ -1,45 +0,0 @@ -///// -// NOTE: -// Each beat has its own setup overview to allow for the addition of content -// that is unique to each beat. -///// - -[[setting-up-and-running]] -[role="xpack"] -== Set up and deploy {beatname_uc} - -++++ -Set up and deploy -++++ - -Before reading this section, see -<<{beatname_lc}-installation-configuration>> for basic -installation instructions to get you started. - -This section includes additional information on how to install, set up, and run -{beatname_uc}, including: - -* <> - -* <> - -* <> - -* <> - -* <> - - -//MAINTAINERS: If you add a new file to this section, make sure you update the bulleted list ^^ too. - -[role="xpack"] -include::{libbeat-dir}/shared-directory-layout.asciidoc[] - -include::iam-permissions.asciidoc[] - -include::deploying.asciidoc[] - -[role="xpack"] -include::{libbeat-dir}/command-reference.asciidoc[] - -include::export-cloudformation-template.asciidoc[] diff --git a/x-pack/functionbeat/docs/tab-widgets/credentials-aws-widget.asciidoc b/x-pack/functionbeat/docs/tab-widgets/credentials-aws-widget.asciidoc deleted file mode 100644 index d1db7f99189d..000000000000 --- a/x-pack/functionbeat/docs/tab-widgets/credentials-aws-widget.asciidoc +++ /dev/null @@ -1,58 +0,0 @@ -++++ -
-
- - - -
-
-++++ - -include::credentials-aws.asciidoc[tag=mac] - -++++ -
- - -
-++++ diff --git a/x-pack/functionbeat/docs/tab-widgets/credentials-aws.asciidoc b/x-pack/functionbeat/docs/tab-widgets/credentials-aws.asciidoc deleted file mode 100644 index 16f330c906f4..000000000000 --- a/x-pack/functionbeat/docs/tab-widgets/credentials-aws.asciidoc +++ /dev/null @@ -1,26 +0,0 @@ -// tag::mac[] -[source, shell] ----- -export AWS_ACCESS_KEY_ID=ABCDEFGHIJKLMNOPUSER -export AWS_SECRET_ACCESS_KEY=EXAMPLE567890devgHIJKMLOPNQRSTUVZ1234KEY -export AWS_DEFAULT_REGION=us-east-1 ----- -// end::mac[] - -// tag::linux[] -[source, shell] ----- -export AWS_ACCESS_KEY_ID=ABCDEFGHIJKLMNOPUSER -export AWS_SECRET_ACCESS_KEY=EXAMPLE567890devgHIJKMLOPNQRSTUVZ1234KEY -export AWS_DEFAULT_REGION=us-east-1 ----- -// end::linux[] - -// tag::win[] -[source, shell] ----- -set AWS_ACCESS_KEY_ID=ABCDEFGHIJKLMNOPUSER -set AWS_SECRET_ACCESS_KEY=EXAMPLE567890devgHIJKMLOPNQRSTUVZ1234KEY -set AWS_DEFAULT_REGION=us-east-1 ----- -// end::win[] diff --git a/x-pack/functionbeat/docs/tab-widgets/deploy-aws-widget.asciidoc b/x-pack/functionbeat/docs/tab-widgets/deploy-aws-widget.asciidoc deleted file mode 100644 index a6575c0e8597..000000000000 --- a/x-pack/functionbeat/docs/tab-widgets/deploy-aws-widget.asciidoc +++ /dev/null @@ -1,58 +0,0 @@ -++++ -
-
- - - -
-
-++++ - -include::deploy-aws.asciidoc[tag=mac] - -++++ -
- - -
-++++ diff --git a/x-pack/functionbeat/docs/tab-widgets/deploy-aws.asciidoc b/x-pack/functionbeat/docs/tab-widgets/deploy-aws.asciidoc deleted file mode 100644 index 9118384d6e0b..000000000000 --- a/x-pack/functionbeat/docs/tab-widgets/deploy-aws.asciidoc +++ /dev/null @@ -1,19 +0,0 @@ -// tag::mac[] -["source","sh",subs="attributes"] ----- -./{beatname_lc} -v -e -d "*" deploy cloudwatch ----- -// end::mac[] - -// tag::linux[] -["source","sh",subs="attributes"] ----- -./{beatname_lc} -v -e -d "*" deploy cloudwatch ----- -// end::linux[] -// tag::win[] -["source","sh",subs="attributes"] ----- -.{backslash}{beatname_lc}.exe -v -e -d "*" deploy cloudwatch ----- -// end::win[] diff --git a/x-pack/functionbeat/docs/troubleshooting.asciidoc b/x-pack/functionbeat/docs/troubleshooting.asciidoc deleted file mode 100644 index 777f24edd82e..000000000000 --- a/x-pack/functionbeat/docs/troubleshooting.asciidoc +++ /dev/null @@ -1,43 +0,0 @@ -[[troubleshooting]] -[role="xpack"] -= Troubleshoot - -[partintro] --- -If you have issues installing or running {beatname_uc}, read the -following tips: - -* <> -* <> -* <> -* <> - -//sets block macro for getting-help.asciidoc included in next section - --- - -[[getting-help]] -[role="xpack"] -== Get help - -include::{libbeat-dir}/getting-help.asciidoc[] - -//sets block macro for debugging.asciidoc included in next section - -[id="enable-{beatname_lc}-debugging"] -[role="xpack"] -== Debug - -include::{libbeat-dir}/debugging.asciidoc[] - -//sets block macro for metrics-in-logs.asciidoc included in next section - -[id="understand-{beatname_lc}-logs"] -[role="xpack"] -== Understand metrics in {beatname_uc} logs - -++++ -Understand logged metrics -++++ - -include::{libbeat-dir}/metrics-in-logs.asciidoc[] diff --git a/x-pack/functionbeat/function/beater/functionbeat.go b/x-pack/functionbeat/function/beater/functionbeat.go deleted file mode 100644 index 77ea2a7bd008..000000000000 --- a/x-pack/functionbeat/function/beater/functionbeat.go +++ /dev/null @@ -1,185 +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 beater - -import ( - "context" - "fmt" - "os" - "strings" - "time" - - "github.com/elastic/beats/v7/libbeat/common/fmtstr" - "github.com/elastic/beats/v7/libbeat/outputs/elasticsearch" - "github.com/elastic/beats/v7/libbeat/publisher/pipeline" - "github.com/elastic/elastic-agent-libs/mapstr" - - "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/licenser" - "github.com/elastic/beats/v7/libbeat/processors" - "github.com/elastic/beats/v7/x-pack/functionbeat/config" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/core" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/provider" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/telemetry" - conf "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/logp" - "github.com/elastic/elastic-agent-libs/monitoring" -) - -var ( - graceDelay = 45 * time.Minute - refreshDelay = 15 * time.Minute - supportedOutputs = []string{ - "elasticsearch", - "logstash", - "console", // for local debugging - } -) - -// Functionbeat is a beat designed to run under a serverless environment and listen to external triggers, -// each invocation will generate one or more events to Elasticsearch. -// -// Each serverless implementation is different but functionbeat follows a few execution rules. -// - Publishing events from the source to the output is done synchronously. -// - Execution can be suspended. -// - Run on a read only filesystem -// - More execution constraints based on speed and memory usage. -type Functionbeat struct { - Ctx context.Context - log *logp.Logger - cancel context.CancelFunc - telemetry telemetry.T - Provider provider.Provider - Config *config.Config -} - -// New creates an instance of functionbeat. -func New(b *beat.Beat, cfg *conf.C) (beat.Beater, error) { - - c := &config.DefaultConfig - if err := cfg.Unpack(c); err != nil { - return nil, fmt.Errorf("error reading config file: %+v", err) - } - - provider, err := provider.Create(c.Provider) - if err != nil { - return nil, err - } - ctx, cancel := context.WithCancel(context.Background()) - - telemetryReg := monitoring.GetNamespace("state").GetRegistry().NewRegistry("functionbeat") - - bt := &Functionbeat{ - Ctx: ctx, - log: logp.NewLogger("functionbeat"), - cancel: cancel, - telemetry: telemetry.New(telemetryReg), - Provider: provider, - Config: c, - } - return bt, nil -} - -// Run starts functionbeat. -func (bt *Functionbeat) Run(b *beat.Beat) error { - defer bt.cancel() - - outputName := b.Config.Output.Name() - if !isOutputSupported(outputName) { - return fmt.Errorf("unsupported output type: %s; supported ones: %+v", outputName, supportedOutputs) - } - - elasticsearch.RegisterGlobalCallback(licenser.FetchAndVerify) - - bt.log.Info("Functionbeat is running") - defer bt.log.Info("Functionbeat stopped running") - - clientFactory := makeClientFactory(bt.log, b.Publisher, b.Info) - - enabledFunctions := bt.enabledFunctions() - bt.log.Infof("Functionbeat is configuring enabled functions: %s", strings.Join(enabledFunctions, ", ")) - // Create a client per function and wrap them into a runnable function by the coordinator. - functions, err := bt.Provider.CreateFunctions(clientFactory, enabledFunctions) - if err != nil { - return fmt.Errorf("error when creating the functions, error: %+v", err) - } - - // manages the goroutine related to the function handlers, if an error occurs and its not handled - // by the function itself, it will reach the coordinator, we log the error and shutdown beats. - // When an error reach the coordinator we assume that we cannot recover from it and we initiate - // a shutdown and return an aggregated errors. - coordinator := core.NewCoordinator(logp.NewLogger("coordinator"), functions...) - err = coordinator.Run(bt.Ctx, bt.telemetry) - if err != nil { - return err - } - return nil -} - -// enabledFunctions returns the enabled function types -func (bt *Functionbeat) enabledFunctions() (values []string) { - raw, found := os.LookupEnv("ENABLED_FUNCTIONS") - if !found { - return values - } - return strings.Split(raw, ",") -} - -// Stop stops functionbeat. -func (bt *Functionbeat) Stop() { - bt.log.Info("Functionbeat is stopping") - defer bt.log.Info("Functionbeat is stopped") - bt.cancel() -} - -func isOutputSupported(name string) bool { - for _, output := range supportedOutputs { - if name == output { - return true - } - } - return false -} - -type fnExtraConfig struct { - Processors processors.PluginConfig `config:"processors"` - - // KeepNull determines whether published events will keep null values or omit them. - KeepNull bool `config:"keep_null"` - - mapstr.EventMetadata `config:",inline"` // Fields and tags to add to events. - - // ES output index pattern - Index fmtstr.EventFormatString `config:"index"` -} - -func makeClientFactory(log *logp.Logger, pipe beat.Pipeline, beatInfo beat.Info) func(*conf.C) (pipeline.ISyncClient, error) { - // Each function has his own client to the publisher pipeline, - // publish operation will block the calling thread, when the method unwrap we have received the - // ACK for the batch. - return func(cfg *conf.C) (pipeline.ISyncClient, error) { - c := fnExtraConfig{} - - if err := cfg.Unpack(&c); err != nil { - return nil, err - } - - funcProcessors, err := processorsForFunction(beatInfo, c) - if err != nil { - return nil, err - } - - client, err := pipeline.NewSyncClient(log, pipe, beat.ClientConfig{ - PublishMode: beat.GuaranteedSend, - Processing: beat.ProcessingConfig{ - Processor: funcProcessors, - EventMetadata: c.EventMetadata, - KeepNull: c.KeepNull, - }, - }) - - return client, err - } -} diff --git a/x-pack/functionbeat/function/beater/proccessors_test.go b/x-pack/functionbeat/function/beater/proccessors_test.go deleted file mode 100644 index d15f5320e40d..000000000000 --- a/x-pack/functionbeat/function/beater/proccessors_test.go +++ /dev/null @@ -1,124 +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 beater - -import ( - "testing" - "time" - - "github.com/stretchr/testify/assert" - - "github.com/elastic/beats/v7/libbeat/beat" - _ "github.com/elastic/beats/v7/libbeat/processors/actions" - conf "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/mapstr" -) - -func TestProcessorsForFunction(t *testing.T) { - testCases := map[string]struct { - beatInfo beat.Info - configStr string - event beat.Event - expectedFields map[string]string - }{ - "Simple static index": { - configStr: "index: 'test'", - expectedFields: map[string]string{ - "@metadata.raw_index": "test", - }, - }, - "Index with agent info + timestamp": { - beatInfo: beat.Info{Beat: "TestBeat", Version: "3.9.27"}, - configStr: "index: 'beat-%{[agent.name]}-%{[agent.version]}-%{+yyyy.MM.dd}'", - event: beat.Event{Timestamp: time.Date(1999, time.December, 31, 23, 0, 0, 0, time.UTC)}, - expectedFields: map[string]string{ - "@metadata.raw_index": "beat-TestBeat-3.9.27-1999.12.31", - }, - }, - "Set field in input config": { - configStr: `processors: [add_fields: {fields: {testField: inputConfig}}]`, - expectedFields: map[string]string{ - "fields.testField": "inputConfig", - }, - }, - } - for description, test := range testCases { - if test.event.Fields == nil { - test.event.Fields = mapstr.M{} - } - config, err := functionConfigFromString(test.configStr) - if err != nil { - t.Errorf("[%s] %v", description, err) - continue - } - processors, err := processorsForFunction(test.beatInfo, config) - if err != nil { - t.Errorf("[%s] %v", description, err) - continue - } - processedEvent, err := processors.Run(&test.event) - // We don't check if err != nil, because we are testing the final outcome - // of running the processors, including when some of them fail. - if processedEvent == nil { - t.Errorf("[%s] Unexpected fatal error running processors: %v\n", - description, err) - } - for key, value := range test.expectedFields { - field, err := processedEvent.GetValue(key) - if err != nil { - t.Errorf("[%s] Couldn't get field %s from event: %v", description, key, err) - continue - } - assert.Equal(t, field, value) - fieldStr, ok := field.(string) - if !ok { - // Note that requiring a string here is just to simplify the test setup, - // not a requirement of the underlying api. - t.Errorf("[%s] Field [%s] should be a string", description, key) - continue - } - if fieldStr != value { - t.Errorf("[%s] Event field [%s]: expected [%s], got [%s]", description, key, value, fieldStr) - } - } - } -} - -func TestProcessorsForFunctionIsFlat(t *testing.T) { - // This test is regrettable, and exists because of inconsistencies in - // processor handling between processors.Processors and processing.group - // (which implements beat.ProcessorList) -- see processorsForConfig for - // details. The upshot is that, for now, if the function configuration specifies - // processors, they must be returned as direct children of the resulting - // processors.Processors (rather than being collected in additional tree - // structure). - // This test should be removed once we have a more consistent mechanism for - // collecting and running processors. - configStr := `processors: -- add_fields: {fields: {testField: value}} -- add_fields: {fields: {testField2: stuff}}` - config, err := functionConfigFromString(configStr) - if err != nil { - t.Fatal(err) - } - processors, err := processorsForFunction( - beat.Info{}, config) - if err != nil { - t.Fatal(err) - } - assert.Equal(t, 2, len(processors.List)) -} - -// Helper function to convert from YML input string to an unpacked -// fnExtraConfig -func functionConfigFromString(s string) (fnExtraConfig, error) { - config := fnExtraConfig{} - cfg, err := conf.NewConfigFrom(s) - if err != nil { - return config, err - } - err = cfg.Unpack(&config) - return config, err -} diff --git a/x-pack/functionbeat/function/beater/processors.go b/x-pack/functionbeat/function/beater/processors.go deleted file mode 100644 index 23c5da9ca232..000000000000 --- a/x-pack/functionbeat/function/beater/processors.go +++ /dev/null @@ -1,38 +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 beater - -import ( - "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/common/fmtstr" - "github.com/elastic/beats/v7/libbeat/processors" - "github.com/elastic/beats/v7/libbeat/processors/add_formatted_index" -) - -func processorsForFunction(beatInfo beat.Info, config fnExtraConfig) (*processors.Processors, error) { - procs := processors.NewList(nil) - - // Processor ordering is important: - // 1. Index configuration - if !config.Index.IsEmpty() { - staticFields := fmtstr.FieldsForBeat(beatInfo.Beat, beatInfo.Version) - timestampFormat, err := - fmtstr.NewTimestampFormatString(&config.Index, staticFields) - if err != nil { - return nil, err - } - indexProcessor := add_formatted_index.New(timestampFormat) - procs.AddProcessor(indexProcessor) - } - - // 2. User processors - userProcessors, err := processors.New(config.Processors) - if err != nil { - return nil, err - } - procs.AddProcessors(*userProcessors) - - return procs, nil -} diff --git a/x-pack/functionbeat/function/cmd/root.go b/x-pack/functionbeat/function/cmd/root.go deleted file mode 100644 index 75206efbb2c2..000000000000 --- a/x-pack/functionbeat/function/cmd/root.go +++ /dev/null @@ -1,54 +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 cmd - -import ( - "fmt" - "os" - - "github.com/spf13/cobra" - - "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/cfgfile" - "github.com/elastic/beats/v7/libbeat/cmd" - "github.com/elastic/beats/v7/libbeat/cmd/instance" - "github.com/elastic/beats/v7/x-pack/functionbeat/config" -) - -// FunctionCmd is the command of the function. -type FunctionCmd struct { - *cobra.Command - VersionCmd *cobra.Command -} - -// NewFunctionCmd return a new initialized function command. -func NewFunctionCmd(name string, beatCreator beat.Creator) *FunctionCmd { - settings := instance.Settings{ - Name: name, - IndexPrefix: name, - ConfigOverrides: config.FunctionOverrides, - } - - err := cfgfile.ChangeDefaultCfgfileFlag(settings.Name) - if err != nil { - panic(fmt.Errorf("failed to set default config file path: %v", err)) - } - - rootCmd := &FunctionCmd{ - &cobra.Command{ - Run: func(cmd *cobra.Command, args []string) { - err := instance.Run(settings, beatCreator) - if err != nil { - os.Exit(1) - } - }, - }, - cmd.GenVersionCmd(settings), - } - - rootCmd.AddCommand(rootCmd.VersionCmd) - - return rootCmd -} diff --git a/x-pack/functionbeat/function/core/coordinator.go b/x-pack/functionbeat/function/core/coordinator.go deleted file mode 100644 index b7cf2e716bec..000000000000 --- a/x-pack/functionbeat/function/core/coordinator.go +++ /dev/null @@ -1,98 +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 core - -import ( - "context" - "fmt" - - "github.com/joeshaw/multierror" - - "github.com/elastic/beats/v7/x-pack/functionbeat/function/telemetry" - "github.com/elastic/elastic-agent-libs/logp" -) - -// Runner is the interface that the coordinator will follow to manage a function goroutine. -type Runner interface { - fmt.Stringer - Run(context.Context, telemetry.T) error -} - -// Coordinator takes care of managing the function goroutine, it receives the list of functions that -// need to be executed and manage the goroutine. If an error happen and its not handled by the -// function, we assume its a fatal error and we will -// stop all the other goroutine and functionbeat will terminate. -type Coordinator struct { - log *logp.Logger - runners []Runner -} - -// NewCoordinator create a new coordinator objects receiving the clientFactory and the runner. -func NewCoordinator(log *logp.Logger, - runners ...Runner, -) *Coordinator { - if log == nil { - log = logp.NewLogger("") - } - log = log.Named("Coordinator") - return &Coordinator{log: log, runners: runners} -} - -// Run starts each functions into an independent goroutine and wait until all the goroutine are -// stopped to exit. -func (r *Coordinator) Run(ctx context.Context, t telemetry.T) error { - r.log.Debug("Coordinator is starting") - defer r.log.Debug("Coordinator is stopped") - - // When an errors happen in a function and its not handled by the running function, we log an error - // and we trigger a shutdown of all the others goroutine. - ctx, cancel := context.WithCancel(ctx) - defer cancel() - - results := make(chan error) - defer close(results) - - r.log.Debugf("The coordinator is starting %d functions", len(r.runners)) - for _, rfn := range r.runners { - go func(ctx context.Context, t telemetry.T, rfn Runner) { - var err error - defer func() { results <- err }() - err = r.runFunc(ctx, t, rfn) - if err != nil { - cancel() - } - }(ctx, t, rfn) - } - - // Wait for goroutine to complete and aggregate any errors from the goroutine and - // raise them back to the main program. - var errors multierror.Errors - for range r.runners { - err := <-results - if err != nil { - errors = append(errors, err) - } - } - return errors.Err() -} - -func (r *Coordinator) runFunc( - ctx context.Context, - t telemetry.T, - rfn Runner, -) error { - r.log.Infof("The function '%s' is starting", rfn.String()) - defer r.log.Infof("The function '%s' is stopped", rfn.String()) - - err := rfn.Run(ctx, t) - if err != nil { - r.log.Errorf( - "Nonrecoverable error when executing the function: '%s', error: '%+v', terminating all running functions", - rfn, - err, - ) - } - return err -} diff --git a/x-pack/functionbeat/function/core/coordinator_test.go b/x-pack/functionbeat/function/core/coordinator_test.go deleted file mode 100644 index 71f3356941d7..000000000000 --- a/x-pack/functionbeat/function/core/coordinator_test.go +++ /dev/null @@ -1,58 +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 core - -import ( - "context" - "errors" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/elastic/beats/v7/x-pack/functionbeat/function/telemetry" -) - -var errUnhappy = errors.New("unhappy :(") - -type happyRunner struct{} - -func (hr *happyRunner) Run(ctx context.Context, _ telemetry.T) error { - <-ctx.Done() - return nil -} -func (hr *happyRunner) String() string { return "happyRunner" } - -type unhappyRunner struct{} - -func (uhr *unhappyRunner) Run(ctx context.Context, _ telemetry.T) error { - return errUnhappy -} - -func (uhr *unhappyRunner) String() string { return "unhappyRunner" } - -func TestStart(t *testing.T) { - t.Run("start the runner", func(t *testing.T) { - coordinator := NewCoordinator(nil, &happyRunner{}, &happyRunner{}) - ctx, cancel := context.WithCancel(context.Background()) - var err error - go func() { - err = coordinator.Run(ctx, telemetry.Ignored()) - assert.NoError(t, err) - }() - cancel() - }) - - t.Run("on error shutdown all the runner", func(t *testing.T) { - coordinator := NewCoordinator(nil, &happyRunner{}, &unhappyRunner{}) - err := coordinator.Run(context.Background(), telemetry.Ignored()) - assert.Error(t, err) - }) - - t.Run("aggregate all errors", func(t *testing.T) { - coordinator := NewCoordinator(nil, &unhappyRunner{}, &unhappyRunner{}) - err := coordinator.Run(context.Background(), telemetry.Ignored()) - assert.Error(t, err) - }) -} diff --git a/x-pack/functionbeat/function/provider/cli.go b/x-pack/functionbeat/function/provider/cli.go deleted file mode 100644 index 7f112330289a..000000000000 --- a/x-pack/functionbeat/function/provider/cli.go +++ /dev/null @@ -1,32 +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 provider - -import ( - conf "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/logp" -) - -// CLIManager is the interface implemented by each provider to expose a command CLI interface -// to their interface. -type CLIManager interface { - // Deploy takes a function name and deploy functionbeat and the function configuration to the provider. - Deploy(string) error - - //Update takes a function name and update the configuration to the remote provider. - Update(string) error - - // Remove takes a function name and remove the specific function from the remote provider. - Remove(string) error - - // Export prints exported function template to stdout. - Export(string) error - - // Package packages functions for the provider configurable output. - Package(string) error -} - -// CLIManagerFactory factory method to call to create a new CLI manager -type CLIManagerFactory func(*logp.Logger, *conf.C, Provider) (CLIManager, error) diff --git a/x-pack/functionbeat/function/provider/default_provider.go b/x-pack/functionbeat/function/provider/default_provider.go deleted file mode 100644 index 3693d0a718f8..000000000000 --- a/x-pack/functionbeat/function/provider/default_provider.go +++ /dev/null @@ -1,112 +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 provider - -import ( - "fmt" - - "github.com/elastic/beats/v7/x-pack/functionbeat/config" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/core" - conf "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/logp" -) - -// DefaultProvider implements the minimal required to retrieve and start functions. -type DefaultProvider struct { - rawConfig *conf.C - config *config.ProviderConfig - registry *Registry - name string - log *logp.Logger - managerFactory CLIManagerFactory - templateFactory TemplateBuilderFactory -} - -// NewDefaultProvider returns factory methods to handle generic provider. -func NewDefaultProvider( - name string, - manager CLIManagerFactory, - templater TemplateBuilderFactory, -) func(*logp.Logger, *Registry, *conf.C) (Provider, error) { - return func(log *logp.Logger, registry *Registry, cfg *conf.C) (Provider, error) { - c := &config.ProviderConfig{} - err := cfg.Unpack(c) - if err != nil { - return nil, err - } - - if manager == nil { - manager = NewNullCli - } - - return &DefaultProvider{ - rawConfig: cfg, - config: c, - registry: registry, - name: name, - log: log, - managerFactory: manager, - templateFactory: templater, - }, nil - } -} - -// Name returns the name of the provider. -func (d *DefaultProvider) Name() string { - return d.name -} - -// CreateFunctions takes factory method and returns runnable function. -func (d *DefaultProvider) CreateFunctions(clientFactory clientFactory, enabledFunctions []string) ([]core.Runner, error) { - return CreateFunctions(d.registry, d, enabledFunctions, d.config.Functions, clientFactory) -} - -// FindFunctionByName returns a function instance identified by a unique name or an error if not found. -func (d *DefaultProvider) FindFunctionByName(name string) (Function, error) { - return FindFunctionByName(d.registry, d, d.config.Functions, name) -} - -// CLIManager returns the type responsable of installing, updating and removing remote function -// for a specific provider. -func (d *DefaultProvider) CLIManager() (CLIManager, error) { - return d.managerFactory(nil, d.rawConfig, d) -} - -// TemplateBuilder returns a TemplateBuilder returns a the type responsible to generate templates. -func (d *DefaultProvider) TemplateBuilder() (TemplateBuilder, error) { - return d.templateFactory(d.log, d.rawConfig, d) -} - -// EnabledFunctions return the list of enabled funcionts. -func (d *DefaultProvider) EnabledFunctions() ([]string, error) { - return EnabledFunctions(d.registry, d, d.config.Functions) -} - -// nullCLI is used when a provider doesn't implement the CLI to manager functions on the service provider. -type nullCLI struct{} - -// NewNullCli returns a NOOP CliManager. -func NewNullCli(_ *logp.Logger, _ *conf.C, _ Provider) (CLIManager, error) { - return (*nullCLI)(nil), nil -} - -func (*nullCLI) Deploy(_ string) error { return fmt.Errorf("deploy not implemented") } -func (*nullCLI) Update(_ string) error { return fmt.Errorf("update not implemented") } -func (*nullCLI) Remove(_ string) error { return fmt.Errorf("remove not implemented") } -func (*nullCLI) Export(_ string) error { return fmt.Errorf("export not implemented") } -func (*nullCLI) Package(_ string) error { return fmt.Errorf("package not implemented") } - -// nullTemplateBuilder is used when a provider does not implement a template builder functionality. -type nullTemplateBuilder struct{} - -// NewNullTemplateBuilder returns a NOOP TemplateBuilder. -func NewNullTemplateBuilder(_ *logp.Logger, _ *conf.C, _ Provider) (TemplateBuilder, error) { - return (*nullTemplateBuilder)(nil), nil -} - -// RawTemplate returns a empty string. -func (*nullTemplateBuilder) RawTemplate(_ string) (string, error) { - return "", fmt.Errorf("raw temaplate not implemented") -} diff --git a/x-pack/functionbeat/function/provider/feature.go b/x-pack/functionbeat/function/provider/feature.go deleted file mode 100644 index 34c381b24714..000000000000 --- a/x-pack/functionbeat/function/provider/feature.go +++ /dev/null @@ -1,64 +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 provider - -import ( - "github.com/elastic/beats/v7/libbeat/feature" -) - -// getNamespace return the namespace for functions of a specific provider. The registry have a flat view -// representation of the plugin world this mean we don't really have a tree, instead what we do is -// to create a unique keys per providers that will only keep the functions of the provider. -func getNamespace(provider string) string { - return namespace + "." + provider + ".functions" -} - -// newFeature creates a new Provider feature to be added to the global registry. -// The namespace will be 'functionbeat.provider' in the registry. -func newFeature(name string, factory Factory) *feature.Feature { - return feature.New(namespace, name, factory) -} - -// newFunctionFeature Feature creates a new function feature to be added to the global registry -// The namespace will be 'functionbeat.provider.local' in the registry. -func newFunctionFeature( - provider, name string, - factory FunctionFactory, -) *feature.Feature { - return feature.New(getNamespace(provider), name, factory) -} - -// builder is used to have a fluent interface to build a set of function for a specific provider, it -// provides a fluent interface to the developper of provider and functions, it wraps the Feature -// functions to make sure the namespace are correctly configured. -type builder struct { - name string - features []feature.Featurable -} - -// Builder creates a new provider builder, it is used to define a provider and the function -// it supports. -func Builder(name string, factory Factory, details feature.Details) *builder { - return &builder{ - name: name, - features: []feature.Featurable{ - newFeature(name, factory), - }, - } -} - -func (b *builder) Features() []feature.Featurable { - return b.features -} - -// AddFunction adds a new function type to the provider and return the builder. -func (b *builder) AddFunction( - name string, - factory FunctionFactory, - details feature.Details, -) *builder { - b.features = append(b.features, newFunctionFeature(b.name, name, factory)) - return b -} diff --git a/x-pack/functionbeat/function/provider/feature_test.go b/x-pack/functionbeat/function/provider/feature_test.go deleted file mode 100644 index a0b8a6d7fcbe..000000000000 --- a/x-pack/functionbeat/function/provider/feature_test.go +++ /dev/null @@ -1,51 +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 provider - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/elastic/beats/v7/libbeat/feature" - conf "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/logp" -) - -func TestBuilder(t *testing.T) { - provider := "myprovider" - providerFactory := func(_ *logp.Logger, _ *Registry, _ *conf.C) (Provider, error) { - return nil, nil - } - - fnFactory1 := func(_ Provider, _ *conf.C) (Function, error) { return nil, nil } - fnFactory2 := func(_ Provider, _ *conf.C) (Function, error) { return nil, nil } - - features := Builder( - provider, - providerFactory, - feature.MakeDetails("myprovider", "myprovider", feature.Experimental), - ).AddFunction( - "f1", - fnFactory1, - feature.MakeDetails("fn1 description", "fn1", feature.Experimental), - ).AddFunction("f2", fnFactory2, feature.MakeDetails( - "fn1 description", - "fn1", - feature.Experimental, - )).Features() - - require.Equal(t, 3, len(features)) - - assert.Equal(t, "myprovider", features[0].Name()) - assert.Equal(t, "functionbeat.provider", features[0].Namespace()) - - assert.Equal(t, "f1", features[1].Name()) - assert.Equal(t, "functionbeat.provider.myprovider.functions", features[1].Namespace()) - - assert.Equal(t, "f2", features[2].Name()) - assert.Equal(t, "functionbeat.provider.myprovider.functions", features[2].Namespace()) -} diff --git a/x-pack/functionbeat/function/provider/provider.go b/x-pack/functionbeat/function/provider/provider.go deleted file mode 100644 index 6c33eb80b1a1..000000000000 --- a/x-pack/functionbeat/function/provider/provider.go +++ /dev/null @@ -1,133 +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 provider - -import ( - "context" - "fmt" - - "github.com/elastic/beats/v7/libbeat/feature" - "github.com/elastic/beats/v7/libbeat/publisher/pipeline" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/core" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/telemetry" - conf "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/logp" -) - -// Create a new pipeline client based on the function configuration. -type clientFactory func(*conf.C) (pipeline.ISyncClient, error) - -// Function is temporary -type Function interface { - Run(context.Context, pipeline.ISyncClient, telemetry.T) error - Name() string -} - -// Provider providers the layer between functionbeat and cloud specific settings, its is responsable to -// return the function that need to be executed. -type Provider interface { - CreateFunctions(clientFactory, []string) ([]core.Runner, error) - FindFunctionByName(string) (Function, error) - EnabledFunctions() ([]string, error) - CLIManager() (CLIManager, error) - TemplateBuilder() (TemplateBuilder, error) - Name() string -} - -// Runnable is the unit of work managed by the coordinator, anything related to the life of a function -// is encapsulated into the runnable. -type Runnable struct { - config *conf.C - function Function - makeClient clientFactory -} - -// Run call the the function's Run method, the method is a specific goroutine, it will block until -// beats shutdown or an error happen. -func (r *Runnable) Run(ctx context.Context, t telemetry.T) error { - client, err := r.makeClient(r.config) - if err != nil { - return fmt.Errorf("could not create a client for the function: %w", err) - } - defer client.Close() - return r.function.Run(ctx, client, t) -} - -func (r *Runnable) String() string { - return r.function.Name() -} - -// NewProvider return the provider specified in the configuration or an error. -func NewProvider(name string, cfg *conf.C) (Provider, error) { - // Configure the provider, the provider will take care of the configuration for the - // functions. - registry := NewRegistry(feature.GlobalRegistry()) - providerFunc, err := registry.Lookup(name) - if err != nil { - return nil, fmt.Errorf("error finding the provider '%s', error: %v", name, err) - } - - provider, err := providerFunc(logp.NewLogger("provider"), registry, cfg) - if err != nil { - return nil, fmt.Errorf("error creating the provider '%s', error: %v", name, err) - } - - return provider, nil -} - -// IsAvailable checks if a cloud provider is available in the binary. -func IsAvailable(name string) (bool, error) { - registry := NewRegistry(feature.GlobalRegistry()) - - availableProviders, err := registry.AvailableProviders() - if err != nil { - return false, err - } - - for _, p := range availableProviders { - if p == name { - return true, nil - } - } - return false, nil -} - -// ListFunctions returns the list of enabled function names. -func ListFunctions(provider string) ([]string, error) { - functions, err := feature.GlobalRegistry().LookupAll(getNamespace(provider)) - if err != nil { - return nil, err - } - - names := make([]string, len(functions)) - for i, f := range functions { - names[i] = f.Name() - } - return names, nil -} - -// Create returns the provider from a configuration. -func Create(cfg *conf.C) (Provider, error) { - providers, err := List() - if err != nil { - return nil, err - } - if len(providers) != 1 { - return nil, fmt.Errorf("too many providers are available, expected one, got: %s", providers) - } - - providerCfg, err := cfg.Child(providers[0], -1) - if err != nil { - return nil, err - } - - return NewProvider(providers[0], providerCfg) -} - -// List returns the list of available providers. -func List() ([]string, error) { - registry := NewRegistry(feature.GlobalRegistry()) - return registry.AvailableProviders() -} diff --git a/x-pack/functionbeat/function/provider/provider_test.go b/x-pack/functionbeat/function/provider/provider_test.go deleted file mode 100644 index 47385cbb0292..000000000000 --- a/x-pack/functionbeat/function/provider/provider_test.go +++ /dev/null @@ -1,74 +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 provider - -import ( - "context" - "errors" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/publisher/pipeline" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/telemetry" - conf "github.com/elastic/elastic-agent-libs/config" -) - -type simpleFunction struct { - err error -} - -func (s *simpleFunction) Run(ctx context.Context, client pipeline.ISyncClient, _ telemetry.T) error { - return s.err -} - -func (s *simpleFunction) Name() string { - return "simpleFunction" -} - -type mockClient struct{} - -func (sc *mockClient) Publish(event beat.Event) error { return nil } -func (sc *mockClient) PublishAll(events []beat.Event) error { return nil } -func (sc *mockClient) Close() error { return nil } -func (sc *mockClient) Wait() {} - -func TestRunnable(t *testing.T) { - t.Run("return an error when we cannot create the client", func(t *testing.T) { - err := errors.New("oops") - runnable := Runnable{ - config: conf.NewConfig(), - makeClient: func(cfg *conf.C) (pipeline.ISyncClient, error) { return nil, err }, - function: &simpleFunction{err: nil}, - } - - errReceived := runnable.Run(context.Background(), telemetry.Ignored()) - assert.Equal(t, "could not create a client for the function: "+err.Error(), errReceived.Error()) - }) - - t.Run("propagate functions errors to the coordinator", func(t *testing.T) { - err := errors.New("function error") - runnable := Runnable{ - config: conf.NewConfig(), - makeClient: func(cfg *conf.C) (pipeline.ISyncClient, error) { return &mockClient{}, nil }, - function: &simpleFunction{err: err}, - } - - errReceived := runnable.Run(context.Background(), telemetry.Ignored()) - assert.Equal(t, err.Error(), errReceived.Error()) - }) - - t.Run("when there is no error run and exit normaly", func(t *testing.T) { - runnable := Runnable{ - config: conf.NewConfig(), - makeClient: func(cfg *conf.C) (pipeline.ISyncClient, error) { return &mockClient{}, nil }, - function: &simpleFunction{err: nil}, - } - - errReceived := runnable.Run(context.Background(), telemetry.Ignored()) - assert.NoError(t, errReceived) - }) -} diff --git a/x-pack/functionbeat/function/provider/registry.go b/x-pack/functionbeat/function/provider/registry.go deleted file mode 100644 index 4cd1575cac0c..000000000000 --- a/x-pack/functionbeat/function/provider/registry.go +++ /dev/null @@ -1,217 +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 provider - -import ( - "errors" - "fmt" - - "github.com/elastic/beats/v7/libbeat/feature" - "github.com/elastic/beats/v7/x-pack/functionbeat/config" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/core" - conf "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/logp" -) - -// Errors generated by the registry when we are retrieving providers or functions from the main registry. -var ( - errInvalidProvider = errors.New("invalid provider name") - errInvalidFunctionName = errors.New("invalid function name") - errInvalidType = errors.New("incomptible type received for the feature") -) - -// namespace is the namespace were providers will be registered in the global registry. -const namespace = "functionbeat.provider" - -// Factory factory to create a concrete provider for a specific cloud service. -type Factory func(*logp.Logger, *Registry, *conf.C) (Provider, error) - -// FunctionFactory factory to create a concrete function. -type FunctionFactory func(Provider, *conf.C) (Function, error) - -// Registry is a wrapper around the global feature registry and will take care of returning the -// the right providers and will do the type assertion for the providers, we hide the fact that -// we are actually accessing a global registry. -type Registry struct { - registry *feature.Registry -} - -// NewRegistry return a new registry. -func NewRegistry(registry *feature.Registry) *Registry { - return &Registry{registry: registry} -} - -// Lookup search the registry for the specific provider, normalization is done inside the -// registry to deal with lower case and uppercase. -func (r *Registry) Lookup(name string) (Factory, error) { - if len(name) == 0 { - return nil, errInvalidProvider - } - - f, err := r.registry.Lookup(namespace, name) - if err != nil { - return nil, err - } - - p, ok := f.Factory().(Factory) - if !ok { - return nil, errInvalidType - } - - return p, nil -} - -// LookupFunction takes a provider and a function and return the corresponding type or an -// error if the function or the provider is not found. -func (r *Registry) LookupFunction(provider, function string) (FunctionFactory, error) { - if len(provider) == 0 { - return nil, errInvalidProvider - } - if len(function) == 0 { - return nil, errInvalidFunctionName - } - - if _, err := r.Lookup(provider); err != nil { - return nil, err - } - - ns := getNamespace(provider) - - f, err := r.registry.Lookup(ns, function) - if err != nil { - return nil, err - } - - fn, ok := f.Factory().(FunctionFactory) - if !ok { - return nil, errInvalidType - } - - return fn, nil -} - -// AvailableProviders returns the names of registered providers. -func (r *Registry) AvailableProviders() ([]string, error) { - providerFeatures, err := r.registry.LookupAll(namespace) - if err != nil { - return nil, err - } - - var providers []string - for _, f := range providerFeatures { - providers = append(providers, f.Name()) - } - - return providers, nil -} - -// CreateFunctions create runnable function based on the configurations received. -func CreateFunctions( - registry *Registry, - provider Provider, - enabledFunctions []string, - configs []*conf.C, - clientFactory clientFactory, -) ([]core.Runner, error) { - var runners []core.Runner - - for _, cfg := range configs { - c := config.DefaultFunctionConfig - err := cfg.Unpack(&c) - if err != nil { - return nil, err - } - - if strInSlice(enabledFunctions, c.Name.String()) == -1 { - continue - } - - if !c.Enabled { - return nil, fmt.Errorf("function '%s' not enabled for provider '%s'", c.Name, provider.Name()) - } - - f, err := registry.LookupFunction(provider.Name(), c.Type) - if err != nil { - return nil, err - } - - fn, err := f(provider, cfg) - if err != nil { - return nil, err - } - - runners = append(runners, &Runnable{config: cfg, makeClient: clientFactory, function: fn}) - } - - if len(runners) == 0 { - return nil, fmt.Errorf("no function are enabled for selected provider: '%s'", provider.Name()) - } - return runners, nil -} - -func strInSlice(haystack []string, name string) int { - for idx, s := range haystack { - if s == name { - return idx - } - } - return -1 -} - -// FindFunctionByName returns a function instance identified by a unique name or an error if not found. -func FindFunctionByName( - registry *Registry, - provider Provider, - configs []*conf.C, - name string, -) (Function, error) { - - for _, cfg := range configs { - c := config.FunctionConfig{} - err := cfg.Unpack(&c) - if err != nil { - return nil, err - } - - if c.Name.String() != name { - continue - } - - if !c.Enabled { - return nil, fmt.Errorf("function '%s' not enabled for provider '%s'", name, provider.Name()) - } - - f, err := registry.LookupFunction(provider.Name(), c.Type) - if err != nil { - return nil, err - } - - fn, err := f(provider, cfg) - if err != nil { - return nil, err - } - return fn, nil - } - - return nil, fmt.Errorf("no function with name '%s' exists", name) -} - -// EnabledFunctions returns the list of enabled functions. -func EnabledFunctions(registry *Registry, provider Provider, configs []*conf.C) ([]string, error) { - var names []string - for _, cfg := range configs { - c := config.FunctionConfig{} - err := cfg.Unpack(&c) - if err != nil { - return names, fmt.Errorf("error while finding enabled functions: %+v", err) - } - - if c.Enabled { - names = append(names, c.Name.String()) - } - } - - return names, nil -} diff --git a/x-pack/functionbeat/function/provider/registry_test.go b/x-pack/functionbeat/function/provider/registry_test.go deleted file mode 100644 index 01c994c6186c..000000000000 --- a/x-pack/functionbeat/function/provider/registry_test.go +++ /dev/null @@ -1,274 +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 provider - -import ( - "context" - "errors" - "reflect" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/elastic/beats/v7/libbeat/feature" - "github.com/elastic/beats/v7/libbeat/publisher/pipeline" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/core" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/telemetry" - conf "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/logp" -) - -type mockProvider struct { - runners []core.Runner - name string -} - -func (m *mockProvider) CreateFunctions(clientFactory clientFactory, _ []string) ([]core.Runner, error) { - return m.runners, nil -} - -func (m *mockProvider) FindFunctionByName(_ string) (Function, error) { - return nil, errors.New("not found") -} - -func (m *mockProvider) Name() string { return m.name } - -func (m *mockProvider) CLIManager() (CLIManager, error) { return nil, nil } - -func (m *mockProvider) TemplateBuilder() (TemplateBuilder, error) { return nil, nil } - -func (m *mockProvider) EnabledFunctions() ([]string, error) { return []string{}, nil } - -func TestRegistry(t *testing.T) { - t.Run("provider", testProviderLookup) - t.Run("functions", testFunctionLookup) -} - -type mockFunction struct { - name string -} - -func (mf *mockFunction) Run(ctx context.Context, client pipeline.ISyncClient, t telemetry.T) error { - return nil -} -func (mf *mockFunction) Name() string { return mf.name } - -func testProviderLookup(t *testing.T) { - name := "myprovider" - myprovider := &mockProvider{} - - providerFn := func(log *logp.Logger, registry *Registry, config *conf.C) (Provider, error) { - return myprovider, nil - } - - f := newFeature( - name, - providerFn, - ) - - t.Run("adding and retrieving a provider", withRegistry(func( - t *testing.T, - global *feature.Registry, - wrapper *Registry, - ) { - err := global.Register(f) - if !assert.NoError(t, err) { - return - } - - factory, err := wrapper.Lookup(name) - if !assert.NoError(t, err) { - return - } - - // Compare func pointers instead of comparing the function value. - assert.Equal(t, reflect.ValueOf(providerFn).Pointer(), reflect.ValueOf(factory).Pointer()) - })) - - t.Run("retrieving a non existing provider", withRegistry(func( - t *testing.T, - global *feature.Registry, - wrapper *Registry, - ) { - _, err := wrapper.Lookup("unknown") - assert.Error(t, err) - })) - - t.Run("invalid provider name when doing lookup", withRegistry(func( - t *testing.T, - global *feature.Registry, - wrapper *Registry, - ) { - _, err := wrapper.Lookup("") - assert.Error(t, err) - })) -} - -func testFunctionLookup(t *testing.T) { - name := "myprovider" - myprovider := &mockProvider{} - - providerFn := func(log *logp.Logger, registry *Registry, config *conf.C) (Provider, error) { - return myprovider, nil - } - - f := newFeature( - name, - providerFn, - ) - - fnName := "myfunc" - myfunction := &mockFunction{name} - functionFn := func(provider Provider, config *conf.C) (Function, error) { - return myfunction, nil - } - - fnFeature := newFunctionFeature(name, fnName, functionFn) - - t.Run("adding and retrieving a function", withRegistry(func( - t *testing.T, - global *feature.Registry, - wrapper *Registry, - ) { - err := global.Register(f) - if !assert.NoError(t, err) { - return - } - - err = global.Register(fnFeature) - if !assert.NoError(t, err) { - return - } - - factory, err := wrapper.LookupFunction(name, fnName) - if !assert.NoError(t, err) { - return - } - - // Compare func pointers instead of comparing the function value. - assert.Equal(t, reflect.ValueOf(functionFn).Pointer(), reflect.ValueOf(factory).Pointer()) - })) - - t.Run("return an error if the provider doesn't exist", withRegistry(func( - t *testing.T, - global *feature.Registry, - wrapper *Registry, - ) { - err := global.Register(f) - if !assert.NoError(t, err) { - return - } - - err = global.Register(fnFeature) - if !assert.NoError(t, err) { - return - } - - _, err = wrapper.LookupFunction("I do not exist", fnName) - assert.Error(t, err) - })) - - t.Run("return an error if the function doesn't exist", withRegistry(func( - t *testing.T, - global *feature.Registry, - wrapper *Registry, - ) { - err := global.Register(f) - if !assert.NoError(t, err) { - return - } - - err = global.Register(fnFeature) - if !assert.NoError(t, err) { - return - } - - _, err = wrapper.LookupFunction(name, "I do not exist") - assert.Error(t, err) - })) -} - -func withRegistry(fn func(t *testing.T, global *feature.Registry, registry *Registry)) func(t *testing.T) { - return func(t *testing.T) { - global := feature.NewRegistry() - wrapped := NewRegistry(global) - fn(t, global, wrapped) - } -} - -func TestStrInSlice(t *testing.T) { - haystack := []string{"bob", "aline"} - t.Run("when in slice return position", func(t *testing.T) { - assert.Equal(t, 1, strInSlice(haystack, "aline")) - }) - - t.Run("when not in slice return -1", func(t *testing.T) { - assert.Equal(t, -1, strInSlice(haystack, "robert")) - }) -} - -func TestFindFunctionByName(t *testing.T) { - t.Run("when the function is not enabled", withRegistry(func( - t *testing.T, - global *feature.Registry, - wrapper *Registry, - ) { - configs := []*conf.C{ - conf.MustNewConfigFrom(map[string]interface{}{ - "name": "mysqs", - "type": "sqs", - "enabled": false, - }), - } - - myprovider := &mockProvider{} - - _, err := FindFunctionByName(wrapper, myprovider, configs, "mysqs") - assert.Error(t, err) - })) - - t.Run("when the function is enabled", withRegistry(func( - t *testing.T, - global *feature.Registry, - wrapper *Registry, - ) { - fnName := "sqs" - configs := []*conf.C{ - conf.MustNewConfigFrom(map[string]interface{}{ - "name": "mysqs", - "type": fnName, - "enabled": true, - }), - } - - name := "myprovider" - myprovider := &mockProvider{name: name} - - providerFn := func(log *logp.Logger, registry *Registry, config *conf.C) (Provider, error) { - return myprovider, nil - } - f := newFeature(name, providerFn) - - myfunction := &mockFunction{name} - functionFn := func(provider Provider, config *conf.C) (Function, error) { - return myfunction, nil - } - - fnFeature := newFunctionFeature(name, fnName, functionFn) - - err := global.Register(f) - if !assert.NoError(t, err) { - return - } - - err = global.Register(fnFeature) - if !assert.NoError(t, err) { - return - } - - _, err = FindFunctionByName(wrapper, myprovider, configs, "mysqs") - assert.NoError(t, err) - })) -} diff --git a/x-pack/functionbeat/function/provider/template.go b/x-pack/functionbeat/function/provider/template.go deleted file mode 100644 index d313774ccb52..000000000000 --- a/x-pack/functionbeat/function/provider/template.go +++ /dev/null @@ -1,19 +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 provider - -import ( - conf "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/logp" -) - -// TemplateBuilderFactory factory method to call to create a new template builder. -type TemplateBuilderFactory func(*logp.Logger, *conf.C, Provider) (TemplateBuilder, error) - -// TemplateBuilder generates templates for a given provider. -type TemplateBuilder interface { - // RawTemplate returns a deployable template string. - RawTemplate(string) (string, error) -} diff --git a/x-pack/functionbeat/function/telemetry/telemetry.go b/x-pack/functionbeat/function/telemetry/telemetry.go deleted file mode 100644 index 7bb4f370bf97..000000000000 --- a/x-pack/functionbeat/function/telemetry/telemetry.go +++ /dev/null @@ -1,37 +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 telemetry - -import ( - "github.com/elastic/elastic-agent-libs/monitoring" -) - -// T is a telemetry instance -type T interface { - AddTriggeredFunction() -} - -type telemetry struct { - registry *monitoring.Registry - countFunctions *monitoring.Int -} - -// New returns a new telemetry registry. -func New(r *monitoring.Registry) T { - return &telemetry{ - registry: r.NewRegistry("functions"), - countFunctions: monitoring.NewInt(r, "count"), - } -} - -// Ignored is used when the package is not monitored. -func Ignored() T { - return nil -} - -// AddTriggeredFunction adds a triggered function data to the registry. -func (t *telemetry) AddTriggeredFunction() { - t.countFunctions.Inc() -} diff --git a/x-pack/functionbeat/functionbeat.reference.yml b/x-pack/functionbeat/functionbeat.reference.yml deleted file mode 100644 index a3df78c4e2df..000000000000 --- a/x-pack/functionbeat/functionbeat.reference.yml +++ /dev/null @@ -1,1573 +0,0 @@ -########################## Functionbeat Configuration ########################### - -# This file is a full configuration example documenting all non-deprecated -# options in comments. For a shorter configuration example, that contains only -# the most common options, please see functionbeat.yml in the same directory. -# -# You can find the full configuration reference here: -# https://www.elastic.co/guide/en/beats/functionbeat/index.html - -# ================================== Provider ================================== -# Configure functions to run on AWS Lambda, currently, we assume that the credentials -# are present in the environment to correctly create the function when using the CLI. -# -# Configure which S3 endpoint should we use. -functionbeat.provider.aws.endpoint: "s3.amazonaws.com" -# Configure which S3 bucket we should upload the lambda artifact. -functionbeat.provider.aws.deploy_bucket: "functionbeat-deploy" - -# Configure credentials of Functionbeat while deploying to AWS. -# Available options: -# * access_key_id, secret_access_key and/or session_token -#functionbeat.provider.aws.access_key_id: '${AWS_ACCESS_KEY_ID:""}' -#functionbeat.provider.aws.secret_access_key: '${AWS_SECRET_ACCESS_KEY:""}' -#functionbeat.provider.aws.session_token: '${AWS_SESSION_TOKEN:""}' -# * role_arn -#functionbeat.provider.aws.role_arn: arn:aws:iam::123456789012:role/test-fnb -# * credential_profile_name and/or shared_credential_file -#functionbeat.provider.aws.credential_profile_name: fnb-aws -#functionbeat.provider.aws.shared_credential_file: /etc/functionbeat/aws_credentials - -functionbeat.provider.aws.functions: - # Define the list of functions available, each function is required to have a unique name. - # Create a function that accepts events coming from cloudwatchlogs. - - name: cloudwatch - enabled: false - type: cloudwatch_logs - - # Description of the method to help identify them when you run multiple functions. - description: "lambda function for cloudwatch logs" - - # Concurrency, is the reserved number of instances for that function. - # Default is 5. - # - # Note: There is a hard limit of 1000 functions of any kind per account. - #concurrency: 5 - - # The maximum memory allocated for this function, the configured size must be a factor of 64. - # There is a hard limit of 3008MiB for each function. Default is 128MiB. - #memory_size: 128MiB - - # The amount of time the function is allowed to run. - #timeout: 3s - - # Execution role of the function. - #role: arn:aws:iam::123456789012:role/MyFunction - - # Connect to private resources in an Amazon VPC. - #virtual_private_cloud: - # security_group_ids: [] - # subnet_ids: [] - - # Dead letter queue configuration, this must be set to an ARN pointing to an SQS queue. - #dead_letter_config.target_arn: - - # Tags are key-value pairs attached to the function. - #tags: - # department: ops - - # Optional fields that you can specify to add additional information to the - # output. Fields can be scalar values, arrays, dictionaries, or any nested - # combination of these. - #fields: - # env: staging - - # List of cloudwatch log group registered to that function. - triggers: - - log_group_name: /aws/lambda/functionbeat-cloudwatch - #filter_pattern: mylog_ - - # Define custom processors for this function. - #processors: - # - dissect: - # tokenizer: "%{key1} %{key2}" - - # Set to true to publish fields with null values in events. - #keep_null: false - - # Create a function that accepts events from SQS queues. - - name: sqs - enabled: false - type: sqs - - # Description of the method to help identify them when you run multiple functions. - description: "lambda function for SQS events" - - # Concurrency, is the reserved number of instances for that function. - # Default is 5. - # - # Note: There is a hard limit of 1000 functions of any kind per account. - #concurrency: 5 - - # The maximum memory allocated for this function, the configured size must be a factor of 64. - # There is a hard limit of 3008MiB for each function. Default is 128MiB. - #memory_size: 128MiB - - # The amount of time the function is allowed to run. - #timeout: 3s - - # Execution role of the function. - #role: arn:aws:iam::123456789012:role/MyFunction - - # Connect to private resources in an Amazon VPC. - #virtual_private_cloud: - # security_group_ids: [] - # subnet_ids: [] - - # Dead letter queue configuration, this must be set to an ARN pointing to an SQS queue. - #dead_letter_config.target_arn: - - # Tags are key-value pairs attached to the function. - #tags: - # department: ops - - # Optional fields that you can specify to add additional information to the - # output. Fields can be scalar values, arrays, dictionaries, or any nested - # combination of these. - #fields: - # env: staging - - # List of SQS queues. - triggers: - # Arn for the SQS queue. - - event_source_arn: arn:aws:sqs:us-east-1:xxxxx:myevents - - # Define custom processors for this function. - #processors: - # - decode_json_fields: - # fields: ["message"] - # process_array: false - # max_depth: 1 - # target: "" - # overwrite_keys: false - # - - # Set to true to publish fields with null values in events. - #keep_null: false - - # Create a function that accepts events from Kinesis streams. - - name: kinesis - enabled: false - type: kinesis - - # Description of the method to help identify them when you run multiple functions. - description: "lambda function for Kinesis events" - - # Concurrency, is the reserved number of instances for that function. - # Default is 5. - # - # Note: There is a hard limit of 1000 functions of any kind per account. - #concurrency: 5 - - # The maximum memory allocated for this function, the configured size must be a factor of 64. - # There is a hard limit of 3008MiB for each function. Default is 128MiB. - #memory_size: 128MiB - - # The amount of time the function is allowed to run. - #timeout: 3s - - # Execution role of the function. - #role: arn:aws:iam::123456789012:role/MyFunction - - # Connect to private resources in an Amazon VPC. - #virtual_private_cloud: - # security_group_ids: [] - # subnet_ids: [] - - # Dead letter queue configuration, this must be set to an ARN pointing to an SQS queue. - #dead_letter_config.target_arn: - - # Tags are key-value pairs attached to the function. - #tags: - # department: ops - - # Optional fields that you can specify to add additional information to the - # output. Fields can be scalar values, arrays, dictionaries, or any nested - # combination of these. - #fields: - # env: staging - - # Define custom processors for this function. - #processors: - # This example extracts the raw data from events. - # - decode_base64_field: - # field: - # from: message - # to: message - # - decompress_gzip_field: - # field: - # from: message - # to: message - # - decode_json_fields: - # fields: ["message"] - # process_array: false - # max_depth: 1 - # target: "" - # overwrite_keys: false - - # List of Kinesis streams. - triggers: - # Arn for the Kinesis stream. - - event_source_arn: arn:aws:kinesis:us-east-1:xxxxx:myevents - - # batch_size is the number of events read in a batch. - # Default is 10. - #batch_size: 100 - - # Starting position is where to start reading events from the Kinesis stream. - # Default is trim_horizon. - #starting_position: "trim_horizon" - - # parallelization_factor is the number of batches to process from each shard concurrently. - # Default is 1. - #parallelization_factor: 1 - - # Set to true to publish fields with null values in events. - #keep_null: false - - # Create a function that accepts Cloudwatch logs from Kinesis streams. - - name: cloudwatch-logs-kinesis - enabled: false - type: cloudwatch_logs_kinesis - - # Description of the method to help identify them when you run multiple functions. - description: "lambda function for Cloudwatch logs in Kinesis events" - - # Set base64_encoded if your data is base64 encoded. - #base64_encoded: false - - # Set compressed if your data is compressed with gzip. - #compressed: true - - # Concurrency, is the reserved number of instances for that function. - # Default is 5. - # - # Note: There is a hard limit of 1000 functions of any kind per account. - #concurrency: 5 - - # The maximum memory allocated for this function, the configured size must be a factor of 64. - # There is a hard limit of 3008MiB for each function. Default is 128MiB. - #memory_size: 128MiB - - # Dead letter queue configuration, this must be set to an ARN pointing to an SQS queue. - #dead_letter_config.target_arn: - - # Tags are key-value pairs attached to the function. - #tags: - # department: ops - - # The amount of time the function is allowed to run. - #timeout: 3s - - # Execution role of the function. - #role: arn:aws:iam::123456789012:role/MyFunction - - # Connect to private resources in an Amazon VPC. - #virtual_private_cloud: - # security_group_ids: [] - # subnet_ids: [] - # - # Define custom processors for this function. - #processors: - # - decode_json_fields: - # fields: ["message"] - # process_array: false - # max_depth: 1 - # target: "" - # overwrite_keys: false - - # List of Kinesis streams. - triggers: - # Arn for the Kinesis stream. - - event_source_arn: arn:aws:kinesis:us-east-1:xxxxx:myevents - - # batch_size is the number of events read in a batch. - # Default is 10. - #batch_size: 100 - - # Starting position is where to start reading events from the Kinesis stream. - # Default is trim_horizon. - #starting_position: "trim_horizon" - - # parallelization_factor is the number of batches to process from each shard concurrently. - # Default is 1. - #parallelization_factor: 1 - - # Set to true to publish fields with null values in events. - #keep_null: false - -# ================================== General =================================== - -# The name of the shipper that publishes the network data. It can be used to group -# all the transactions sent by a single shipper in the web interface. -# If this option is not defined, the hostname is used. -#name: - -# The tags of the shipper are included in their field with each -# transaction published. Tags make it easy to group servers by different -# logical properties. -#tags: ["service-X", "web-tier"] - -# Optional fields that you can specify to add additional information to the -# output. Fields can be scalar values, arrays, dictionaries, or any nested -# combination of these. -#fields: -# env: staging - -# If this option is set to true, the custom fields are stored as top-level -# fields in the output document instead of being grouped under a field -# sub-dictionary. Default is false. -#fields_under_root: false - -# Configure the precision of all timestamps in Functionbeat. -# Available options: millisecond, microsecond, nanosecond -#timestamp.precision: millisecond - -# Internal queue configuration for buffering events to be published. -# Queue settings may be overridden by performance presets in the -# Elasticsearch output. To configure them manually use "preset: custom". -#queue: - # Queue type by name (default 'mem') - # The memory queue will present all available events (up to the outputs - # bulk_max_size) to the output, the moment the output is ready to serve - # another batch of events. - #mem: - # Max number of events the queue can buffer. - #events: 3200 - - # Hints the minimum number of events stored in the queue, - # before providing a batch of events to the outputs. - # The default value is set to 2048. - # A value of 0 ensures events are immediately available - # to be sent to the outputs. - #flush.min_events: 1600 - - # Maximum duration after which events are available to the outputs, - # if the number of events stored in the queue is < `flush.min_events`. - #flush.timeout: 10s - - # The disk queue stores incoming events on disk until the output is - # ready for them. This allows a higher event limit than the memory-only - # queue and lets pending events persist through a restart. - #disk: - # The directory path to store the queue's data. - #path: "${path.data}/diskqueue" - - # The maximum space the queue should occupy on disk. Depending on - # input settings, events that exceed this limit are delayed or discarded. - #max_size: 10GB - - # The maximum size of a single queue data file. Data in the queue is - # stored in smaller segments that are deleted after all their events - # have been processed. - #segment_size: 1GB - - # The number of events to read from disk to memory while waiting for - # the output to request them. - #read_ahead: 512 - - # The number of events to accept from inputs while waiting for them - # to be written to disk. If event data arrives faster than it - # can be written to disk, this setting prevents it from overflowing - # main memory. - #write_ahead: 2048 - - # The duration to wait before retrying when the queue encounters a disk - # write error. - #retry_interval: 1s - - # The maximum length of time to wait before retrying on a disk write - # error. If the queue encounters repeated errors, it will double the - # length of its retry interval each time, up to this maximum. - #max_retry_interval: 30s - -# Sets the maximum number of CPUs that can be executed simultaneously. The -# default is the number of logical CPUs available in the system. -#max_procs: - -# ================================= Processors ================================= - -# Processors are used to reduce the number of fields in the exported event or to -# enhance the event with external metadata. This section defines a list of -# processors that are applied one by one and the first one receives the initial -# event: -# -# event -> filter1 -> event1 -> filter2 ->event2 ... -# -# The supported processors are drop_fields, drop_event, include_fields, -# decode_json_fields, and add_cloud_metadata. -# -# For example, you can use the following processors to keep the fields that -# contain CPU load percentages, but remove the fields that contain CPU ticks -# values: -# -#processors: -# - include_fields: -# fields: ["cpu"] -# - drop_fields: -# fields: ["cpu.user", "cpu.system"] -# -# The following example drops the events that have the HTTP response code 200: -# -#processors: -# - drop_event: -# when: -# equals: -# http.code: 200 -# -# The following example renames the field a to b: -# -#processors: -# - rename: -# fields: -# - from: "a" -# to: "b" -# -# The following example tokenizes the string into fields: -# -#processors: -# - dissect: -# tokenizer: "%{key1} - %{key2}" -# field: "message" -# target_prefix: "dissect" -# -# The following example enriches each event with metadata from the cloud -# provider about the host machine. It works on EC2, GCE, DigitalOcean, -# Tencent Cloud, and Alibaba Cloud. -# -#processors: -# - add_cloud_metadata: ~ -# -# The following example enriches each event with the machine's local time zone -# offset from UTC. -# -#processors: -# - add_locale: -# format: offset -# -# The following example enriches each event with docker metadata, it matches -# given fields to an existing container id and adds info from that container: -# -#processors: -# - add_docker_metadata: -# host: "unix:///var/run/docker.sock" -# match_fields: ["system.process.cgroup.id"] -# match_pids: ["process.pid", "process.parent.pid"] -# match_source: true -# match_source_index: 4 -# match_short_id: false -# cleanup_timeout: 60 -# labels.dedot: false -# # To connect to Docker over TLS you must specify a client and CA certificate. -# #ssl: -# # certificate_authority: "/etc/pki/root/ca.pem" -# # certificate: "/etc/pki/client/cert.pem" -# # key: "/etc/pki/client/cert.key" -# -# The following example enriches each event with docker metadata, it matches -# container id from log path available in `source` field (by default it expects -# it to be /var/lib/docker/containers/*/*.log). -# -#processors: -# - add_docker_metadata: ~ -# -# The following example enriches each event with host metadata. -# -#processors: -# - add_host_metadata: ~ -# -# The following example enriches each event with process metadata using -# process IDs included in the event. -# -#processors: -# - add_process_metadata: -# match_pids: ["system.process.ppid"] -# target: system.process.parent -# -# The following example decodes fields containing JSON strings -# and replaces the strings with valid JSON objects. -# -#processors: -# - decode_json_fields: -# fields: ["field1", "field2", ...] -# process_array: false -# max_depth: 1 -# target: "" -# overwrite_keys: false -# -#processors: -# - decompress_gzip_field: -# from: "field1" -# to: "field2" -# ignore_missing: false -# fail_on_error: true -# -# The following example copies the value of the message to message_copied -# -#processors: -# - copy_fields: -# fields: -# - from: message -# to: message_copied -# fail_on_error: true -# ignore_missing: false -# -# The following example truncates the value of the message to 1024 bytes -# -#processors: -# - truncate_fields: -# fields: -# - message -# max_bytes: 1024 -# fail_on_error: false -# ignore_missing: true -# -# The following example preserves the raw message under event.original -# -#processors: -# - copy_fields: -# fields: -# - from: message -# to: event.original -# fail_on_error: false -# ignore_missing: true -# - truncate_fields: -# fields: -# - event.original -# max_bytes: 1024 -# fail_on_error: false -# ignore_missing: true -# -# The following example URL-decodes the value of field1 to field2 -# -#processors: -# - urldecode: -# fields: -# - from: "field1" -# to: "field2" -# ignore_missing: false -# fail_on_error: true - -# =============================== Elastic Cloud ================================ - -# These settings simplify using Functionbeat with the Elastic Cloud (https://cloud.elastic.co/). - -# The cloud.id setting overwrites the `output.elasticsearch.hosts` and -# `setup.kibana.host` options. -# You can find the `cloud.id` in the Elastic Cloud web UI. -#cloud.id: - -# The cloud.auth setting overwrites the `output.elasticsearch.username` and -# `output.elasticsearch.password` settings. The format is `:`. -#cloud.auth: - -# ================================== Outputs =================================== - -# Configure what output to use when sending the data collected by the beat. - -# ---------------------------- Elasticsearch Output ---------------------------- -output.elasticsearch: - # Boolean flag to enable or disable the output module. - #enabled: true - - # Array of hosts to connect to. - # Scheme and port can be left out and will be set to the default (http and 9200) - # In case you specify and additional path, the scheme is required: http://localhost:9200/path - # IPv6 addresses should always be defined as: https://[2001:db8::1]:9200 - hosts: ["localhost:9200"] - - # Performance presets configure other output fields to recommended values - # based on a performance priority. - # Options are "balanced", "throughput", "scale", "latency" and "custom". - # Default if unspecified: "custom" - preset: balanced - - # Set gzip compression level. Set to 0 to disable compression. - # This field may conflict with performance presets. To set it - # manually use "preset: custom". - # The default is 1. - #compression_level: 1 - - # Configure escaping HTML symbols in strings. - #escape_html: false - - # Protocol - either `http` (default) or `https`. - #protocol: "https" - - # Authentication credentials - either API key or username/password. - #api_key: "id:api_key" - #username: "elastic" - #password: "changeme" - - # Dictionary of HTTP parameters to pass within the URL with index operations. - #parameters: - #param1: value1 - #param2: value2 - - # Number of workers per Elasticsearch host. - # This field may conflict with performance presets. To set it - # manually use "preset: custom". - #worker: 1 - - # If set to true and multiple hosts are configured, the output plugin load - # balances published events onto all Elasticsearch hosts. If set to false, - # the output plugin sends all events to only one host (determined at random) - # and will switch to another host if the currently selected one becomes - # unreachable. The default value is true. - #loadbalance: true - - # Optional data stream or index name. The default is "functionbeat-%{[agent.version]}". - # In case you modify this pattern you must update setup.template.name and setup.template.pattern accordingly. - #index: "functionbeat-%{[agent.version]}" - - # Optional ingest pipeline. By default, no pipeline will be used. - #pipeline: "" - - # Optional HTTP path - #path: "/elasticsearch" - - # Custom HTTP headers to add to each request - #headers: - # X-My-Header: Contents of the header - - # Proxy server URL - #proxy_url: http://proxy:3128 - - # Whether to disable proxy settings for outgoing connections. If true, this - # takes precedence over both the proxy_url field and any environment settings - # (HTTP_PROXY, HTTPS_PROXY). The default is false. - #proxy_disable: false - - # The number of times a particular Elasticsearch index operation is attempted. If - # the indexing operation doesn't succeed after this many retries, the events are - # dropped. The default is 3. - #max_retries: 3 - - # The maximum number of events to bulk in a single Elasticsearch bulk API index request. - # This field may conflict with performance presets. To set it - # manually use "preset: custom". - # The default is 1600. - #bulk_max_size: 1600 - - # The number of seconds to wait before trying to reconnect to Elasticsearch - # after a network error. After waiting backoff.init seconds, the Beat - # tries to reconnect. If the attempt fails, the backoff timer is increased - # exponentially up to backoff.max. After a successful connection, the backoff - # timer is reset. The default is 1s. - #backoff.init: 1s - - # The maximum number of seconds to wait before attempting to connect to - # Elasticsearch after a network error. The default is 60s. - #backoff.max: 60s - - # The maximum amount of time an idle connection will remain idle - # before closing itself. Zero means use the default of 60s. The - # format is a Go language duration (example 60s is 60 seconds). - # This field may conflict with performance presets. To set it - # manually use "preset: custom". - # The default is 3s. - # idle_connection_timeout: 3s - - # Configure HTTP request timeout before failing a request to Elasticsearch. - #timeout: 90 - - # Prevents functionbeat from connecting to older Elasticsearch versions when set to `false` - #allow_older_versions: true - - # Use SSL settings for HTTPS. - #ssl.enabled: true - - # Controls the verification of certificates. Valid values are: - # * full, which verifies that the provided certificate is signed by a trusted - # authority (CA) and also verifies that the server's hostname (or IP address) - # matches the names identified within the certificate. - # * strict, which verifies that the provided certificate is signed by a trusted - # authority (CA) and also verifies that the server's hostname (or IP address) - # matches the names identified within the certificate. If the Subject Alternative - # Name is empty, it returns an error. - # * certificate, which verifies that the provided certificate is signed by a - # trusted authority (CA), but does not perform any hostname verification. - # * none, which performs no verification of the server's certificate. This - # mode disables many of the security benefits of SSL/TLS and should only be used - # after very careful consideration. It is primarily intended as a temporary - # diagnostic mechanism when attempting to resolve TLS errors; its use in - # production environments is strongly discouraged. - # The default value is full. - #ssl.verification_mode: full - - # List of supported/valid TLS versions. By default all TLS versions from 1.1 - # up to 1.3 are enabled. - #ssl.supported_protocols: [TLSv1.1, TLSv1.2, TLSv1.3] - - # List of root certificates for HTTPS server verifications - #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] - - # Certificate for SSL client authentication - #ssl.certificate: "/etc/pki/client/cert.pem" - - # Client certificate key - #ssl.key: "/etc/pki/client/cert.key" - - # Optional passphrase for decrypting the certificate key. - #ssl.key_passphrase: '' - - # Configure cipher suites to be used for SSL connections - #ssl.cipher_suites: [] - - # Configure curve types for ECDHE-based cipher suites - #ssl.curve_types: [] - - # Configure what types of renegotiation are supported. Valid options are - # never, once, and freely. Default is never. - #ssl.renegotiation: never - - # Configure a pin that can be used to do extra validation of the verified certificate chain, - # this allow you to ensure that a specific certificate is used to validate the chain of trust. - # - # The pin is a base64 encoded string of the SHA-256 fingerprint. - #ssl.ca_sha256: "" - - # A root CA HEX encoded fingerprint. During the SSL handshake if the - # fingerprint matches the root CA certificate, it will be added to - # the provided list of root CAs (`certificate_authorities`), if the - # list is empty or not defined, the matching certificate will be the - # only one in the list. Then the normal SSL validation happens. - #ssl.ca_trusted_fingerprint: "" - - - # Enables restarting functionbeat if any file listed by `key`, - # `certificate`, or `certificate_authorities` is modified. - # This feature IS NOT supported on Windows. - #ssl.restart_on_cert_change.enabled: false - - # Period to scan for changes on CA certificate files - #ssl.restart_on_cert_change.period: 1m - - # Enable Kerberos support. Kerberos is automatically enabled if any Kerberos setting is set. - #kerberos.enabled: true - - # Authentication type to use with Kerberos. Available options: keytab, password. - #kerberos.auth_type: password - - # Path to the keytab file. It is used when auth_type is set to keytab. - #kerberos.keytab: /etc/elastic.keytab - - # Path to the Kerberos configuration. - #kerberos.config_path: /etc/krb5.conf - - # Name of the Kerberos user. - #kerberos.username: elastic - - # Password of the Kerberos user. It is used when auth_type is set to password. - #kerberos.password: changeme - - # Kerberos realm. - #kerberos.realm: ELASTIC - - -# ------------------------------ Logstash Output ------------------------------- -#output.logstash: - # Boolean flag to enable or disable the output module. - #enabled: true - - # The Logstash hosts - #hosts: ["localhost:5044"] - - # Number of workers per Logstash host. - #worker: 1 - - # Set gzip compression level. - #compression_level: 3 - - # Configure escaping HTML symbols in strings. - #escape_html: false - - # Optional maximum time to live for a connection to Logstash, after which the - # connection will be re-established. A value of `0s` (the default) will - # disable this feature. - # - # Not yet supported for async connections (i.e. with the "pipelining" option set) - #ttl: 30s - - # Optionally load-balance events between Logstash hosts. Default is false. - #loadbalance: false - - # Number of batches to be sent asynchronously to Logstash while processing - # new batches. - #pipelining: 2 - - # If enabled only a subset of events in a batch of events is transferred per - # transaction. The number of events to be sent increases up to `bulk_max_size` - # if no error is encountered. - #slow_start: false - - # The number of seconds to wait before trying to reconnect to Logstash - # after a network error. After waiting backoff.init seconds, the Beat - # tries to reconnect. If the attempt fails, the backoff timer is increased - # exponentially up to backoff.max. After a successful connection, the backoff - # timer is reset. The default is 1s. - #backoff.init: 1s - - # The maximum number of seconds to wait before attempting to connect to - # Logstash after a network error. The default is 60s. - #backoff.max: 60s - - # Optional index name. The default index name is set to functionbeat - # in all lowercase. - #index: 'functionbeat' - - # SOCKS5 proxy server URL - #proxy_url: socks5://user:password@socks5-server:2233 - - # Resolve names locally when using a proxy server. Defaults to false. - #proxy_use_local_resolver: false - - # Use SSL settings for HTTPS. - #ssl.enabled: true - - # Controls the verification of certificates. Valid values are: - # * full, which verifies that the provided certificate is signed by a trusted - # authority (CA) and also verifies that the server's hostname (or IP address) - # matches the names identified within the certificate. - # * strict, which verifies that the provided certificate is signed by a trusted - # authority (CA) and also verifies that the server's hostname (or IP address) - # matches the names identified within the certificate. If the Subject Alternative - # Name is empty, it returns an error. - # * certificate, which verifies that the provided certificate is signed by a - # trusted authority (CA), but does not perform any hostname verification. - # * none, which performs no verification of the server's certificate. This - # mode disables many of the security benefits of SSL/TLS and should only be used - # after very careful consideration. It is primarily intended as a temporary - # diagnostic mechanism when attempting to resolve TLS errors; its use in - # production environments is strongly discouraged. - # The default value is full. - #ssl.verification_mode: full - - # List of supported/valid TLS versions. By default all TLS versions from 1.1 - # up to 1.3 are enabled. - #ssl.supported_protocols: [TLSv1.1, TLSv1.2, TLSv1.3] - - # List of root certificates for HTTPS server verifications - #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] - - # Certificate for SSL client authentication - #ssl.certificate: "/etc/pki/client/cert.pem" - - # Client certificate key - #ssl.key: "/etc/pki/client/cert.key" - - # Optional passphrase for decrypting the certificate key. - #ssl.key_passphrase: '' - - # Configure cipher suites to be used for SSL connections - #ssl.cipher_suites: [] - - # Configure curve types for ECDHE-based cipher suites - #ssl.curve_types: [] - - # Configure what types of renegotiation are supported. Valid options are - # never, once, and freely. Default is never. - #ssl.renegotiation: never - - # Configure a pin that can be used to do extra validation of the verified certificate chain, - # this allow you to ensure that a specific certificate is used to validate the chain of trust. - # - # The pin is a base64 encoded string of the SHA-256 fingerprint. - #ssl.ca_sha256: "" - - # A root CA HEX encoded fingerprint. During the SSL handshake if the - # fingerprint matches the root CA certificate, it will be added to - # the provided list of root CAs (`certificate_authorities`), if the - # list is empty or not defined, the matching certificate will be the - # only one in the list. Then the normal SSL validation happens. - #ssl.ca_trusted_fingerprint: "" - - # Enables restarting functionbeat if any file listed by `key`, - # `certificate`, or `certificate_authorities` is modified. - # This feature IS NOT supported on Windows. - #ssl.restart_on_cert_change.enabled: false - - # Period to scan for changes on CA certificate files - #ssl.restart_on_cert_change.period: 1m - - # The number of times to retry publishing an event after a publishing failure. - # After the specified number of retries, the events are typically dropped. - # Some Beats, such as Filebeat and Winlogbeat, ignore the max_retries setting - # and retry until all events are published. Set max_retries to a value less - # than 0 to retry until all events are published. The default is 3. - #max_retries: 3 - - # The maximum number of events to bulk in a single Logstash request. The - # default is 2048. - #bulk_max_size: 2048 - - # The number of seconds to wait for responses from the Logstash server before - # timing out. The default is 30s. - #timeout: 30s - - - - -# ------------------------------- Console Output ------------------------------- -#output.console: - # Boolean flag to enable or disable the output module. - #enabled: true - - # Configure JSON encoding - #codec.json: - # Pretty-print JSON event - #pretty: false - - # Configure escaping HTML symbols in strings. - #escape_html: false - -# =================================== Paths ==================================== - -# The home path for the Functionbeat installation. This is the default base path -# for all other path settings and for miscellaneous files that come with the -# distribution (for example, the sample dashboards). -# If not set by a CLI flag or in the configuration file, the default for the -# home path is the location of the binary. -#path.home: - -# The configuration path for the Functionbeat installation. This is the default -# base path for configuration files, including the main YAML configuration file -# and the Elasticsearch template file. If not set by a CLI flag or in the -# configuration file, the default for the configuration path is the home path. -#path.config: ${path.home} - -# The data path for the Functionbeat installation. This is the default base path -# for all the files in which Functionbeat needs to store its data. If not set by a -# CLI flag or in the configuration file, the default for the data path is a data -# subdirectory inside the home path. -#path.data: ${path.home}/data - -# The logs path for a Functionbeat installation. This is the default location for -# the Beat's log files. If not set by a CLI flag or in the configuration file, -# the default for the logs path is a logs subdirectory inside the home path. -#path.logs: ${path.home}/logs - -# ================================== Keystore ================================== - -# Location of the Keystore containing the keys and their sensitive values. -#keystore.path: "${path.config}/beats.keystore" - -# ================================= Dashboards ================================= - -# These settings control loading the sample dashboards to the Kibana index. Loading -# the dashboards are disabled by default and can be enabled either by setting the -# options here or by using the `-setup` CLI flag or the `setup` command. -#setup.dashboards.enabled: false - -# The directory from where to read the dashboards. The default is the `kibana` -# folder in the home path. -#setup.dashboards.directory: ${path.home}/kibana - -# The URL from where to download the dashboard archive. It is used instead of -# the directory if it has a value. -#setup.dashboards.url: - -# The file archive (zip file) from where to read the dashboards. It is used instead -# of the directory when it has a value. -#setup.dashboards.file: - -# In case the archive contains the dashboards from multiple Beats, this lets you -# select which one to load. You can load all the dashboards in the archive by -# setting this to the empty string. -#setup.dashboards.beat: functionbeat - -# The name of the Kibana index to use for setting the configuration. Default is ".kibana" -#setup.dashboards.kibana_index: .kibana - -# The Elasticsearch index name. This overwrites the index name defined in the -# dashboards and index pattern. Example: testbeat-* -#setup.dashboards.index: - -# Always use the Kibana API for loading the dashboards instead of autodetecting -# how to install the dashboards by first querying Elasticsearch. -#setup.dashboards.always_kibana: false - -# If true and Kibana is not reachable at the time when dashboards are loaded, -# it will retry to reconnect to Kibana instead of exiting with an error. -#setup.dashboards.retry.enabled: false - -# Duration interval between Kibana connection retries. -#setup.dashboards.retry.interval: 1s - -# Maximum number of retries before exiting with an error, 0 for unlimited retrying. -#setup.dashboards.retry.maximum: 0 - -# ================================== Template ================================== - -# A template is used to set the mapping in Elasticsearch -# By default template loading is enabled and the template is loaded. -# These settings can be adjusted to load your own template or overwrite existing ones. - -# Set to false to disable template loading. -#setup.template.enabled: true - -# Template name. By default the template name is "functionbeat-%{[agent.version]}" -# The template name and pattern has to be set in case the Elasticsearch index pattern is modified. -#setup.template.name: "functionbeat-%{[agent.version]}" - -# Template pattern. By default the template pattern is "functionbeat-%{[agent.version]}" to apply to the default index settings. -# The template name and pattern has to be set in case the Elasticsearch index pattern is modified. -#setup.template.pattern: "functionbeat-%{[agent.version]}" - -# Path to fields.yml file to generate the template -#setup.template.fields: "${path.config}/fields.yml" - -# A list of fields to be added to the template and Kibana index pattern. Also -# specify setup.template.overwrite: true to overwrite the existing template. -#setup.template.append_fields: -#- name: field_name -# type: field_type - -# Enable JSON template loading. If this is enabled, the fields.yml is ignored. -#setup.template.json.enabled: false - -# Path to the JSON template file -#setup.template.json.path: "${path.config}/template.json" - -# Name under which the template is stored in Elasticsearch -#setup.template.json.name: "" - -# Set this option if the JSON template is a data stream. -#setup.template.json.data_stream: false - -# Overwrite existing template -# Do not enable this option for more than one instance of functionbeat as it might -# overload your Elasticsearch with too many update requests. -#setup.template.overwrite: false - -# Elasticsearch template settings -setup.template.settings: - - # A dictionary of settings to place into the settings.index dictionary - # of the Elasticsearch template. For more details, please check - # https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html - #index: - #number_of_shards: 1 - #codec: best_compression - - # A dictionary of settings for the _source field. For more details, please check - # https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-source-field.html - #_source: - #enabled: false - -# ====================== Index Lifecycle Management (ILM) ====================== - -# Configure index lifecycle management (ILM) to manage the backing indices -# of your data streams. - -# Enable ILM support. Valid values are true, or false. -#setup.ilm.enabled: true - -# Set the lifecycle policy name. The default policy name is -# 'beatname'. -#setup.ilm.policy_name: "mypolicy" - -# The path to a JSON file that contains a lifecycle policy configuration. Used -# to load your own lifecycle policy. -#setup.ilm.policy_file: - -# Disable the check for an existing lifecycle policy. The default is true. -# If you set this option to false, lifecycle policy will not be installed, -# even if setup.ilm.overwrite is set to true. -#setup.ilm.check_exists: true - -# Overwrite the lifecycle policy at startup. The default is false. -#setup.ilm.overwrite: false - -# ======================== Data Stream Lifecycle (DSL) ========================= - -# Configure Data Stream Lifecycle to manage data streams while connected to Serverless elasticsearch. -# These settings are mutually exclusive with ILM settings which are not supported in Serverless projects. - -# Enable DSL support. Valid values are true, or false. -#setup.dsl.enabled: true - -# Set the lifecycle policy name or pattern. For DSL, this name must match the data stream that the lifecycle is for. -# The default data stream pattern is functionbeat-%{[agent.version]}" -# The template string `%{[agent.version]}` will resolve to the current stack version. -# The other possible template value is `%{[beat.name]}`. -#setup.dsl.data_stream_pattern: "functionbeat-%{[agent.version]}" - -# The path to a JSON file that contains a lifecycle policy configuration. Used -# to load your own lifecycle policy. -# If no custom policy is specified, a default policy with a lifetime of 7 days will be created. -#setup.dsl.policy_file: - -# Disable the check for an existing lifecycle policy. The default is true. If -# you disable this check, set setup.dsl.overwrite: true so the lifecycle policy -# can be installed. -#setup.dsl.check_exists: true - -# Overwrite the lifecycle policy at startup. The default is false. -#setup.dsl.overwrite: false - -# =================================== Kibana =================================== - -# Starting with Beats version 6.0.0, the dashboards are loaded via the Kibana API. -# This requires a Kibana endpoint configuration. -setup.kibana: - - # Kibana Host - # Scheme and port can be left out and will be set to the default (http and 5601) - # In case you specify and additional path, the scheme is required: http://localhost:5601/path - # IPv6 addresses should always be defined as: https://[2001:db8::1]:5601 - #host: "localhost:5601" - - # Optional protocol and basic auth credentials. - #protocol: "https" - #username: "elastic" - #password: "changeme" - - # Optional HTTP path - #path: "" - - # Optional Kibana space ID. - #space.id: "" - - # Custom HTTP headers to add to each request - #headers: - # X-My-Header: Contents of the header - - # Use SSL settings for HTTPS. - #ssl.enabled: true - - # Controls the verification of certificates. Valid values are: - # * full, which verifies that the provided certificate is signed by a trusted - # authority (CA) and also verifies that the server's hostname (or IP address) - # matches the names identified within the certificate. - # * strict, which verifies that the provided certificate is signed by a trusted - # authority (CA) and also verifies that the server's hostname (or IP address) - # matches the names identified within the certificate. If the Subject Alternative - # Name is empty, it returns an error. - # * certificate, which verifies that the provided certificate is signed by a - # trusted authority (CA), but does not perform any hostname verification. - # * none, which performs no verification of the server's certificate. This - # mode disables many of the security benefits of SSL/TLS and should only be used - # after very careful consideration. It is primarily intended as a temporary - # diagnostic mechanism when attempting to resolve TLS errors; its use in - # production environments is strongly discouraged. - # The default value is full. - #ssl.verification_mode: full - - # List of supported/valid TLS versions. By default all TLS versions from 1.1 - # up to 1.3 are enabled. - #ssl.supported_protocols: [TLSv1.1, TLSv1.2, TLSv1.3] - - # List of root certificates for HTTPS server verifications - #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] - - # Certificate for SSL client authentication - #ssl.certificate: "/etc/pki/client/cert.pem" - - # Client certificate key - #ssl.key: "/etc/pki/client/cert.key" - - # Optional passphrase for decrypting the certificate key. - #ssl.key_passphrase: '' - - # Configure cipher suites to be used for SSL connections - #ssl.cipher_suites: [] - - # Configure curve types for ECDHE-based cipher suites - #ssl.curve_types: [] - - # Configure what types of renegotiation are supported. Valid options are - # never, once, and freely. Default is never. - #ssl.renegotiation: never - - # Configure a pin that can be used to do extra validation of the verified certificate chain, - # this allow you to ensure that a specific certificate is used to validate the chain of trust. - # - # The pin is a base64 encoded string of the SHA-256 fingerprint. - #ssl.ca_sha256: "" - - # A root CA HEX encoded fingerprint. During the SSL handshake if the - # fingerprint matches the root CA certificate, it will be added to - # the provided list of root CAs (`certificate_authorities`), if the - # list is empty or not defined, the matching certificate will be the - # only one in the list. Then the normal SSL validation happens. - #ssl.ca_trusted_fingerprint: "" - - -# ================================== Logging =================================== - -# There are four options for the log output: file, stderr, syslog, eventlog -# The file output is the default. - -# Sets log level. The default log level is info. -# Available log levels are: error, warning, info, debug -#logging.level: info - -# Enable debug output for selected components. To enable all selectors use ["*"] -# Other available selectors are "beat", "publisher", "service" -# Multiple selectors can be chained. -#logging.selectors: [ ] - -# Send all logging output to stderr. The default is false. -#logging.to_stderr: false - -# Send all logging output to syslog. The default is false. -#logging.to_syslog: false - -# Send all logging output to Windows Event Logs. The default is false. -#logging.to_eventlog: false - -# If enabled, Functionbeat periodically logs its internal metrics that have changed -# in the last period. For each metric that changed, the delta from the value at -# the beginning of the period is logged. Also, the total values for -# all non-zero internal metrics are logged on shutdown. The default is true. -#logging.metrics.enabled: true - -# The period after which to log the internal metrics. The default is 30s. -#logging.metrics.period: 30s - -# A list of metrics namespaces to report in the logs. Defaults to [stats]. -# `stats` contains general Beat metrics. `dataset` may be present in some -# Beats and contains module or input metrics. -#logging.metrics.namespaces: [stats] - -# Logging to rotating files. Set logging.to_files to false to disable logging to -# files. -logging.to_files: true -logging.files: - # Configure the path where the logs are written. The default is the logs directory - # under the home path (the binary location). - #path: /var/log/functionbeat - - # The name of the files where the logs are written to. - #name: functionbeat - - # Configure log file size limit. If the limit is reached, log file will be - # automatically rotated. - #rotateeverybytes: 10485760 # = 10MB - - # Number of rotated log files to keep. The oldest files will be deleted first. - #keepfiles: 7 - - # The permissions mask to apply when rotating log files. The default value is 0600. - # Must be a valid Unix-style file permissions mask expressed in octal notation. - #permissions: 0600 - - # Enable log file rotation on time intervals in addition to the size-based rotation. - # Intervals must be at least 1s. Values of 1m, 1h, 24h, 7*24h, 30*24h, and 365*24h - # are boundary-aligned with minutes, hours, days, weeks, months, and years as - # reported by the local system clock. All other intervals are calculated from the - # Unix epoch. Defaults to disabled. - #interval: 0 - - # Rotate existing logs on startup rather than appending them to the existing - # file. Defaults to true. - # rotateonstartup: true - -#=============================== Events Logging =============================== -# Some outputs will log raw events on errors like indexing errors in the -# Elasticsearch output, to prevent logging raw events (that may contain -# sensitive information) together with other log messages, a different -# log file, only for log entries containing raw events, is used. It will -# use the same level, selectors and all other configurations from the -# default logger, but it will have it's own file configuration. -# -# Having a different log file for raw events also prevents event data -# from drowning out the regular log files. -# -# IMPORTANT: No matter the default logger output configuration, raw events -# will **always** be logged to a file configured by `logging.event_data.files`. - -# logging.event_data: -# Logging to rotating files. Set logging.to_files to false to disable logging to -# files. -#logging.event_data.to_files: true -#logging.event_data: - # Configure the path where the logs are written. The default is the logs directory - # under the home path (the binary location). - #path: /var/log/functionbeat - - # The name of the files where the logs are written to. - #name: functionbeat-event-data - - # Configure log file size limit. If the limit is reached, log file will be - # automatically rotated. - #rotateeverybytes: 5242880 # = 5MB - - # Number of rotated log files to keep. The oldest files will be deleted first. - #keepfiles: 2 - - # The permissions mask to apply when rotating log files. The default value is 0600. - # Must be a valid Unix-style file permissions mask expressed in octal notation. - #permissions: 0600 - - # Enable log file rotation on time intervals in addition to the size-based rotation. - # Intervals must be at least 1s. Values of 1m, 1h, 24h, 7*24h, 30*24h, and 365*24h - # are boundary-aligned with minutes, hours, days, weeks, months, and years as - # reported by the local system clock. All other intervals are calculated from the - # Unix epoch. Defaults to disabled. - #interval: 0 - - # Rotate existing logs on startup rather than appending them to the existing - # file. Defaults to false. - # rotateonstartup: false - -# ============================= X-Pack Monitoring ============================== -# Functionbeat can export internal metrics to a central Elasticsearch monitoring -# cluster. This requires xpack monitoring to be enabled in Elasticsearch. The -# reporting is disabled by default. - -# Set to true to enable the monitoring reporter. -#monitoring.enabled: false - -# Sets the UUID of the Elasticsearch cluster under which monitoring data for this -# Functionbeat instance will appear in the Stack Monitoring UI. If output.elasticsearch -# is enabled, the UUID is derived from the Elasticsearch cluster referenced by output.elasticsearch. -#monitoring.cluster_uuid: - -# Uncomment to send the metrics to Elasticsearch. Most settings from the -# Elasticsearch output are accepted here as well. -# Note that the settings should point to your Elasticsearch *monitoring* cluster. -# Any setting that is not set is automatically inherited from the Elasticsearch -# output configuration, so if you have the Elasticsearch output configured such -# that it is pointing to your Elasticsearch monitoring cluster, you can simply -# uncomment the following line. -#monitoring.elasticsearch: - - # Array of hosts to connect to. - # Scheme and port can be left out and will be set to the default (http and 9200) - # In case you specify an additional path, the scheme is required: http://localhost:9200/path - # IPv6 addresses should always be defined as: https://[2001:db8::1]:9200 - #hosts: ["localhost:9200"] - - # Set gzip compression level. - #compression_level: 0 - - # Protocol - either `http` (default) or `https`. - #protocol: "https" - - # Authentication credentials - either API key or username/password. - #api_key: "id:api_key" - #username: "beats_system" - #password: "changeme" - - # Dictionary of HTTP parameters to pass within the URL with index operations. - #parameters: - #param1: value1 - #param2: value2 - - # Custom HTTP headers to add to each request - #headers: - # X-My-Header: Contents of the header - - # Proxy server url - #proxy_url: http://proxy:3128 - - # The number of times a particular Elasticsearch index operation is attempted. If - # the indexing operation doesn't succeed after this many retries, the events are - # dropped. The default is 3. - #max_retries: 3 - - # The maximum number of events to bulk in a single Elasticsearch bulk API index request. - # The default is 50. - #bulk_max_size: 50 - - # The number of seconds to wait before trying to reconnect to Elasticsearch - # after a network error. After waiting backoff.init seconds, the Beat - # tries to reconnect. If the attempt fails, the backoff timer is increased - # exponentially up to backoff.max. After a successful connection, the backoff - # timer is reset. The default is 1s. - #backoff.init: 1s - - # The maximum number of seconds to wait before attempting to connect to - # Elasticsearch after a network error. The default is 60s. - #backoff.max: 60s - - # Configure HTTP request timeout before failing a request to Elasticsearch. - #timeout: 90 - - # Use SSL settings for HTTPS. - #ssl.enabled: true - - # Controls the verification of certificates. Valid values are: - # * full, which verifies that the provided certificate is signed by a trusted - # authority (CA) and also verifies that the server's hostname (or IP address) - # matches the names identified within the certificate. - # * strict, which verifies that the provided certificate is signed by a trusted - # authority (CA) and also verifies that the server's hostname (or IP address) - # matches the names identified within the certificate. If the Subject Alternative - # Name is empty, it returns an error. - # * certificate, which verifies that the provided certificate is signed by a - # trusted authority (CA), but does not perform any hostname verification. - # * none, which performs no verification of the server's certificate. This - # mode disables many of the security benefits of SSL/TLS and should only be used - # after very careful consideration. It is primarily intended as a temporary - # diagnostic mechanism when attempting to resolve TLS errors; its use in - # production environments is strongly discouraged. - # The default value is full. - #ssl.verification_mode: full - - # List of supported/valid TLS versions. By default all TLS versions from 1.1 - # up to 1.3 are enabled. - #ssl.supported_protocols: [TLSv1.1, TLSv1.2, TLSv1.3] - - # List of root certificates for HTTPS server verifications - #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] - - # Certificate for SSL client authentication - #ssl.certificate: "/etc/pki/client/cert.pem" - - # Client certificate key - #ssl.key: "/etc/pki/client/cert.key" - - # Optional passphrase for decrypting the certificate key. - #ssl.key_passphrase: '' - - # Configure cipher suites to be used for SSL connections - #ssl.cipher_suites: [] - - # Configure curve types for ECDHE-based cipher suites - #ssl.curve_types: [] - - # Configure what types of renegotiation are supported. Valid options are - # never, once, and freely. Default is never. - #ssl.renegotiation: never - - # Configure a pin that can be used to do extra validation of the verified certificate chain, - # this allow you to ensure that a specific certificate is used to validate the chain of trust. - # - # The pin is a base64 encoded string of the SHA-256 fingerprint. - #ssl.ca_sha256: "" - - # A root CA HEX encoded fingerprint. During the SSL handshake if the - # fingerprint matches the root CA certificate, it will be added to - # the provided list of root CAs (`certificate_authorities`), if the - # list is empty or not defined, the matching certificate will be the - # only one in the list. Then the normal SSL validation happens. - #ssl.ca_trusted_fingerprint: "" - - # Enable Kerberos support. Kerberos is automatically enabled if any Kerberos setting is set. - #kerberos.enabled: true - - # Authentication type to use with Kerberos. Available options: keytab, password. - #kerberos.auth_type: password - - # Path to the keytab file. It is used when auth_type is set to keytab. - #kerberos.keytab: /etc/elastic.keytab - - # Path to the Kerberos configuration. - #kerberos.config_path: /etc/krb5.conf - - # Name of the Kerberos user. - #kerberos.username: elastic - - # Password of the Kerberos user. It is used when auth_type is set to password. - #kerberos.password: changeme - - # Kerberos realm. - #kerberos.realm: ELASTIC - - #metrics.period: 10s - #state.period: 1m - -# The `monitoring.cloud.id` setting overwrites the `monitoring.elasticsearch.hosts` -# setting. You can find the value for this setting in the Elastic Cloud web UI. -#monitoring.cloud.id: - -# The `monitoring.cloud.auth` setting overwrites the `monitoring.elasticsearch.username` -# and `monitoring.elasticsearch.password` settings. The format is `:`. -#monitoring.cloud.auth: - -# =============================== HTTP Endpoint ================================ - -# Each beat can expose internal metrics through an HTTP endpoint. For security -# reasons the endpoint is disabled by default. This feature is currently experimental. -# Stats can be accessed through http://localhost:5066/stats. For pretty JSON output -# append ?pretty to the URL. - -# Defines if the HTTP endpoint is enabled. -#http.enabled: false - -# The HTTP endpoint will bind to this hostname, IP address, unix socket, or named pipe. -# When using IP addresses, it is recommended to only use localhost. -#http.host: localhost - -# Port on which the HTTP endpoint will bind. Default is 5066. -#http.port: 5066 - -# Define which user should be owning the named pipe. -#http.named_pipe.user: - -# Define which permissions should be applied to the named pipe, use the Security -# Descriptor Definition Language (SDDL) to define the permission. This option cannot be used with -# `http.user`. -#http.named_pipe.security_descriptor: - -# Defines if the HTTP pprof endpoints are enabled. -# It is recommended that this is only enabled on localhost as these endpoints may leak data. -#http.pprof.enabled: false - -# Controls the fraction of goroutine blocking events that are reported in the -# blocking profile. -#http.pprof.block_profile_rate: 0 - -# Controls the fraction of memory allocations that are recorded and reported in -# the memory profile. -#http.pprof.mem_profile_rate: 524288 - -# Controls the fraction of mutex contention events that are reported in the -# mutex profile. -#http.pprof.mutex_profile_rate: 0 - -# ============================== Process Security ============================== - -# Enable or disable seccomp system call filtering on Linux. Default is enabled. -#seccomp.enabled: true - -# ============================== Instrumentation =============================== - -# Instrumentation support for the functionbeat. -#instrumentation: - # Set to true to enable instrumentation of functionbeat. - #enabled: false - - # Environment in which functionbeat is running on (eg: staging, production, etc.) - #environment: "" - - # APM Server hosts to report instrumentation results to. - #hosts: - # - http://localhost:8200 - - # API Key for the APM Server(s). - # If api_key is set then secret_token will be ignored. - #api_key: - - # Secret token for the APM Server(s). - #secret_token: - - # Enable profiling of the server, recording profile samples as events. - # - # This feature is experimental. - #profiling: - #cpu: - # Set to true to enable CPU profiling. - #enabled: false - #interval: 60s - #duration: 10s - #heap: - # Set to true to enable heap profiling. - #enabled: false - #interval: 60s - -# ================================= Migration ================================== - -# This allows to enable 6.7 migration aliases -#migration.6_to_7.enabled: false - -# =============================== Feature Flags ================================ - -# Enable and configure feature flags. -#features: -# fqdn: -# enabled: true - diff --git a/x-pack/functionbeat/functionbeat.yml b/x-pack/functionbeat/functionbeat.yml deleted file mode 100644 index 9a2627ca44f1..000000000000 --- a/x-pack/functionbeat/functionbeat.yml +++ /dev/null @@ -1,416 +0,0 @@ -###################### Functionbeat Configuration Example ####################### - -# This file is an example configuration file highlighting only the most common -# options. The functionbeat.reference.yml file from the same directory contains all the -# supported options with more comments. You can use it as a reference. -# -# You can find the full configuration reference here: -# https://www.elastic.co/guide/en/beats/functionbeat/index.html -# - -# ================================== Provider ================================== -# Configure functions to run on AWS Lambda, currently, we assume that the credentials -# are present in the environment to correctly create the function when using the CLI. -# -# Configure which S3 endpoint should we use. -functionbeat.provider.aws.endpoint: "s3.amazonaws.com" -# Configure which S3 bucket we should upload the lambda artifact. -functionbeat.provider.aws.deploy_bucket: "functionbeat-deploy" - -functionbeat.provider.aws.functions: - # Define the list of functions available, each function is required to have a unique name. - # Create a function that accepts events coming from cloudwatchlogs. - - name: cloudwatch - enabled: false - type: cloudwatch_logs - - # Description of the method to help identify them when you run multiple functions. - description: "lambda function for cloudwatch logs" - - # Concurrency, is the reserved number of instances for that function. - # Default is 5. - # - # Note: There is a hard limit of 1000 functions of any kind per account. - #concurrency: 5 - - # The maximum memory allocated for this function, the configured size must be a factor of 64. - # There is a hard limit of 3008MiB for each function. Default is 128MiB. - #memory_size: 128MiB - - # Dead letter queue configuration, this must be set to an ARN pointing to an SQS queue. - #dead_letter_config.target_arn: - - # Execution role of the function. - #role: arn:aws:iam::123456789012:role/MyFunction - - # Connect to private resources in an Amazon VPC. - #virtual_private_cloud: - # security_group_ids: [] - # subnet_ids: [] - - # Optional fields that you can specify to add additional information to the - # output. Fields can be scalar values, arrays, dictionaries, or any nested - # combination of these. - #fields: - # env: staging - - # List of cloudwatch log groups registered to that function. - triggers: - - log_group_name: /aws/lambda/functionbeat-cloudwatch_logs - filter_pattern: mylog_ - - # Define custom processors for this function. - #processors: - # - dissect: - # tokenizer: "%{key1} %{key2}" - - # Create a function that accepts events from SQS queues. - - name: sqs - enabled: false - type: sqs - - # Description of the method to help identify them when you run multiple functions. - description: "lambda function for SQS events" - - # Concurrency, is the reserved number of instances for that function. - # Default is 5. - # - # Note: There is a hard limit of 1000 functions of any kind per account. - #concurrency: 5 - - # The maximum memory allocated for this function, the configured size must be a factor of 64. - # There is a hard limit of 3008MiB for each function. Default is 128MiB. - #memory_size: 128MiB - - # Dead letter queue configuration, this must be set to an ARN pointing to an SQS queue. - #dead_letter_config.target_arn: - - # Execution role of the function. - #role: arn:aws:iam::123456789012:role/MyFunction - - # Connect to private resources in an Amazon VPC. - #virtual_private_cloud: - # security_group_ids: [] - # subnet_ids: [] - - # Optional fields that you can specify to add additional information to the - # output. Fields can be scalar values, arrays, dictionaries, or any nested - # combination of these. - #fields: - # env: staging - - # List of SQS queues. - triggers: - # Arn for the SQS queue. - - event_source_arn: arn:aws:sqs:us-east-1:xxxxx:myevents - - # Define custom processors for this function. - #processors: - # - decode_json_fields: - # fields: ["message"] - # process_array: false - # max_depth: 1 - # target: "" - # overwrite_keys: false - # - - # Create a function that accepts events from Kinesis streams. - - name: kinesis - enabled: false - type: kinesis - - # Description of the method to help identify them when you run multiple functions. - description: "lambda function for Kinesis events" - - # Concurrency, is the reserved number of instances for that function. - # Default is 5. - # - # Note: There is a hard limit of 1000 functions of any kind per account. - #concurrency: 5 - - # The maximum memory allocated for this function, the configured size must be a factor of 64. - # There is a hard limit of 3008MiB for each function. Default is 128MiB. - #memory_size: 128MiB - - # Dead letter queue configuration, this must be set to an ARN pointing to an SQS queue. - #dead_letter_config.target_arn: - - # Execution role of the function. - #role: arn:aws:iam::123456789012:role/MyFunction - - # Connect to private resources in an Amazon VPC. - #virtual_private_cloud: - # security_group_ids: [] - # subnet_ids: [] - - # Optional fields that you can specify to add additional information to the - # output. Fields can be scalar values, arrays, dictionaries, or any nested - # combination of these. - #fields: - # env: staging - - # Define custom processors for this function. - #processors: - # This example extracts the raw data from events. - # - decode_base64_field: - # field: - # from: message - # to: message - # - decompress_gzip_field: - # field: - # from: message - # to: message - # - decode_json_fields: - # fields: ["message"] - # process_array: false - # max_depth: 1 - # target: "" - # overwrite_keys: false - - # List of Kinesis streams. - triggers: - # Arn for the Kinesis stream. - - event_source_arn: arn:aws:kinesis:us-east-1:xxxxx:myevents - - # batch_size is the number of events read in a batch. - # Default is 10. - #batch_size: 100 - - # Starting position is where to start reading events from the Kinesis stream. - # Default is trim_horizon. - #starting_position: "trim_horizon" - - # parallelization_factor is the number of batches to process from each shard concurrently. - # Default is 1. - #parallelization_factor: 1 - - # Create a function that accepts Cloudwatch logs from Kinesis streams. - - name: cloudwatch-logs-kinesis - enabled: false - type: cloudwatch_logs_kinesis - - # Description of the method to help identify them when you run multiple functions. - description: "lambda function for Cloudwatch logs in Kinesis events" - - # Set base64_encoded if your data is base64 encoded. - #base64_encoded: false - - # Set compressed if your data is compressed with gzip. - #compressed: true - - # Concurrency, is the reserved number of instances for that function. - # Default is 5. - # - # Note: There is a hard limit of 1000 functions of any kind per account. - #concurrency: 5 - - # The maximum memory allocated for this function, the configured size must be a factor of 64. - # There is a hard limit of 3008MiB for each function. Default is 128MiB. - #memory_size: 128MiB - - # Dead letter queue configuration, this must be set to an ARN pointing to an SQS queue. - #dead_letter_config.target_arn: - - # Execution role of the function. - #role: arn:aws:iam::123456789012:role/MyFunction - - # Connect to private resources in an Amazon VPC. - #virtual_private_cloud: - # security_group_ids: [] - # subnet_ids: [] - - # Optional fields that you can specify to add additional information to the - # output. Fields can be scalar values, arrays, dictionaries, or any nested - # combination of these. - #fields: - # env: staging - - # Define custom processors for this function. - #processors: - # - decode_json_fields: - # fields: ["message"] - # process_array: false - # max_depth: 1 - # target: "" - # overwrite_keys: false - - # List of Kinesis streams. - triggers: - # Arn for the Kinesis stream. - - event_source_arn: arn:aws:kinesis:us-east-1:xxxxx:myevents - - # batch_size is the number of events read in a batch. - # Default is 10. - #batch_size: 100 - - # Starting position is where to start reading events from the Kinesis stream. - # Default is trim_horizon. - #starting_position: "trim_horizon" - - # parallelization_factor is the number of batches to process from each shard concurrently. - # Default is 1. - #parallelization_factor: 1 - - -# ================================== General =================================== - -# The name of the shipper that publishes the network data. It can be used to group -# all the transactions sent by a single shipper in the web interface. -#name: - -# The tags of the shipper are included in their field with each -# transaction published. -#tags: ["service-X", "web-tier"] - -# Optional fields that you can specify to add additional information to the -# output. -#fields: -# env: staging - -# ================================= Dashboards ================================= -# These settings control loading the sample dashboards to the Kibana index. Loading -# the dashboards is disabled by default and can be enabled either by setting the -# options here or by using the `setup` command. -#setup.dashboards.enabled: false - -# The URL from where to download the dashboard archive. By default, this URL -# has a value that is computed based on the Beat name and version. For released -# versions, this URL points to the dashboard archive on the artifacts.elastic.co -# website. -#setup.dashboards.url: - -# =================================== Kibana =================================== - -# Starting with Beats version 6.0.0, the dashboards are loaded via the Kibana API. -# This requires a Kibana endpoint configuration. -setup.kibana: - - # Kibana Host - # Scheme and port can be left out and will be set to the default (http and 5601) - # In case you specify and additional path, the scheme is required: http://localhost:5601/path - # IPv6 addresses should always be defined as: https://[2001:db8::1]:5601 - #host: "localhost:5601" - - # Kibana Space ID - # ID of the Kibana Space into which the dashboards should be loaded. By default, - # the Default Space will be used. - #space.id: - -# =============================== Elastic Cloud ================================ - -# These settings simplify using Functionbeat with the Elastic Cloud (https://cloud.elastic.co/). - -# The cloud.id setting overwrites the `output.elasticsearch.hosts` and -# `setup.kibana.host` options. -# You can find the `cloud.id` in the Elastic Cloud web UI. -#cloud.id: - -# The cloud.auth setting overwrites the `output.elasticsearch.username` and -# `output.elasticsearch.password` settings. The format is `:`. -#cloud.auth: - -# ================================== Outputs =================================== - -# Configure what output to use when sending the data collected by the beat. - -# ---------------------------- Elasticsearch Output ---------------------------- -output.elasticsearch: - # Array of hosts to connect to. - hosts: ["localhost:9200"] - - # Performance preset - one of "balanced", "throughput", "scale", - # "latency", or "custom". - preset: balanced - - # Protocol - either `http` (default) or `https`. - #protocol: "https" - - # Authentication credentials - either API key or username/password. - #api_key: "id:api_key" - #username: "elastic" - #password: "changeme" - -# ------------------------------ Logstash Output ------------------------------- -#output.logstash: - # The Logstash hosts - #hosts: ["localhost:5044"] - - # Optional SSL. By default is off. - # List of root certificates for HTTPS server verifications - #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] - - # Certificate for SSL client authentication - #ssl.certificate: "/etc/pki/client/cert.pem" - - # Client Certificate Key - #ssl.key: "/etc/pki/client/cert.key" - -# ================================= Processors ================================= - -# Configure processors to enhance or manipulate events generated by the beat. - -processors: - - add_host_metadata: ~ - - add_cloud_metadata: ~ - - -# ================================== Logging =================================== - -# Sets log level. The default log level is info. -# Available log levels are: error, warning, info, debug -#logging.level: debug - -# At debug level, you can selectively enable logging only for some components. -# To enable all selectors, use ["*"]. Examples of other selectors are "beat", -# "publisher", "service". -#logging.selectors: ["*"] - -# ============================= X-Pack Monitoring ============================== -# Functionbeat can export internal metrics to a central Elasticsearch monitoring -# cluster. This requires xpack monitoring to be enabled in Elasticsearch. The -# reporting is disabled by default. - -# Set to true to enable the monitoring reporter. -#monitoring.enabled: false - -# Sets the UUID of the Elasticsearch cluster under which monitoring data for this -# Functionbeat instance will appear in the Stack Monitoring UI. If output.elasticsearch -# is enabled, the UUID is derived from the Elasticsearch cluster referenced by output.elasticsearch. -#monitoring.cluster_uuid: - -# Uncomment to send the metrics to Elasticsearch. Most settings from the -# Elasticsearch outputs are accepted here as well. -# Note that the settings should point to your Elasticsearch *monitoring* cluster. -# Any setting that is not set is automatically inherited from the Elasticsearch -# output configuration, so if you have the Elasticsearch output configured such -# that it is pointing to your Elasticsearch monitoring cluster, you can simply -# uncomment the following line. -#monitoring.elasticsearch: - -# ============================== Instrumentation =============================== - -# Instrumentation support for the functionbeat. -#instrumentation: - # Set to true to enable instrumentation of functionbeat. - #enabled: false - - # Environment in which functionbeat is running on (eg: staging, production, etc.) - #environment: "" - - # APM Server hosts to report instrumentation results to. - #hosts: - # - http://localhost:8200 - - # API Key for the APM Server(s). - # If api_key is set then secret_token will be ignored. - #api_key: - - # Secret token for the APM Server(s). - #secret_token: - - -# ================================= Migration ================================== - -# This allows to enable 6.7 migration aliases -#migration.6_to_7.enabled: true - diff --git a/x-pack/functionbeat/include/feature.go b/x-pack/functionbeat/include/feature.go deleted file mode 100644 index b37796cfd77e..000000000000 --- a/x-pack/functionbeat/include/feature.go +++ /dev/null @@ -1,16 +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 include - -import ( - "github.com/elastic/beats/v7/libbeat/feature" - "github.com/elastic/beats/v7/x-pack/functionbeat/manager/aws" - "github.com/elastic/beats/v7/x-pack/functionbeat/provider/local/local" -) - -func init() { - feature.MustRegister(aws.Features...) - feature.MustRegister(local.Features...) -} diff --git a/x-pack/functionbeat/include/fields.go b/x-pack/functionbeat/include/fields.go deleted file mode 100644 index b58f331ad473..000000000000 --- a/x-pack/functionbeat/include/fields.go +++ /dev/null @@ -1,23 +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. - -// Code generated by beats/dev-tools/cmd/asset/asset.go - DO NOT EDIT. - -package include - -import ( - "github.com/elastic/beats/v7/libbeat/asset" -) - -func init() { - if err := asset.SetFields("functionbeat", "fields.yml", asset.BeatFieldsPri, AssetFieldsYml); err != nil { - panic(err) - } -} - -// AssetFieldsYml returns asset data. -// This is the base64 encoded zlib format compressed contents of fields.yml. -func AssetFieldsYml() string { - return "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" -} diff --git a/x-pack/functionbeat/magefile.go b/x-pack/functionbeat/magefile.go deleted file mode 100644 index 5df39f8c3c88..000000000000 --- a/x-pack/functionbeat/magefile.go +++ /dev/null @@ -1,234 +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. - -//go:build mage - -package main - -import ( - "fmt" - "os" - "path/filepath" - "runtime" - "time" - - "github.com/magefile/mage/mg" - - devtools "github.com/elastic/beats/v7/dev-tools/mage" - "github.com/elastic/beats/v7/dev-tools/mage/target/build" - functionbeat "github.com/elastic/beats/v7/x-pack/functionbeat/scripts/mage" - - // mage:import - _ "github.com/elastic/beats/v7/dev-tools/mage/target/common" - // mage:import - _ "github.com/elastic/beats/v7/dev-tools/mage/target/pkg" - // mage:import - _ "github.com/elastic/beats/v7/dev-tools/mage/target/unittest" - // mage:import - _ "github.com/elastic/beats/v7/dev-tools/mage/target/integtest/notests" - // mage:import - _ "github.com/elastic/beats/v7/dev-tools/mage/target/test" -) - -func init() { - devtools.BeatDescription = "Functionbeat is a beat implementation for a serverless architecture." - devtools.BeatLicense = "Elastic License" -} - -// Build builds the Beat binary and functions by provider. -func Build() error { - params := devtools.DefaultBuildArgs() - - // Building functionbeat manager - err := devtools.Build(params) - if err != nil { - return err - } - - // Getting selected cloud providers - selectedProviders, err := functionbeat.SelectedProviders() - if err != nil { - return err - } - - // Building functions to deploy - for _, provider := range selectedProviders { - if !provider.Buildable { - continue - } - - inputFiles := filepath.Join("provider", provider.Name, "main.go") - params.InputFiles = []string{inputFiles} - params.Name = devtools.BeatName + "-" + provider.Name - params.OutputDir = filepath.Join("provider", provider.Name) - params.CGO = false - params.Env = make(map[string]string) - if provider.GOOS != "" { - params.Env["GOOS"] = provider.GOOS - } - if provider.GOARCH != "" { - params.Env["GOARCH"] = provider.GOARCH - } - err := devtools.Build(params) - if err != nil { - return err - } - } - return nil -} - -// GolangCrossBuild build the Beat binary inside of the golang-builder. -// Do not use directly, use crossBuild instead. -func GolangCrossBuild() error { - return devtools.GolangCrossBuild(devtools.DefaultGolangCrossBuildArgs()) -} - -// BuildGoDaemon builds the go-daemon binary (use crossBuildGoDaemon). -func BuildGoDaemon() error { - return devtools.BuildGoDaemon() -} - -// CrossBuild cross-builds the beat for all target platforms. -func CrossBuild() error { - - // Building functionbeat manager - err := devtools.CrossBuild() - if err != nil { - return err - } - - // Getting selected cloud providers - selectedProviders, err := functionbeat.SelectedProviders() - if err != nil { - return err - } - - // Building functions to deploy - for _, provider := range selectedProviders { - if !provider.Buildable { - continue - } - - if runtime.GOARCH != "amd64" { - fmt.Println("Crossbuilding functions only works on amd64 architecture.") - return nil - } - - err := devtools.CrossBuild(devtools.AddPlatforms("linux/amd64"), devtools.InDir("x-pack", "functionbeat", "provider", provider.Name)) - if err != nil { - return err - } - } - return nil -} - -// CrossBuildGoDaemon cross-builds the go-daemon binary using Docker. -func CrossBuildGoDaemon() error { - return devtools.CrossBuildGoDaemon() -} - -// Update is an alias for update:all. This is a workaround for -// https://github.com/magefile/mage/issues/217. -func Update() { mg.Deps(functionbeat.Update.All) } - -// Fields is an alias for update:fields. This is a workaround for -// https://github.com/magefile/mage/issues/217. -func Fields() { mg.Deps(functionbeat.Update.Fields) } - -// Config is an alias for update:config. This is a workaround for -// https://github.com/magefile/mage/issues/217. -func Config() { mg.Deps(functionbeat.Update.Config) } - -// AssembleDarwinUniversal merges the darwin/amd64 and darwin/arm64 into a single -// universal binary using `lipo`. It assumes the darwin/amd64 and darwin/arm64 -// were built and only performs the merge. -func AssembleDarwinUniversal() error { - return build.AssembleDarwinUniversal() -} - -// Package packages the Beat for distribution. -// Use SNAPSHOT=true to build snapshots. -// Use PLATFORMS to control the target platforms. -func Package() { - start := time.Now() - defer func() { fmt.Println("package ran for", time.Since(start)) }() - - devtools.MustUsePackaging("functionbeat", "x-pack/functionbeat/dev-tools/packaging/packages.yml") - - mg.Deps(Update) - mg.Deps(CrossBuild, CrossBuildGoDaemon) - mg.SerialDeps(devtools.Package, TestPackages) -} - -// Package packages the Beat for IronBank distribution. -// -// Use SNAPSHOT=true to build snapshots. -func Ironbank() error { - fmt.Println(">> Ironbank: this module is not subscribed to the IronBank releases.") - return nil -} - -// TestPackages tests the generated packages (i.e. file modes, owners, groups). -func TestPackages() error { - return devtools.TestPackages() -} - -// BuildPkgForFunctions creates a folder named pkg and adds functions to it. -// This makes testing the manager more comfortable. -func BuildPkgForFunctions() error { - mg.Deps(Update, Build) - - err := os.RemoveAll("pkg") - - filesToCopy := map[string]string{ - filepath.Join("provider", "aws", "functionbeat-aws"): filepath.Join("pkg", "functionbeat-aws"), - } - for src, dest := range filesToCopy { - c := &devtools.CopyTask{ - Source: src, - Dest: dest, - } - err = c.Execute() - if err != nil { - return err - } - } - return nil -} - -// BuildSystemTestBinary build a binary for testing that is instrumented for -// testing and measuring code coverage. The binary is only instrumented for -// coverage when TEST_COVERAGE=true (default is false). -func BuildSystemTestBinary() error { - err := devtools.BuildSystemTestBinary() - if err != nil { - return err - } - - params := devtools.DefaultTestBinaryArgs() - - // Getting selected cloud providers - selectedProviders, err := functionbeat.SelectedProviders() - if err != nil { - return err - } - - for _, provider := range selectedProviders { - if !provider.Buildable { - continue - } - - params.Name = filepath.Join("provider", provider.Name, devtools.BeatName+"-"+provider.Name) - inputFiles := make([]string, 0) - for _, inputFileName := range []string{"main.go", "main_test.go"} { - inputFiles = append(inputFiles, filepath.Join("provider", provider.Name, inputFileName)) - } - params.InputFiles = inputFiles - err := devtools.BuildSystemTestGoBinary(params) - if err != nil { - return err - } - } - return nil -} diff --git a/x-pack/functionbeat/main.go b/x-pack/functionbeat/main.go deleted file mode 100644 index 47c4c10ad4f6..000000000000 --- a/x-pack/functionbeat/main.go +++ /dev/null @@ -1,19 +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 main - -import ( - "os" - _ "time/tzdata" // for timezone handling - - _ "github.com/elastic/beats/v7/x-pack/functionbeat/include" // imports features - "github.com/elastic/beats/v7/x-pack/functionbeat/manager/cmd" -) - -func main() { - if err := cmd.RootCmd.Execute(); err != nil { - os.Exit(1) - } -} diff --git a/x-pack/functionbeat/main_test.go b/x-pack/functionbeat/main_test.go deleted file mode 100644 index 1c21f88e2891..000000000000 --- a/x-pack/functionbeat/main_test.go +++ /dev/null @@ -1,40 +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 main - -// This file is mandatory as otherwise the functionbeat.test binary is not generated correctly. - -import ( - "flag" - "testing" - - "github.com/elastic/beats/v7/libbeat/cfgfile" - "github.com/elastic/beats/v7/libbeat/tests/system/template" - "github.com/elastic/beats/v7/x-pack/functionbeat/manager/cmd" -) - -var systemTest *bool - -func init() { - testing.Init() - systemTest = flag.Bool("systemTest", false, "Set to true when running system tests") - - cmd.RootCmd.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("systemTest")) - cfgfile.AddAllowedBackwardsCompatibleFlag("systemTest") - cmd.RootCmd.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("test.coverprofile")) - cfgfile.AddAllowedBackwardsCompatibleFlag("test.coverprofile") -} - -// Test started when the test binary is started. Only calls main. -func TestSystem(t *testing.T) { - cfgfile.ConvertFlagsForBackwardsCompatibility() - if *systemTest { - main() - } -} - -func TestTemplate(t *testing.T) { - template.TestTemplate(t, cmd.Name, true) -} diff --git a/x-pack/functionbeat/make.bat b/x-pack/functionbeat/make.bat deleted file mode 100644 index 9fe6b2b801e2..000000000000 --- a/x-pack/functionbeat/make.bat +++ /dev/null @@ -1,11 +0,0 @@ -@echo off - -REM Windows wrapper for Mage (https://magefile.org/) that installs it -REM to %GOPATH%\bin from the Beats vendor directory. -REM -REM After running this once you may invoke mage.exe directly. - -WHERE mage -IF %ERRORLEVEL% NEQ 0 go install github.com/ph/functionbeat/vendor/github.com/magefile/mage - -mage %* diff --git a/x-pack/functionbeat/manager/aws/aws.go b/x-pack/functionbeat/manager/aws/aws.go deleted file mode 100644 index a8f2f5a5ad13..000000000000 --- a/x-pack/functionbeat/manager/aws/aws.go +++ /dev/null @@ -1,33 +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 aws - -import ( - "github.com/elastic/beats/v7/libbeat/feature" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/provider" - "github.com/elastic/beats/v7/x-pack/functionbeat/provider/aws/aws" -) - -// Features exposes the trigger supported by the AWS provider. -var Features = provider.Builder( - "aws", - provider.NewDefaultProvider("aws", NewCLI, NewTemplateBuilder), - feature.MakeDetails("AWS Lambda", "listen to events on AWS lambda", feature.Stable), -).AddFunction("cloudwatch_logs", - aws.NewCloudwatchLogs, - aws.CloudwatchLogsDetails(), -).AddFunction("api_gateway_proxy", - aws.NewAPIGatewayProxy, - aws.APIGatewayProxyDetails(), -).AddFunction("kinesis", - aws.NewKinesis, - aws.KinesisDetails(), -).AddFunction("sqs", - aws.NewSQS, - aws.SQSDetails(), -).AddFunction("cloudwatch_logs_kinesis", - aws.NewCloudwatchKinesis, - aws.CloudwatchKinesisDetails(), -).Features() diff --git a/x-pack/functionbeat/manager/aws/cli_manager.go b/x-pack/functionbeat/manager/aws/cli_manager.go deleted file mode 100644 index 3bdb5ffa1ad4..000000000000 --- a/x-pack/functionbeat/manager/aws/cli_manager.go +++ /dev/null @@ -1,240 +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 aws - -import ( - "context" - "fmt" - "os" - "strings" - - "github.com/aws/aws-sdk-go-v2/aws" - cf "github.com/aws/aws-sdk-go-v2/service/cloudformation" - "github.com/awslabs/goformation/v7/cloudformation" - "github.com/awslabs/goformation/v7/cloudformation/iam" - "github.com/awslabs/goformation/v7/cloudformation/lambda" - - "github.com/elastic/beats/v7/x-pack/functionbeat/function/provider" - "github.com/elastic/beats/v7/x-pack/functionbeat/manager/core" - "github.com/elastic/beats/v7/x-pack/functionbeat/manager/executor" - fnaws "github.com/elastic/beats/v7/x-pack/functionbeat/provider/aws/aws" - awscommon "github.com/elastic/beats/v7/x-pack/libbeat/common/aws" - conf "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/logp" -) - -const ( - // AWS lambda currently support go 1.x as a runtime. - runtime = "go1.x" - handlerName = "functionbeat-aws" -) - -// AWSLambdaFunction add 'dependsOn' as a serializable parameters, goformation doesn't currently -// serialize this field. -type AWSLambdaFunction struct { - *lambda.Function - DependsOn []string -} - -type installer interface { - Policies() []iam.Role_Policy - Template() *cloudformation.Template - LambdaConfig() *fnaws.LambdaConfig -} - -// CLIManager interacts with the AWS Lambda API to deploy, update or remove a function. -// It will take care of creating the main lambda function and ask for each function type for the -// operation that need to be executed to connect the lambda to the triggers. -type CLIManager struct { - templateBuilder *defaultTemplateBuilder - awsCfg aws.Config - log *logp.Logger - config *fnaws.Config -} - -// stackName cloudformation stack are unique per function. -func (c *CLIManager) stackName(name string) string { - return "fnb-" + name + "-stack" -} - -func (c *CLIManager) deployTemplate(update bool, name string) error { - templateData, err := c.templateBuilder.execute(name) - if err != nil { - return err - } - - c.log.Debugf("Using cloudformation template:\n%s", templateData.json) - - _, err = c.awsCfg.Credentials.Retrieve(context.Background()) - if err != nil { - return fmt.Errorf("failed to retrieve aws credentials, please check AWS credential in config: %w", err) - } - - svcCF := cf.NewFromConfig(c.awsCfg) - - executer := executor.NewExecutor(c.log) - _ = executer.Add(newOpEnsureBucket(c.log, c.awsCfg, c.bucket())) - _ = executer.Add(newOpUploadToBucket( - c.log, - c.awsCfg, - c.bucket(), - templateData.codeKey, - templateData.zip.content, - )) - _ = executer.Add(newOpUploadToBucket( - c.log, - c.awsCfg, - c.bucket(), - templateData.key, - templateData.json, - )) - if update { - _ = executer.Add(newOpUpdateCloudFormation( - c.log, - svcCF, - templateData.url, - c.stackName(name), - )) - } else { - _ = executer.Add(newOpCreateCloudFormation( - c.log, - svcCF, - templateData.url, - c.stackName(name), - )) - } - - _ = executer.Add(newOpWaitCloudFormation(c.log, cf.NewFromConfig(c.awsCfg))) - _ = executer.Add(newOpDeleteFileBucket(c.log, c.awsCfg, c.bucket(), templateData.codeKey)) - - ctx := newStackContext() - if err := executer.Execute(ctx); err != nil { - if rollbackErr := executer.Rollback(ctx); rollbackErr != nil { - return fmt.Errorf("could not rollback, error: %s, %w", rollbackErr.Error(), err) - } - return err - } - return nil -} - -// Deploy uploads the function to AWS. -func (c *CLIManager) Deploy(name string) error { - c.log.Debugf("Deploying function: %s", name) - defer c.log.Debugf("Deploy finish for function '%s'", name) - - if err := c.deployTemplate(false, name); err != nil { - return err - } - c.log.Debugf("Successfully created function '%s'", name) - return nil -} - -// Update updates lambda using cloudformation. -func (c *CLIManager) Update(name string) error { - c.log.Debugf("Starting updating function '%s'", name) - defer c.log.Debugf("Update complete for function '%s'", name) - - if err := c.deployTemplate(true, name); err != nil { - return err - } - - c.log.Debugf("Successfully updated function: '%s'", name) - return nil -} - -// Remove removes a stack and unregister any resources created. -func (c *CLIManager) Remove(name string) error { - c.log.Debugf("Removing function: %s", name) - defer c.log.Debugf("Removal of function '%s' complete", name) - - _, err := c.awsCfg.Credentials.Retrieve(context.Background()) - if err != nil { - return fmt.Errorf("failed to retrieve aws credentials, please check AWS credential in config: %w", err) - } - - svc := cf.NewFromConfig(c.awsCfg) - executer := executor.NewExecutor(c.log) - _ = executer.Add(newOpDeleteCloudFormation(c.log, svc, c.stackName(name))) - _ = executer.Add(newWaitDeleteCloudFormation(c.log, c.awsCfg)) - - ctx := newStackContext() - if err := executer.Execute(ctx); err != nil { - if rollbackErr := executer.Rollback(ctx); rollbackErr != nil { - return fmt.Errorf("could not rollback, error: %s, %w", rollbackErr.Error(), err) - } - return err - } - return nil -} - -// Export prints the exported function data. -func (c *CLIManager) Export(name string) error { - tmpl, err := c.templateBuilder.RawTemplate(name) - if err != nil { - return err - } - - fmt.Println(tmpl) //nolint:forbidigo // standalone tool - - return nil -} - -// Package packages functions for AWS. -func (c *CLIManager) Package(outputPattern string) error { - resource := zipResources() - content, err := core.MakeZip(packageUncompressedLimit, packageCompressedLimit, resource) - if err != nil { - return err - } - - output := strings.ReplaceAll(outputPattern, "{{.Provider}}", "aws") - err = os.WriteFile(output, content, 0644) - if err != nil { - return err - } - - _, _ = fmt.Fprintf(os.Stderr, "Generated package for provider aws at: %s\n", output) - return nil -} - -func (c *CLIManager) bucket() string { - return string(c.config.DeployBucket) -} - -// NewCLI returns the interface to manage function on Amazon lambda. -func NewCLI( - log *logp.Logger, - cfg *conf.C, - provider provider.Provider, -) (provider.CLIManager, error) { - config := fnaws.DefaultConfig() - if err := cfg.Unpack(config); err != nil { - return nil, err - } - awsCfg, err := awscommon.InitializeAWSConfig(config.Credentials) - if err != nil { - return nil, fmt.Errorf("failed to get aws credentials, please check AWS credential in config: %w", err) - } - if config.Region != "" { - awsCfg.Region = config.Region - } - - builder, err := provider.TemplateBuilder() - if err != nil { - return nil, err - } - - templateBuilder, ok := builder.(*defaultTemplateBuilder) - if !ok { - return nil, fmt.Errorf("not defaultTemplateBuilder") - } - - return &CLIManager{ - config: config, - awsCfg: awsCfg, - log: logp.NewLogger("aws"), - templateBuilder: templateBuilder, - }, nil -} diff --git a/x-pack/functionbeat/manager/aws/cli_manager_test.go b/x-pack/functionbeat/manager/aws/cli_manager_test.go deleted file mode 100644 index 336f979587f8..000000000000 --- a/x-pack/functionbeat/manager/aws/cli_manager_test.go +++ /dev/null @@ -1,38 +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 aws - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/elastic/beats/v7/libbeat/common" -) - -func TestChecksum(t *testing.T) { - t.Run("same bytes content return the same key", func(t *testing.T) { - content, err := common.RandomBytes(100) - if !assert.NoError(t, err) { - return - } - - assert.Equal(t, checksum(content), checksum(content)) - }) - - t.Run("different bytes return a different key", func(t *testing.T) { - content, err := common.RandomBytes(100) - if !assert.NoError(t, err) { - return - } - - other, err := common.RandomBytes(100) - if !assert.NoError(t, err) { - return - } - - assert.NotEqual(t, checksum(content), checksum(other)) - }) -} diff --git a/x-pack/functionbeat/manager/aws/cloudformation_interface.go b/x-pack/functionbeat/manager/aws/cloudformation_interface.go deleted file mode 100644 index 46d03734c958..000000000000 --- a/x-pack/functionbeat/manager/aws/cloudformation_interface.go +++ /dev/null @@ -1,24 +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 aws - -import ( - "context" - - "github.com/aws/aws-sdk-go-v2/service/cloudformation" -) - -type deleteStackClient interface { - cloudformation.DescribeStacksAPIClient - DeleteStack(ctx context.Context, params *cloudformation.DeleteStackInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DeleteStackOutput, error) -} - -type createStackClient interface { - CreateStack(ctx context.Context, params *cloudformation.CreateStackInput, optFns ...func(*cloudformation.Options)) (*cloudformation.CreateStackOutput, error) -} - -type updateStackClient interface { - UpdateStack(ctx context.Context, params *cloudformation.UpdateStackInput, optFns ...func(*cloudformation.Options)) (*cloudformation.UpdateStackOutput, error) -} diff --git a/x-pack/functionbeat/manager/aws/event_stack_poller.go b/x-pack/functionbeat/manager/aws/event_stack_poller.go deleted file mode 100644 index 6b3b58ae79fb..000000000000 --- a/x-pack/functionbeat/manager/aws/event_stack_poller.go +++ /dev/null @@ -1,157 +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 aws - -import ( - "context" - "sync" - "time" - - "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" - - "github.com/aws/aws-sdk-go-v2/service/cloudformation" - - "github.com/elastic/elastic-agent-libs/logp" -) - -// Resource type to look for. -const eventAWSCloudFormationStack = "AWS::CloudFormation::Stack" - -type eventStackHandler interface { - sync(event types.StackEvent) bool - handle(event types.StackEvent) -} - -// eventStackPoller takes a stack id and will report any events coming from it. -// The event stream for a stack will return all the events for a specific existence of a stack, -// it's important to be able to skip some events and only report the meaningful events. -type eventStackPoller struct { - log *logp.Logger - svc cloudformation.DescribeStackEventsAPIClient - stackID *string - periodicCheck time.Duration - handler eventStackHandler - done chan struct{} - wg sync.WaitGroup -} - -func newEventStackPoller( - log *logp.Logger, - svc cloudformation.DescribeStackEventsAPIClient, - stackID *string, - periodicCheck time.Duration, - handler eventStackHandler, -) *eventStackPoller { - return &eventStackPoller{ - log: log, - svc: svc, - stackID: stackID, - periodicCheck: periodicCheck, - handler: handler, - done: make(chan struct{}), - } -} - -func (e *eventStackPoller) Start() { - e.wg.Add(1) - go func() { - defer e.wg.Done() - e.poll() - }() -} - -func (e *eventStackPoller) Stop() { - close(e.done) - e.wg.Wait() -} - -func (e *eventStackPoller) poll() { - var nextToken *string - var foundFirstEvent bool - var alreadyLoggedEvents = make(map[string]struct{}) - for { - input := &cloudformation.DescribeStackEventsInput{ - NextToken: nextToken, - StackName: e.stackID, - } - - // Currently no way to skip items based on time. - // doc: https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_DescribeStackEvents.html - resp, err := e.svc.DescribeStackEvents(context.TODO(), input) - if err != nil { - // This is not a fatal error because the check is made out of bound from the current status logic. - // I wanted to keep them separate so it is easier to deal with states and reporting. - e.log.Errorf("Could not retrieve the events for stack, error: %+v", err) - } - - // Events are in reverse order. we need older -> new, but we do not rely on the time but just - // the position in the slice. - for i, j := 0, len(resp.StackEvents)-1; i < j; i, j = i+1, j-1 { - resp.StackEvents[i], resp.StackEvents[j] = resp.StackEvents[j], resp.StackEvents[i] - } - - for _, event := range resp.StackEvents { - // Since we receive all the events from the beginning of the stack we have - // to first position ourself to an event of interest. - if !foundFirstEvent { - if !e.handler.sync(event) { - // keep current event and position to the first meaningful event. - foundFirstEvent = true - } else { - //discard current event. - continue - } - } - - // When the stack is in progress we will receive an empty token, so we have to make another - // call with the current token this mean we probably have already see the events so we have to - // ignore them. I am using ids here instance of time because I think 2 events might have - // the same time. I am assuming this map should stay relatively small. - if _, ok := alreadyLoggedEvents[*event.EventId]; ok { - continue - } - - e.handler.handle(event) - alreadyLoggedEvents[*event.EventId] = struct{}{} - } - - select { - case <-e.done: - // if nextToken is nil it mean we are at the end of the current pages. - // if not it mean we still have log to get and we need to report them before quitting. - if nextToken == nil { - return - } - case <-time.After(e.periodicCheck): - } - } -} - -type reportStackEvent struct { - skipBefore time.Time - callback func(event types.StackEvent) -} - -func (r *reportStackEvent) sync(event types.StackEvent) bool { - // Ignore anything before the Start pointer and everything which is not AWS::CloudFormation::Stack - if r.skipBefore.Before(*event.Timestamp) && *event.ResourceType == eventAWSCloudFormationStack { - // We are only interested in events thats `START` a request. - switch event.ResourceStatus { - case types.ResourceStatusCreateInProgress: - return false - case types.ResourceStatusDeleteInProgress: - return false - case types.ResourceStatusUpdateInProgress: - return false - default: - return true - } - } - return true -} - -func (r *reportStackEvent) handle(event types.StackEvent) { - r.callback(event) -} diff --git a/x-pack/functionbeat/manager/aws/event_stack_poller_test.go b/x-pack/functionbeat/manager/aws/event_stack_poller_test.go deleted file mode 100644 index 3679f07fb547..000000000000 --- a/x-pack/functionbeat/manager/aws/event_stack_poller_test.go +++ /dev/null @@ -1,341 +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 aws - -import ( - "context" - "strconv" - "sync/atomic" - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" - - "github.com/aws/aws-sdk-go-v2/service/cloudformation" - "github.com/stretchr/testify/assert" - - "github.com/elastic/elastic-agent-libs/logp" -) - -type mockEventHandler struct { - skipEvents int32 - skipCount atomic.Int32 - events chan types.StackEvent -} - -func (m *mockEventHandler) sync(event types.StackEvent) bool { - if m.skipCount.Load() >= m.skipEvents { - return false - } - m.skipCount.Add(1) - return true -} - -func (m *mockEventHandler) handle(event types.StackEvent) { - m.events <- event -} - -type mockCloudFormationClient struct { - Responses []*cloudformation.DescribeStackEventsOutput - Index int -} - -func (m *mockCloudFormationClient) DescribeStackEvents(context.Context, *cloudformation.DescribeStackEventsInput, ...func(*cloudformation.Options)) (*cloudformation.DescribeStackEventsOutput, error) { - defer func() { - // This minic the fact that the last token will be nil. - if m.Index < len(m.Responses)-1 { - m.Index++ - } - }() - - return m.Responses[m.Index], nil -} - -func TestEventStackPoller(t *testing.T) { - t.Run("emits all events", testEmitAllEvents) - t.Run("skip events", testSkipEvents) - t.Run("skip duplicates", testSkipDuplicates) - t.Run("return time ordered events", testReturnTimeOrdered) -} - -func testEmitAllEvents(t *testing.T) { - response1 := &cloudformation.DescribeStackEventsOutput{ - NextToken: ptr("12345"), - StackEvents: []types.StackEvent{ - types.StackEvent{EventId: ptr("1"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("2"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("3"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("4"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("5"), Timestamp: ptrTime(time.Now())}, - }, - } - response2 := &cloudformation.DescribeStackEventsOutput{ - StackEvents: []types.StackEvent{ - types.StackEvent{EventId: ptr("6"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("7"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("8"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("9"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("10"), Timestamp: ptrTime(time.Now())}, - }, - } - - client := &mockCloudFormationClient{Responses: []*cloudformation.DescribeStackEventsOutput{ - response1, - response2, - }} - - handler := &mockEventHandler{events: make(chan types.StackEvent)} - poller := newEventStackPoller( - logp.NewLogger(""), - client, - ptr("1235"), - 1, - handler, - ) - poller.Start() - defer poller.Stop() - - var c int - for range handler.events { - c++ - if c == 10 { - return - } - } -} - -func testSkipEvents(t *testing.T) { - response1 := &cloudformation.DescribeStackEventsOutput{ - NextToken: ptr("12345"), - StackEvents: []types.StackEvent{ - types.StackEvent{EventId: ptr("1"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("2"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("3"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("4"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("5"), Timestamp: ptrTime(time.Now())}, - }, - } - response2 := &cloudformation.DescribeStackEventsOutput{ - StackEvents: []types.StackEvent{ - types.StackEvent{EventId: ptr("6"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("7"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("8"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("9"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("10"), Timestamp: ptrTime(time.Now())}, - }, - } - - client := &mockCloudFormationClient{Responses: []*cloudformation.DescribeStackEventsOutput{ - response1, - response2, - }} - - handler := &mockEventHandler{skipEvents: 3, events: make(chan types.StackEvent)} - poller := newEventStackPoller( - logp.NewLogger(""), - client, - ptr("1235"), - 0, - handler, - ) - poller.Start() - defer poller.Stop() - - var c int - for range handler.events { - c++ - if c == 7 { - return - } - } -} - -func testSkipDuplicates(t *testing.T) { - response1 := &cloudformation.DescribeStackEventsOutput{ - NextToken: ptr("12345"), - StackEvents: []types.StackEvent{ - types.StackEvent{EventId: ptr("1"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("2"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("3"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("4"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("4"), Timestamp: ptrTime(time.Now())}, - }, - } - response2 := &cloudformation.DescribeStackEventsOutput{ - StackEvents: []types.StackEvent{ - types.StackEvent{EventId: ptr("1"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("2"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("2"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("4"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("5"), Timestamp: ptrTime(time.Now())}, - }, - } - - client := &mockCloudFormationClient{Responses: []*cloudformation.DescribeStackEventsOutput{ - response1, - response2, - }} - - handler := &mockEventHandler{skipEvents: 3, events: make(chan types.StackEvent)} - poller := newEventStackPoller( - logp.NewLogger(""), - client, - ptr("1235"), - 0, - handler, - ) - poller.Start() - defer poller.Stop() - - var c int - for range handler.events { - c++ - if c == 4 { - return - } - } -} - -func testReturnTimeOrdered(t *testing.T) { - response1 := &cloudformation.DescribeStackEventsOutput{ - NextToken: ptr("12345"), - StackEvents: []types.StackEvent{ - types.StackEvent{EventId: ptr("5"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("4"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("3"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("2"), Timestamp: ptrTime(time.Now())}, - types.StackEvent{EventId: ptr("1"), Timestamp: ptrTime(time.Now())}, - }, - } - - client := &mockCloudFormationClient{Responses: []*cloudformation.DescribeStackEventsOutput{ - response1, - }} - - handler := &mockEventHandler{events: make(chan types.StackEvent)} - poller := newEventStackPoller( - logp.NewLogger(""), - client, - ptr("1235"), - 0, - handler, - ) - poller.Start() - defer poller.Stop() - - c := 1 - for event := range handler.events { - if c == 5 { - return - } - - assert.Equal(t, strconv.Itoa(c), *event.EventId) - c++ - } -} - -func TestReportStackEvent(t *testing.T) { - t.Run("test skip event", testReportSkipEvents) - t.Run("test that handle forward the event to callback", testReportCallback) -} - -func testReportSkipEvents(t *testing.T) { - now := time.Now() - - tests := []struct { - name string - event types.StackEvent - sync bool - }{ - { - name: "is stack event but happened before", - event: types.StackEvent{ - ResourceType: ptr("AWS::CloudFormation::Stack"), - EventId: ptr("1"), - Timestamp: ptrTime(now.Add(-10 * time.Second)), - }, - sync: true, - }, - { - name: "is not a stack event", - event: types.StackEvent{ - ResourceType: ptr("AWS::S3::Bucket"), - EventId: ptr("2"), - Timestamp: ptrTime(now.Add(10 * time.Second)), - }, - sync: true, - }, - { - name: "is a stack event and happens after but with wrong status", - event: types.StackEvent{ - ResourceType: ptr("AWS::CloudFormation::Stack"), - ResourceStatus: types.ResourceStatusDeleteFailed, - EventId: ptr("2"), - Timestamp: ptrTime(now.Add(11 * time.Second)), - }, - sync: true, - }, - { - name: "is a stack event and happens after with a CREATE_IN_PROGRESS status", - event: types.StackEvent{ - ResourceType: ptr("AWS::CloudFormation::Stack"), - ResourceStatus: types.ResourceStatusCreateInProgress, - EventId: ptr("2"), - Timestamp: ptrTime(now.Add(11 * time.Second)), - }, - sync: false, - }, - { - name: "is a stack event and happens after with an UPDATE_IN_PROGRESS status", - event: types.StackEvent{ - ResourceType: ptr("AWS::CloudFormation::Stack"), - ResourceStatus: types.ResourceStatusUpdateInProgress, - EventId: ptr("2"), - Timestamp: ptrTime(now.Add(11 * time.Second)), - }, - sync: false, - }, - { - name: "is a stack event and happens after with an DELETE_IN_PROGRESS status", - event: types.StackEvent{ - ResourceType: ptr("AWS::CloudFormation::Stack"), - ResourceStatus: types.ResourceStatusDeleteInProgress, - EventId: ptr("2"), - Timestamp: ptrTime(now.Add(11 * time.Second)), - }, - sync: false, - }, - } - - reporter := reportStackEvent{ - skipBefore: now, - callback: func(event types.StackEvent) {}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - assert.Equal(t, test.sync, reporter.sync(test.event)) - }) - } -} - -func testReportCallback(t *testing.T) { - var received bool - reporter := reportStackEvent{ - skipBefore: time.Now(), - callback: func(event types.StackEvent) { received = true }, - } - - reporter.handle(types.StackEvent{}) - assert.True(t, received) -} - -func ptr(v string) *string { - return &v -} - -func ptrTime(t time.Time) *time.Time { - return &t -} diff --git a/x-pack/functionbeat/manager/aws/op_cloudformation.go b/x-pack/functionbeat/manager/aws/op_cloudformation.go deleted file mode 100644 index 028c78cd4a4e..000000000000 --- a/x-pack/functionbeat/manager/aws/op_cloudformation.go +++ /dev/null @@ -1,110 +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 aws - -import ( - "context" - "fmt" - "strings" - "time" - - "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" - - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/cloudformation" - "github.com/gofrs/uuid/v5" - - "github.com/elastic/beats/v7/x-pack/functionbeat/manager/executor" - "github.com/elastic/elastic-agent-libs/logp" -) - -type opCreateCloudFormation struct { - log *logp.Logger - svc createStackClient - templateURL string - stackName string -} - -func newOpCreateCloudFormation( - log *logp.Logger, - svc createStackClient, - templateURL, stackName string, -) *opCreateCloudFormation { - return &opCreateCloudFormation{ - log: log, - svc: svc, - templateURL: templateURL, - stackName: stackName, - } -} - -func (o *opCreateCloudFormation) Execute(ctx executor.Context) error { - c, ok := ctx.(*stackContext) - if !ok { - return errWrongContext - } - - o.log.Debug("Creating CloudFormation create stack request") - uuid, err := uuid.NewV4() - if err != nil { - return err - } - input := &cloudformation.CreateStackInput{ - ClientRequestToken: aws.String(uuid.String()), - StackName: aws.String(o.stackName), - TemplateURL: aws.String(o.templateURL), - Capabilities: []types.Capability{ - types.CapabilityCapabilityNamedIam, - }, - } - - resp, err := o.svc.CreateStack(context.TODO(), input) - if err != nil { - o.log.Debugf("Could not create the CloudFormation stack request, resp: %v", resp) - return err - } - - c.ID = resp.StackId - - return nil -} - -func makeEventStackPoller( - log *logp.Logger, - svc *cloudformation.Client, - periodicCheck time.Duration, - ctx *stackContext, -) *eventStackPoller { - return newEventStackPoller( - log, - svc, - ctx.ID, - periodicCheck, - &reportStackEvent{skipBefore: ctx.StartedAt, callback: func(event types.StackEvent) { - // Returned values for a stack events are hit or miss, so lets try to create a - // meaningful string. - var buf strings.Builder - fmt.Fprintf(&buf, "Stack event received") - - writeOptKV(&buf, "ResourceType", event.ResourceType) - writeOptKV(&buf, "LogicalResourceId", event.LogicalResourceId) - s := string(event.ResourceStatus) - writeOptKV(&buf, "ResourceStatus", &s) - writeOptKV(&buf, "ResourceStatusReason", event.ResourceStatusReason) - - log.Info(buf.String()) - }}, - ) -} - -func writeKV(buf *strings.Builder, key string, value string) { - fmt.Fprintf(buf, ", %s: %s", key, value) -} - -func writeOptKV(buf *strings.Builder, key string, value *string) { - if value != nil { - writeKV(buf, key, *value) - } -} diff --git a/x-pack/functionbeat/manager/aws/op_cloudformation_test.go b/x-pack/functionbeat/manager/aws/op_cloudformation_test.go deleted file mode 100644 index 767b638083b4..000000000000 --- a/x-pack/functionbeat/manager/aws/op_cloudformation_test.go +++ /dev/null @@ -1,211 +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 aws - -import ( - "context" - "errors" - "testing" - - "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" - - "github.com/aws/aws-sdk-go-v2/service/cloudformation" - "github.com/stretchr/testify/assert" - - "github.com/elastic/elastic-agent-libs/logp" -) - -type mockCloudformationStack struct { - respCreateStackOutput *cloudformation.CreateStackOutput - onCreateStackInput func(*cloudformation.CreateStackInput) - - respDeleteStackOutput *cloudformation.DeleteStackOutput - onDeleteStackInput func(*cloudformation.DeleteStackInput) - - respDescribeStacksOutput *cloudformation.DescribeStacksOutput - onDescribeStacksInput func(*cloudformation.DescribeStacksInput) - - respUpdateStackOutput *cloudformation.UpdateStackOutput - onUpdateStackInput func(*cloudformation.UpdateStackInput) - err error -} - -func (m *mockCloudformationStack) CreateStack(ctx context.Context, params *cloudformation.CreateStackInput, optFns ...func(*cloudformation.Options)) (*cloudformation.CreateStackOutput, error) { - if m.onCreateStackInput != nil { - m.onCreateStackInput(params) - } - - if m.err != nil { - return m.respCreateStackOutput, m.err - } - - return m.respCreateStackOutput, nil -} - -func (m *mockCloudformationStack) DeleteStack(ctx context.Context, params *cloudformation.DeleteStackInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DeleteStackOutput, error) { - if m.onDeleteStackInput != nil { - m.onDeleteStackInput(params) - } - - if m.err != nil { - return m.respDeleteStackOutput, m.err - } - - return m.respDeleteStackOutput, nil -} - -func (m *mockCloudformationStack) DescribeStacks(ctx context.Context, params *cloudformation.DescribeStacksInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DescribeStacksOutput, error) { - if m.onDescribeStacksInput != nil { - m.onDescribeStacksInput(params) - } - - if m.err != nil { - return m.respDescribeStacksOutput, m.err - } - - return m.respDescribeStacksOutput, nil -} - -func (m *mockCloudformationStack) UpdateStack(ctx context.Context, params *cloudformation.UpdateStackInput, optFns ...func(*cloudformation.Options)) (*cloudformation.UpdateStackOutput, error) { - if m.onUpdateStackInput != nil { - m.onUpdateStackInput(params) - } - - if m.err != nil { - return m.respUpdateStackOutput, m.err - } - - return m.respUpdateStackOutput, nil -} - -func TestCreateStack(t *testing.T) { - stackName := "new-stack" - stackID := "new-stack-ID" - templateURL := "https://localhost/stack.zip" - log := logp.NewLogger("") - - t.Run("assert execution context", func(t *testing.T) { - op := &opCreateCloudFormation{} - err := op.Execute(struct{}{}) - assert.Error(t, err) - }) - - t.Run("create stack", func(t *testing.T) { - mockSvc := &mockCloudformationStack{respCreateStackOutput: &cloudformation.CreateStackOutput{ - StackId: &stackID, - }, onCreateStackInput: func(input *cloudformation.CreateStackInput) { - assert.Equal(t, stackName, *input.StackName) - assert.Equal(t, templateURL, *input.TemplateURL) - }} - - ctx := &stackContext{} - op := newOpCreateCloudFormation(log, mockSvc, templateURL, stackName) - err := op.Execute(ctx) - if !assert.NoError(t, err) { - return - } - - assert.Equal(t, stackID, *ctx.ID) - }) - - t.Run("bubble any stack error back to the caller", func(t *testing.T) { - anErr := errors.New("something is bad") - mockSvc := &mockCloudformationStack{err: anErr} - - ctx := &stackContext{} - op := newOpCreateCloudFormation(log, mockSvc, templateURL, stackName) - err := op.Execute(ctx) - assert.Equal(t, anErr, err) - }) -} - -func TestDeleteStack(t *testing.T) { - stackName := "new-stack" - stackID := "new-stack-ID" - log := logp.NewLogger("") - - t.Run("assert execution context", func(t *testing.T) { - op := &opDeleteCloudFormation{} - err := op.Execute(struct{}{}) - assert.Error(t, err) - }) - - t.Run("delete stack", func(t *testing.T) { - mockSvc := &mockCloudformationStack{ - respDeleteStackOutput: &cloudformation.DeleteStackOutput{}, - onDeleteStackInput: func( - input *cloudformation.DeleteStackInput, - ) { - assert.Equal(t, stackName, *input.StackName) - }, - respDescribeStacksOutput: &cloudformation.DescribeStacksOutput{ - Stacks: []types.Stack{types.Stack{StackId: &stackID}}, - }, - } - ctx := &stackContext{} - op := newOpDeleteCloudFormation(log, mockSvc, stackName) - err := op.Execute(ctx) - if !assert.NoError(t, err) { - return - } - - assert.Equal(t, stackID, *ctx.ID) - }) - - t.Run("bubble any stack error back to the caller", func(t *testing.T) { - anErr := errors.New("something is bad") - mockSvc := &mockCloudformationStack{err: anErr} - - ctx := &stackContext{} - op := newOpDeleteCloudFormation(log, mockSvc, stackName) - err := op.Execute(ctx) - assert.Equal(t, anErr, err) - }) -} - -func TestUpdateStack(t *testing.T) { - stackName := "new-stack" - stackID := "new-stack-ID" - templateURL := "https://localhost/stack.zip" - log := logp.NewLogger("") - - t.Run("assert execution context", func(t *testing.T) { - op := &opDeleteCloudFormation{} - err := op.Execute(struct{}{}) - assert.Error(t, err) - }) - - t.Run("update stack", func(t *testing.T) { - mockSvc := &mockCloudformationStack{ - onUpdateStackInput: func( - input *cloudformation.UpdateStackInput, - ) { - assert.Equal(t, stackName, *input.StackName) - assert.Equal(t, templateURL, *input.TemplateURL) - }, - respUpdateStackOutput: &cloudformation.UpdateStackOutput{ - StackId: &stackID, - }, - } - ctx := &stackContext{} - op := newOpUpdateCloudFormation(log, mockSvc, templateURL, stackName) - err := op.Execute(ctx) - if !assert.NoError(t, err) { - return - } - - assert.Equal(t, stackID, *ctx.ID) - }) - - t.Run("bubble any stack error back to the caller", func(t *testing.T) { - anErr := errors.New("something is bad") - mockSvc := &mockCloudformationStack{err: anErr} - - ctx := &stackContext{} - op := newOpUpdateCloudFormation(log, mockSvc, templateURL, stackName) - err := op.Execute(ctx) - assert.Equal(t, anErr, err) - }) -} diff --git a/x-pack/functionbeat/manager/aws/op_delete_cloudformation.go b/x-pack/functionbeat/manager/aws/op_delete_cloudformation.go deleted file mode 100644 index 4954e70b2666..000000000000 --- a/x-pack/functionbeat/manager/aws/op_delete_cloudformation.go +++ /dev/null @@ -1,63 +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 aws - -import ( - "context" - - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/cloudformation" - "github.com/gofrs/uuid/v5" - - "github.com/elastic/beats/v7/x-pack/functionbeat/manager/executor" - "github.com/elastic/elastic-agent-libs/logp" -) - -type opDeleteCloudFormation struct { - log *logp.Logger - svc deleteStackClient - stackName string -} - -func (o *opDeleteCloudFormation) Execute(ctx executor.Context) error { - c, ok := ctx.(*stackContext) - if !ok { - return errWrongContext - } - - uuid, err := uuid.NewV4() - if err != nil { - return err - } - - // retrieve the stack id from the name so we can have access to the Stack events when the - // stack is completely deleted. - stackID, err := queryStackID(o.svc, aws.String(o.stackName)) - if err != nil { - return err - } - c.ID = stackID - - input := &cloudformation.DeleteStackInput{ - ClientRequestToken: aws.String(uuid.String()), - StackName: aws.String(o.stackName), - } - - resp, err := o.svc.DeleteStack(context.TODO(), input) - if err != nil { - o.log.Debugf("Could not delete the stack, response: %v", resp) - return err - } - - return nil -} - -func newOpDeleteCloudFormation( - log *logp.Logger, - svc deleteStackClient, - stackName string, -) *opDeleteCloudFormation { - return &opDeleteCloudFormation{log: log, svc: svc, stackName: stackName} -} diff --git a/x-pack/functionbeat/manager/aws/op_delete_file_bucket.go b/x-pack/functionbeat/manager/aws/op_delete_file_bucket.go deleted file mode 100644 index e30664fde5be..000000000000 --- a/x-pack/functionbeat/manager/aws/op_delete_file_bucket.go +++ /dev/null @@ -1,52 +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 aws - -import ( - "context" - - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/s3" - - "github.com/elastic/beats/v7/x-pack/functionbeat/manager/executor" - "github.com/elastic/elastic-agent-libs/logp" -) - -type opDeleteFileBucket struct { - log *logp.Logger - svc *s3.Client - bucketName string - path string -} - -func newOpDeleteFileBucket( - log *logp.Logger, - config aws.Config, - bucketName, path string, -) *opDeleteFileBucket { - return &opDeleteFileBucket{ - log: log, - svc: s3.NewFromConfig(config), - bucketName: bucketName, - path: path, - } -} - -func (o *opDeleteFileBucket) Execute(_ executor.Context) error { - o.log.Debugf("Removing file '%s' on bucket '%s'", o.path, o.bucketName) - input := &s3.DeleteObjectInput{ - Bucket: aws.String(o.bucketName), - Key: aws.String(o.path), - } - - resp, err := o.svc.DeleteObject(context.TODO(), input) - - if err != nil { - o.log.Debugf("Could not remove object to S3, resp: %v", resp) - return err - } - o.log.Debug("Remove successful") - return nil -} diff --git a/x-pack/functionbeat/manager/aws/op_ensure_bucket.go b/x-pack/functionbeat/manager/aws/op_ensure_bucket.go deleted file mode 100644 index f394650c119c..000000000000 --- a/x-pack/functionbeat/manager/aws/op_ensure_bucket.go +++ /dev/null @@ -1,61 +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 aws - -import ( - "context" - "errors" - "fmt" - - "github.com/aws/smithy-go" - - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/s3" - - "github.com/elastic/beats/v7/x-pack/functionbeat/manager/executor" - "github.com/elastic/elastic-agent-libs/logp" -) - -// This error is not provided by the S3 error package. -const notFound = "NotFound" - -type opEnsureBucket struct { - log *logp.Logger - svc *s3.Client - bucketName string -} - -func newOpEnsureBucket(log *logp.Logger, cfg aws.Config, bucketName string) *opEnsureBucket { - return &opEnsureBucket{log: log, svc: s3.NewFromConfig(cfg), bucketName: bucketName} -} - -func (o *opEnsureBucket) Execute(_ executor.Context) error { - o.log.Debugf("Verifying presence of S3 bucket: %s", o.bucketName) - - check := &s3.HeadBucketInput{Bucket: aws.String(o.bucketName)} - _, err := o.svc.HeadBucket(context.TODO(), check) - if err == nil { - // The bucket exists and we have permission to access it. - return nil - } - - var apiError smithy.APIError - if errors.As(err, &apiError) { - if apiError.ErrorCode() == notFound { - // bucket do not exist let's create it. - input := &s3.CreateBucketInput{Bucket: aws.String(o.bucketName)} - resp, err := o.svc.CreateBucket(context.TODO(), input) - if err != nil { - o.log.Debugf("Could not create bucket, resp: %v", resp) - return err - } - // bucket created successfully - return nil - } - } - - // Catchall for unauthorized access. - return fmt.Errorf("bucket '%s' already exist and you don't have permission to access it: %w", o.bucketName, err) -} diff --git a/x-pack/functionbeat/manager/aws/op_update_cloudformation.go b/x-pack/functionbeat/manager/aws/op_update_cloudformation.go deleted file mode 100644 index 9a75909f2479..000000000000 --- a/x-pack/functionbeat/manager/aws/op_update_cloudformation.go +++ /dev/null @@ -1,68 +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 aws - -import ( - "context" - - "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" - - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/cloudformation" - "github.com/gofrs/uuid/v5" - - "github.com/elastic/beats/v7/x-pack/functionbeat/manager/executor" - "github.com/elastic/elastic-agent-libs/logp" -) - -type opUpdateCloudFormation struct { - log *logp.Logger - svc updateStackClient - templateURL string - stackName string -} - -func (o *opUpdateCloudFormation) Execute(ctx executor.Context) error { - c, ok := ctx.(*stackContext) - if !ok { - return errWrongContext - } - - uuid, err := uuid.NewV4() - if err != nil { - return err - } - input := &cloudformation.UpdateStackInput{ - ClientRequestToken: aws.String(uuid.String()), - StackName: aws.String(o.stackName), - TemplateURL: aws.String(o.templateURL), - Capabilities: []types.Capability{ - types.CapabilityCapabilityNamedIam, - }, - } - - resp, err := o.svc.UpdateStack(context.TODO(), input) - if err != nil { - o.log.Debugf("Could not update the cloudformation stack, resp: %+v", resp) - return err - } - - c.ID = resp.StackId - - return nil -} - -func newOpUpdateCloudFormation( - log *logp.Logger, - svc updateStackClient, - templateURL, stackName string, -) *opUpdateCloudFormation { - return &opUpdateCloudFormation{ - log: log, - svc: svc, - templateURL: templateURL, - stackName: stackName, - } -} diff --git a/x-pack/functionbeat/manager/aws/op_upload_to_bucket.go b/x-pack/functionbeat/manager/aws/op_upload_to_bucket.go deleted file mode 100644 index 0825a26b35a8..000000000000 --- a/x-pack/functionbeat/manager/aws/op_upload_to_bucket.go +++ /dev/null @@ -1,68 +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 aws - -import ( - "bytes" - "context" - - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/s3" - - "github.com/elastic/beats/v7/x-pack/functionbeat/manager/executor" - "github.com/elastic/elastic-agent-libs/logp" -) - -type opUploadToBucket struct { - log *logp.Logger - svc *s3.Client - bucketName string - path string - raw []byte - config aws.Config -} - -func newOpUploadToBucket( - log *logp.Logger, - config aws.Config, - bucketName, path string, - raw []byte, -) *opUploadToBucket { - return &opUploadToBucket{ - log: log, - svc: s3.NewFromConfig(config), - bucketName: bucketName, - path: path, - raw: raw, - config: config, - } -} - -func (o *opUploadToBucket) Execute(_ executor.Context) error { - o.log.Debugf("Uploading file '%s' to bucket '%s' with size %d bytes", o.path, o.bucketName, len(o.raw)) - input := &s3.PutObjectInput{ - Bucket: aws.String(o.bucketName), - Body: bytes.NewReader(o.raw), - Key: aws.String(o.path), - } - resp, err := o.svc.PutObject(context.TODO(), input) - - if err != nil { - o.log.Debugf("Could not upload object to S3, resp: %v", resp) - return err - } - o.log.Debug("Upload successful") - return nil -} - -func (o *opUploadToBucket) Rollback(ctx executor.Context) error { - // The error will be logged but we do not enforce a hard failure because the file could have - // been removed before. - err := newOpDeleteFileBucket(o.log, o.config, o.bucketName, o.path).Execute(ctx) - if err != nil { - o.log.Debugf("Fail to delete file on bucket, error: %+v", err) - } - return nil -} diff --git a/x-pack/functionbeat/manager/aws/op_wait_cloud_formation.go b/x-pack/functionbeat/manager/aws/op_wait_cloud_formation.go deleted file mode 100644 index 7a800fc9773c..000000000000 --- a/x-pack/functionbeat/manager/aws/op_wait_cloud_formation.go +++ /dev/null @@ -1,145 +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 aws - -import ( - "context" - "errors" - "time" - - "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" - - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/cloudformation" - - "github.com/elastic/beats/v7/x-pack/functionbeat/manager/executor" - "github.com/elastic/elastic-agent-libs/logp" -) - -var periodicCheck = 2 * time.Second - -type checkStatusFunc = func(status *types.StackStatus) (bool, error) - -type opWaitCloudFormation struct { - log *logp.Logger - svc *cloudformation.Client - checkStatus checkStatusFunc -} - -func newOpWaitCloudFormation( - log *logp.Logger, - svc *cloudformation.Client, -) *opWaitCloudFormation { - return &opWaitCloudFormation{ - log: log, - svc: svc, - checkStatus: checkCreateStatus, - } -} - -func newWaitDeleteCloudFormation( - log *logp.Logger, - cfg aws.Config, -) *opWaitCloudFormation { - return &opWaitCloudFormation{ - log: log, - svc: cloudformation.NewFromConfig(cfg), - checkStatus: checkDeleteStatus, - } -} - -func (o *opWaitCloudFormation) Execute(ctx executor.Context) error { - c, ok := ctx.(*stackContext) - if !ok { - return errWrongContext - } - - if c.ID == nil { - return errMissingStackID - } - - eventStackPoller := makeEventStackPoller(o.log, o.svc, periodicCheck, c) - eventStackPoller.Start() - defer eventStackPoller.Stop() - - for { - status, _, err := queryStackStatus(o.svc, c.ID) - if err != nil { - return err - } - - completed, err := o.checkStatus(status) - if err != nil { - return err - } - - if completed { - return nil - } - - <-time.After(periodicCheck) - } -} - -func checkCreateStatus(status *types.StackStatus) (bool, error) { - switch *status { - case types.StackStatusUpdateComplete: // OK - return true, nil - case types.StackStatusCreateComplete: // OK - return true, nil - case types.StackStatusRollbackFailed: - return true, errors.New("failed to create and rollback the stack") - case types.StackStatusRollbackComplete: - return true, errors.New("failed to create the stack") - } - return false, nil -} - -func checkDeleteStatus(status *types.StackStatus) (bool, error) { - switch *status { - case types.StackStatusDeleteComplete: // OK - return true, nil - case types.StackStatusDeleteFailed: - return true, errors.New("failed to delete the stack") - case types.StackStatusRollbackFailed: - return true, errors.New("failed to delete and rollback the stack") - case types.StackStatusRollbackComplete: - return true, errors.New("failed to delete the stack") - } - return false, nil -} - -func queryStack( - svc cloudformation.DescribeStacksAPIClient, - stackID *string, -) (*cloudformation.DescribeStacksOutput, error) { - input := &cloudformation.DescribeStacksInput{StackName: stackID} - resp, err := svc.DescribeStacks(context.TODO(), input) - if err != nil { - return nil, err - } - return resp, nil -} - -func queryStackStatus( - svc cloudformation.DescribeStacksAPIClient, - stackID *string, -) (*types.StackStatus, *string, error) { - resp, err := queryStack(svc, stackID) - if err != nil { - return nil, nil, err - } - - stack := resp.Stacks[0] - return &stack.StackStatus, stack.StackStatusReason, nil -} - -func queryStackID(svc cloudformation.DescribeStacksAPIClient, stackName *string) (*string, error) { - resp, err := queryStack(svc, stackName) - if err != nil { - return nil, err - } - return resp.Stacks[0].StackId, nil -} diff --git a/x-pack/functionbeat/manager/aws/policies_test.go b/x-pack/functionbeat/manager/aws/policies_test.go deleted file mode 100644 index 30b484d0b353..000000000000 --- a/x-pack/functionbeat/manager/aws/policies_test.go +++ /dev/null @@ -1,71 +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 aws - -import ( - "testing" - - "github.com/awslabs/goformation/v7/cloudformation" - "github.com/awslabs/goformation/v7/cloudformation/iam" - "github.com/stretchr/testify/assert" - - "github.com/elastic/beats/v7/x-pack/functionbeat/function/provider" - fnaws "github.com/elastic/beats/v7/x-pack/functionbeat/provider/aws/aws" - conf "github.com/elastic/elastic-agent-libs/config" -) - -func TestConfig(t *testing.T) { - t.Run("test permissions for event_source_arn", testPolicies) -} - -func testPolicies(t *testing.T) { - cfg := conf.MustNewConfigFrom(map[string]interface{}{ - "name": "myfunction", - "description": "mydescription", - "triggers": []map[string]interface{}{ - map[string]interface{}{ - "event_source_arn": "abc456", - }, - map[string]interface{}{ - "event_source_arn": "abc1234", - }, - }, - }) - - k, err := fnaws.NewKinesis(&provider.DefaultProvider{}, cfg) - if !assert.NoError(t, err) { - return - } - - i, ok := k.(installer) - if !assert.True(t, ok) { - return - } - - policies := i.Policies() - if !assert.Equal(t, 1, len(policies)) { - return - } - - // ensure permissions on specified resources - expected := iam.Role_Policy{ - PolicyName: cloudformation.Join("-", []string{"fnb", "kinesis", "myfunction"}), - PolicyDocument: map[string]interface{}{ - "Statement": []map[string]interface{}{ - map[string]interface{}{ - "Action": []string{ - "kinesis:GetRecords", - "kinesis:GetShardIterator", - "Kinesis:DescribeStream", - }, - "Effect": "Allow", - "Resource": []string{"abc1234", "abc456"}, - }, - }, - }, - } - - assert.Equal(t, expected, policies[0]) -} diff --git a/x-pack/functionbeat/manager/aws/stack_context.go b/x-pack/functionbeat/manager/aws/stack_context.go deleted file mode 100644 index 638422cb5bbd..000000000000 --- a/x-pack/functionbeat/manager/aws/stack_context.go +++ /dev/null @@ -1,24 +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 aws - -import ( - "errors" - "time" -) - -var ( - errWrongContext = errors.New("invalid type, expecting stack context") - errMissingStackID = errors.New("missing stack id") -) - -type stackContext struct { - ID *string - StartedAt time.Time -} - -func newStackContext() *stackContext { - return &stackContext{StartedAt: time.Now()} -} diff --git a/x-pack/functionbeat/manager/aws/template_builder.go b/x-pack/functionbeat/manager/aws/template_builder.go deleted file mode 100644 index d988f60d7088..000000000000 --- a/x-pack/functionbeat/manager/aws/template_builder.go +++ /dev/null @@ -1,331 +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 aws - -import ( - "crypto/sha256" - "encoding/base64" - "errors" - "fmt" - - "github.com/awslabs/goformation/v7/cloudformation" - "github.com/awslabs/goformation/v7/cloudformation/iam" - "github.com/awslabs/goformation/v7/cloudformation/lambda" - "github.com/awslabs/goformation/v7/cloudformation/logs" - "github.com/awslabs/goformation/v7/cloudformation/tags" - - "github.com/elastic/beats/v7/x-pack/functionbeat/function/provider" - "github.com/elastic/beats/v7/x-pack/functionbeat/manager/core" - "github.com/elastic/beats/v7/x-pack/functionbeat/manager/core/bundle" - fnaws "github.com/elastic/beats/v7/x-pack/functionbeat/provider/aws/aws" - conf "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/logp" -) - -// zipData stores the data on the zip to be deployed -type zipData struct { - content []byte - checksum string -} - -// templateData stores the template and its metadata required to deploy it -type templateData struct { - json []byte - checksum string - key string - url string - codeKey string - zip zipData -} - -type defaultTemplateBuilder struct { - provider provider.Provider - log *logp.Logger - endpoint string - bucket string -} - -const ( - keyPrefix = "functionbeat-deployment/" - - // Package size limits for AWS, we should be a lot under this limit but - // adding a check to make sure we never go over. - // Ref: https://docs.aws.amazon.com/lambda/latest/dg/limits.html - packageCompressedLimit = 50 * 1000 * 1000 // 50MB - packageUncompressedLimit = 250 * 1000 * 1000 // 250MB -) - -func NewTemplateBuilder(log *logp.Logger, cfg *conf.C, p provider.Provider) (provider.TemplateBuilder, error) { - config := &fnaws.Config{} - if err := cfg.Unpack(config); err != nil { - return nil, err - } - - return &defaultTemplateBuilder{ - provider: p, - log: log, - endpoint: config.Credentials.Endpoint, - bucket: string(config.DeployBucket), - }, nil -} - -func (d *defaultTemplateBuilder) findFunction(name string) (installer, error) { - fn, err := d.provider.FindFunctionByName(name) - if err != nil { - return nil, err - } - - function, ok := fn.(installer) - if !ok { - return nil, errors.New("incompatible type received, expecting: 'functionManager'") - } - - return function, nil -} - -// execute generates a template -func (d *defaultTemplateBuilder) execute(name string) (templateData, error) { - d.log.Debug("Compressing all assets into an artifact") - - content, err := core.MakeZip(packageUncompressedLimit, packageCompressedLimit, zipResources()) - if err != nil { - return templateData{}, err - } - d.log.Debugf("Compression is successful (zip size: %d bytes)", len(content)) - - function, err := d.findFunction(name) - if err != nil { - return templateData{}, err - } - - fnTemplate := function.Template() - - zipChecksum := checksum(content) - codeKey := keyPrefix + name + "/" + zipChecksum + "/functionbeat.zip" - to := d.template(function, name, codeKey) - if err := mergeTemplate(to, fnTemplate); err != nil { - return templateData{}, err - } - - templateJSON, err := to.JSON() - if err != nil { - return templateData{}, err - } - - templateChecksum := checksum(templateJSON) - templateKey := keyPrefix + name + "/" + templateChecksum + "/cloudformation-template-create.json" - templateURL := "https://" + d.bucket + "." + d.endpoint + "/" + templateKey - - return templateData{ - json: templateJSON, - checksum: templateChecksum, - key: templateKey, - url: templateURL, - codeKey: codeKey, - zip: zipData{ - checksum: zipChecksum, - content: content, - }, - }, nil -} - -func (d *defaultTemplateBuilder) template(function installer, name, codeLoc string) *cloudformation.Template { - lambdaConfig := function.LambdaConfig() - - prefix := func(s string) string { - return fnaws.NormalizeResourceName("fnb" + name + s) - } - - // AWS variables references:. - // AWS::Partition: aws, aws-cn, aws-gov. - // AWS::Region: us-east-1, us-east-2, ap-northeast-3, - // AWS::AccountId: account id for the current request. - // AWS::URLSuffix: amazonaws.com - // - // Documentation: https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/Welcome.html - // Intrinsic function reference: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html - - template := cloudformation.NewTemplate() - - role := lambdaConfig.Role - dependsOn := make([]string, 0) - if lambdaConfig.Role == "" { - d.log.Infof("No role is configured for function %s, creating a custom role.", name) - - roleRes := prefix("") + "IAMRoleLambdaExecution" - template.Resources[roleRes] = d.roleTemplate(function, name) - role = cloudformation.GetAtt(roleRes, "Arn") - dependsOn = []string{roleRes} - } - - // Configure the Dead letter, any failed events will be send to the configured amazon resource name. - var dlc *lambda.Function_DeadLetterConfig - if lambdaConfig.DeadLetterConfig != nil && len(lambdaConfig.DeadLetterConfig.TargetArn) != 0 { - dlc = &lambda.Function_DeadLetterConfig{ - TargetArn: cloudformation.String(lambdaConfig.DeadLetterConfig.TargetArn), - } - } - - // Configure VPC - var vcpConf *lambda.Function_VpcConfig - if lambdaConfig.VPCConfig != nil && len(lambdaConfig.VPCConfig.SecurityGroupIDs) != 0 && len(lambdaConfig.VPCConfig.SubnetIDs) != 0 { - vcpConf = &lambda.Function_VpcConfig{ - SecurityGroupIds: lambdaConfig.VPCConfig.SecurityGroupIDs, - SubnetIds: lambdaConfig.VPCConfig.SubnetIDs, - } - } - - ts := make([]tags.Tag, 0, len(lambdaConfig.Tags)) - for name, val := range lambdaConfig.Tags { - tag := tags.Tag{ - Key: name, - Value: val, - } - ts = append(ts, tag) - } - - // Create the lambda - // Doc: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html - template.Resources[prefix("")] = &AWSLambdaFunction{ - Function: &lambda.Function{ - Code: &lambda.Function_Code{ - S3Bucket: cloudformation.String(d.bucket), - S3Key: cloudformation.String(codeLoc), - }, - Description: cloudformation.String(lambdaConfig.Description), - Environment: &lambda.Function_Environment{ - // Configure which function need to be run by the lambda function. - Variables: map[string]string{ - "BEAT_STRICT_PERMS": "false", // Disable any check on disk, we are running with really differents permission on lambda. - "ENABLED_FUNCTIONS": name, - }, - }, - DeadLetterConfig: dlc, - VpcConfig: vcpConf, - FunctionName: cloudformation.String(name), - Role: role, - Runtime: cloudformation.String(runtime), - Handler: cloudformation.String(handlerName), - MemorySize: cloudformation.Int(lambdaConfig.MemorySize.Megabytes()), - ReservedConcurrentExecutions: cloudformation.Int(lambdaConfig.Concurrency), - Timeout: cloudformation.Int(int(lambdaConfig.Timeout.Seconds())), - Tags: ts, - }, - DependsOn: dependsOn, - } - - // Create the log group for the specific function lambda. - template.Resources[prefix("LogGroup")] = &logs.LogGroup{ - LogGroupName: cloudformation.String("/aws/lambda/" + name), - } - - return template -} - -func (d *defaultTemplateBuilder) roleTemplate(function installer, name string) *iam.Role { - // Default policies to writes logs from the Lambda. - policies := []iam.Role_Policy{ - iam.Role_Policy{ - PolicyName: cloudformation.Join("-", []string{"fnb", "lambda", name}), - PolicyDocument: map[string]interface{}{ - "Statement": []map[string]interface{}{ - map[string]interface{}{ - "Action": []string{"logs:CreateLogStream", "logs:PutLogEvents"}, - "Effect": "Allow", - "Resource": []string{ - cloudformation.Sub("arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/" + name + ":*"), - }, - }, - }, - }, - }, - } - - // Merge any specific policies from the service. - policies = append(policies, function.Policies()...) - - // Create the roles for the lambda. - // doc: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html - return &iam.Role{ - AssumeRolePolicyDocument: map[string]interface{}{ - "Statement": []interface{}{ - map[string]interface{}{ - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": map[string]interface{}{ - "Service": cloudformation.Join("", []string{ - "lambda.", - cloudformation.Ref("AWS::URLSuffix"), - }), - }, - }, - }, - }, - Path: cloudformation.String("/"), - RoleName: cloudformation.String("functionbeat-lambda-" + name + "-" + cloudformation.Ref("AWS::Region")), - // Allow the lambda to write log to cloudwatch logs. - // doc: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-policy.html - Policies: policies, - } -} - -// RawTemplate generates a template and returns it in a string -func (d *defaultTemplateBuilder) RawTemplate(name string) (string, error) { - data, err := d.execute(name) - return string(data.json), err -} - -func merge[M1 ~map[K]V, M2 ~map[K]V, K comparable, V any](m1 M1, m2 M2) error { - for k, v := range m2 { - if _, ok := m1[k]; ok { - return fmt.Errorf("key %v already exist in the template map", k) - } - m1[k] = v - } - return nil -} - -// mergeTemplate takes two cloudformation and merge them, if a key already exist we return an error. -func mergeTemplate(to, from *cloudformation.Template) error { - err := merge(to.Parameters, from.Parameters) - if err != nil { - return err - } - - err = merge(to.Mappings, from.Mappings) - if err != nil { - return err - } - - err = merge(to.Conditions, from.Conditions) - if err != nil { - return err - } - - for k, v := range from.Resources { - if _, ok := to.Resources[k]; ok { - return fmt.Errorf("key %s already exist in the template map", k) - } - to.Resources[k] = v - } - - err = merge(to.Outputs, from.Outputs) - if err != nil { - return err - } - - return nil -} - -func checksum(data []byte) string { - sha := sha256.Sum256(data) - return base64.RawURLEncoding.EncodeToString(sha[:]) -} - -func zipResources() []bundle.Resource { - return []bundle.Resource{ - &bundle.LocalFile{Path: "pkg/functionbeat-aws", FileMode: 0755}, - } -} diff --git a/x-pack/functionbeat/manager/beater/functionbeat.go b/x-pack/functionbeat/manager/beater/functionbeat.go deleted file mode 100644 index b8e702860d03..000000000000 --- a/x-pack/functionbeat/manager/beater/functionbeat.go +++ /dev/null @@ -1,58 +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 beater - -import ( - "fmt" - "time" - - "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/x-pack/functionbeat/config" - conf "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/logp" -) - -var ( - graceDelay = 45 * time.Minute - refreshDelay = 15 * time.Minute -) - -// Functionbeat is a beat designed to run under a serverless environment and listen to external triggers, -// each invocation will generate one or more events to Elasticsearch. -// -// Each serverless implementation is different but functionbeat follows a few execution rules. -// - Publishing events from the source to the output is done synchronously. -// - Execution can be suspended. -// - Run on a read only filesystem -// - More execution constraints based on speed and memory usage. -type Functionbeat struct { - log *logp.Logger - Config *config.Config -} - -// New creates an instance of functionbeat. -func New(b *beat.Beat, cfg *conf.C) (beat.Beater, error) { - c := &config.DefaultConfig - if err := cfg.Unpack(c); err != nil { - return nil, fmt.Errorf("error reading config file: %+v", err) - } - - bt := &Functionbeat{ - log: logp.NewLogger("functionbeat"), - Config: c, - } - return bt, nil -} - -// Run starts functionbeat. -func (bt *Functionbeat) Run(b *beat.Beat) error { - bt.log.Info("Functionbeat is running") - defer bt.log.Info("Functionbeat stopped running") - - return nil -} - -// Stop stops Functionbeat. -func (bt *Functionbeat) Stop() {} diff --git a/x-pack/functionbeat/manager/cmd/cli_handler.go b/x-pack/functionbeat/manager/cmd/cli_handler.go deleted file mode 100644 index 473f6b038f0e..000000000000 --- a/x-pack/functionbeat/manager/cmd/cli_handler.go +++ /dev/null @@ -1,162 +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 cmd - -import ( - "errors" - "fmt" - "io" - "strings" - - "github.com/elastic/beats/v7/x-pack/functionbeat/function/provider" - "github.com/elastic/elastic-agent-libs/logp" -) - -// Errors generated by the cliHandler. -var ( - errNoFunctionGiven = errors.New("no function given") -) - -// cliHandler takes a provider.CLIManager and acts a bridge between user enterred content from the CLI -// and the type managing the function on the provider. It allow to specify multiple functions at -// the command line but will do a single invocation on the CLIManager and will do general validation -// and normalization of the values. It also communicate the status of the operations to the user. -// -// NOTES: Each execution call of the CLIManager are independant, this mean that a fail call will not -// stop other calls to succeed. -// -// TODO(ph) functions could be merged into a single call , but I thought it was premature to do -// it. -type cliHandler struct { - clis map[string]provider.CLIManager - log *logp.Logger - errOutput io.Writer - output io.Writer - - functionsByProvider map[string]string -} - -func newCLIHandler(clis map[string]provider.CLIManager, functionsByProvider map[string]string, errOutput io.Writer, output io.Writer) *cliHandler { - return &cliHandler{ - clis: clis, - errOutput: errOutput, - functionsByProvider: functionsByProvider, - output: output, - log: logp.NewLogger("cli-handler"), - } -} - -func (c *cliHandler) Deploy(names []string) error { - c.log.Debugf("Starting deploy for: %s", strings.Join(names, ", ")) - defer c.log.Debug("Deploy execution ended") - - if len(names) == 0 { - return errNoFunctionGiven - } - - errCount := c.iterateCLIFuncVerbose(names, "deploy", provider.CLIManager.Deploy) - - if errCount > 0 { - return fmt.Errorf("Fail to deploy %d function(s)", errCount) - } - return nil -} - -func (c *cliHandler) Update(names []string) error { - c.log.Debugf("Starting update for: %s", strings.Join(names, ", ")) - defer c.log.Debug("Update execution ended") - - if len(names) == 0 { - return errNoFunctionGiven - } - - errCount := c.iterateCLIFuncVerbose(names, "update", provider.CLIManager.Update) - - if errCount > 0 { - return fmt.Errorf("fail to update %d function(s)", errCount) - } - return nil -} - -func (c *cliHandler) Remove(names []string) error { - c.log.Debugf("Starting remove for: %s", strings.Join(names, ", ")) - defer c.log.Debug("Remove execution ended") - - if len(names) == 0 { - return errNoFunctionGiven - } - - errCount := c.iterateCLIFuncVerbose(names, "remove", provider.CLIManager.Remove) - - if errCount > 0 { - return fmt.Errorf("fail to remove %d function(s)", errCount) - } - return nil -} - -func (c *cliHandler) Export(names []string) error { - c.log.Debugf("Starting export for: %s", strings.Join(names, ", ")) - defer c.log.Debug("Export execution ended") - - if len(names) == 0 { - return errNoFunctionGiven - } - - errCount := c.iterateCLIFuncQuiet(names, "export", provider.CLIManager.Export) - - if errCount > 0 { - return fmt.Errorf("fail to export %d function(s)", errCount) - } - return nil -} - -func (c *cliHandler) Package(outputPattern string) error { - for _, cli := range c.clis { - err := cli.Package(outputPattern) - if err != nil { - return err - } - } - return nil -} - -func (c *cliHandler) iterateCLIFuncVerbose(names []string, operation string, f func(provider.CLIManager, string) error) int { - return c.iterateCLIFunc(names, operation, f, true) -} - -func (c *cliHandler) iterateCLIFuncQuiet(names []string, operation string, f func(provider.CLIManager, string) error) int { - return c.iterateCLIFunc(names, operation, f, false) -} - -func (c *cliHandler) iterateCLIFunc(names []string, operation string, f func(provider.CLIManager, string) error, verbose bool) int { - errCount := 0 - for _, name := range names { - providerName, ok := c.functionsByProvider[name] - if !ok { - fmt.Fprintf(c.errOutput, "Function: %s, could not be %sed. Enable it.\n", name, operation) - errCount++ - continue - } - - cli, ok := c.clis[providerName] - if !ok { - fmt.Fprintf(c.errOutput, "Function: %s, could not be %s. Selected provider '%s' cannot be found", name, operation, providerName) - errCount++ - continue - } - - err := f(cli, name) - if err != nil { - fmt.Fprintf(c.errOutput, "Function: %s, could not %s, error: %s\n", name, operation, err) - errCount++ - continue - } - - if verbose { - fmt.Fprintf(c.output, "Function: %s, %s successful\n", name, operation) - } - } - return errCount -} diff --git a/x-pack/functionbeat/manager/cmd/cli_handler_test.go b/x-pack/functionbeat/manager/cmd/cli_handler_test.go deleted file mode 100644 index 726ee93e9a1c..000000000000 --- a/x-pack/functionbeat/manager/cmd/cli_handler_test.go +++ /dev/null @@ -1,161 +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 cmd - -import ( - "bytes" - "errors" - "io" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - - "github.com/elastic/beats/v7/x-pack/functionbeat/function/provider" -) - -type mockCLIManager struct { - mock.Mock -} - -func (m *mockCLIManager) Deploy(name string) error { - args := m.Called(name) - return args.Error(0) -} - -func (m *mockCLIManager) Update(name string) error { - args := m.Called(name) - return args.Error(0) -} - -func (m *mockCLIManager) Remove(name string) error { - args := m.Called(name) - return args.Error(0) -} - -func (m *mockCLIManager) Export(name string) error { - args := m.Called(name) - return args.Error(0) -} - -func (m *mockCLIManager) Package(outputPattern string) error { - args := m.Called(outputPattern) - return args.Error(0) -} - -func outputs() (io.Writer, io.Writer) { - errOut := new(bytes.Buffer) - output := new(bytes.Buffer) - return errOut, output -} - -func functionByProvider() map[string]string { - return map[string]string{ - "super": "mockProvider", - "saiyajin": "mockProvider", - } -} - -func wrapCLIManager(m provider.CLIManager) map[string]provider.CLIManager { - return map[string]provider.CLIManager{ - "mockProvider": m, - } -} - -func TestCliHandler(t *testing.T) { - t.Run("deploy", testDeploy) - t.Run("update", testUpdate) - t.Run("remove", testRemove) -} - -func testDeploy(t *testing.T) { - t.Run("return error when no functions are specified", func(t *testing.T) { - errOut, output := outputs() - handler := newCLIHandler(wrapCLIManager(&mockCLIManager{}), functionByProvider(), errOut, output) - err := handler.Deploy([]string{}) - assert.Equal(t, errNoFunctionGiven, err) - }) - - t.Run("return an error if the manager return an error", func(t *testing.T) { - errOut, output := outputs() - myErr := errors.New("my error") - m := &mockCLIManager{} - m.On("Deploy", "saiyajin").Return(myErr) - handler := newCLIHandler(wrapCLIManager(m), functionByProvider(), errOut, output) - err := handler.Deploy([]string{"saiyajin"}) - assert.Error(t, err) - }) - - t.Run("call the method for all the functions", func(t *testing.T) { - errOut, output := outputs() - m := &mockCLIManager{} - m.On("Deploy", "super").Return(nil) - m.On("Deploy", "saiyajin").Return(nil) - handler := newCLIHandler(wrapCLIManager(m), functionByProvider(), errOut, output) - err := handler.Deploy([]string{"super", "saiyajin"}) - assert.NoError(t, err) - m.AssertExpectations(t) - }) -} - -func testUpdate(t *testing.T) { - t.Run("return error when no functions are specified", func(t *testing.T) { - errOut, output := outputs() - handler := newCLIHandler(wrapCLIManager(&mockCLIManager{}), functionByProvider(), errOut, output) - err := handler.Update([]string{}) - assert.Equal(t, errNoFunctionGiven, err) - }) - - t.Run("return an error if the manager return an error", func(t *testing.T) { - errOut, output := outputs() - myErr := errors.New("my error") - m := &mockCLIManager{} - m.On("Update", "saiyajin").Return(myErr) - handler := newCLIHandler(wrapCLIManager(m), functionByProvider(), errOut, output) - err := handler.Update([]string{"saiyajin"}) - assert.Error(t, err) - }) - - t.Run("call the method for all the functions", func(t *testing.T) { - errOut, output := outputs() - m := &mockCLIManager{} - m.On("Update", "super").Return(nil) - m.On("Update", "saiyajin").Return(nil) - handler := newCLIHandler(wrapCLIManager(m), functionByProvider(), errOut, output) - err := handler.Update([]string{"super", "saiyajin"}) - assert.NoError(t, err) - m.AssertExpectations(t) - }) -} - -func testRemove(t *testing.T) { - t.Run("return error when no functions are specified", func(t *testing.T) { - errOut, output := outputs() - handler := newCLIHandler(wrapCLIManager(&mockCLIManager{}), functionByProvider(), errOut, output) - err := handler.Remove([]string{}) - assert.Equal(t, errNoFunctionGiven, err) - }) - - t.Run("return an error if the manager return an error", func(t *testing.T) { - errOut, output := outputs() - myErr := errors.New("my error") - m := &mockCLIManager{} - m.On("Remove", "saiyajin").Return(myErr) - handler := newCLIHandler(wrapCLIManager(m), functionByProvider(), errOut, output) - err := handler.Remove([]string{"saiyajin"}) - assert.Error(t, err) - }) - - t.Run("call the method for all the functions", func(t *testing.T) { - errOut, output := outputs() - m := &mockCLIManager{} - m.On("Remove", "super").Return(nil) - m.On("Remove", "saiyajin").Return(nil) - handler := newCLIHandler(wrapCLIManager(m), functionByProvider(), errOut, output) - err := handler.Remove([]string{"super", "saiyajin"}) - assert.NoError(t, err) - m.AssertExpectations(t) - }) -} diff --git a/x-pack/functionbeat/manager/cmd/provider_cmd.go b/x-pack/functionbeat/manager/cmd/provider_cmd.go deleted file mode 100644 index 70c0637f108c..000000000000 --- a/x-pack/functionbeat/manager/cmd/provider_cmd.go +++ /dev/null @@ -1,142 +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 cmd - -import ( - "os" - "path/filepath" - - "github.com/spf13/cobra" - - "github.com/elastic/beats/v7/libbeat/cmd/instance" - "github.com/elastic/beats/v7/libbeat/common/cli" - "github.com/elastic/beats/v7/x-pack/functionbeat/config" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/provider" -) - -func initProviders() ([]provider.Provider, error) { - b, err := instance.NewInitializedBeat(instance.Settings{ - Name: Name, - ConfigOverrides: config.Overrides, - }) - if err != nil { - return nil, err - } - - c, err := b.BeatConfig() - if err != nil { - return nil, err - } - - cfg := &config.DefaultConfig - if err := c.Unpack(cfg); err != nil { - return nil, err - } - - var providers []provider.Provider - for _, p := range cfg.Provider.GetFields() { - isAvailable, err := provider.IsAvailable(p) - if err != nil { - return nil, err - } - if !isAvailable { - continue - } - - providerCfg, err := cfg.Provider.Child(p, -1) - if err != nil { - return nil, err - } - provider, err := provider.NewProvider(p, providerCfg) - if err != nil { - return nil, err - } - providers = append(providers, provider) - } - - return providers, nil -} - -func handler() (*cliHandler, error) { - providers, err := initProviders() - if err != nil { - return nil, err - } - - clis := make(map[string]provider.CLIManager) - functionsByProvider := make(map[string]string) - for _, provider := range providers { - cli, err := provider.CLIManager() - if err != nil { - return nil, err - } - clis[provider.Name()] = cli - - enabledFunctions, err := provider.EnabledFunctions() - if err != nil { - return nil, err - } - - for _, f := range enabledFunctions { - functionsByProvider[f] = provider.Name() - } - } - return newCLIHandler(clis, functionsByProvider, os.Stdout, os.Stderr), nil -} - -func genCLICmd(use, short string, fn func(*cliHandler, []string) error) *cobra.Command { - return &cobra.Command{ - Use: use, - Short: short, - Run: cli.RunWith(func(_ *cobra.Command, args []string) error { - h, err := handler() - if err != nil { - return err - } - - return fn(h, args) - }), - } -} - -func genDeployCmd() *cobra.Command { - return genCLICmd("deploy", "Deploy a function", (*cliHandler).Deploy) -} - -func genUpdateCmd() *cobra.Command { - return genCLICmd("update", "Update a function", (*cliHandler).Update) -} - -func genRemoveCmd() *cobra.Command { - return genCLICmd("remove", "Remove a function", (*cliHandler).Remove) -} - -func genExportFunctionCmd() *cobra.Command { - return genCLICmd("function", "Export function template", (*cliHandler).Export) -} - -func genPackageCmd() *cobra.Command { - var outputPattern string - cmd := &cobra.Command{ - Use: "package", - Short: "Package the configuration and the executable in a zip", - Run: cli.RunWith(func(cmd *cobra.Command, args []string) error { - h, err := handler() - if err != nil { - return err - } - return h.Package(outputPattern) - }), - } - - dir, err := os.Getwd() - if err != nil { - panic(err) - } - - defaultOutput := filepath.Join(dir, "package-{{.Provider}}.zip") - cmd.Flags().StringVarP(&outputPattern, "output", "o", defaultOutput, "full path pattern to the package") - return cmd -} diff --git a/x-pack/functionbeat/manager/cmd/root.go b/x-pack/functionbeat/manager/cmd/root.go deleted file mode 100644 index fb44d45e3316..000000000000 --- a/x-pack/functionbeat/manager/cmd/root.go +++ /dev/null @@ -1,50 +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 cmd - -import ( - "os" - - "github.com/spf13/cobra" - - cmd "github.com/elastic/beats/v7/libbeat/cmd" - "github.com/elastic/beats/v7/libbeat/cmd/instance" - "github.com/elastic/beats/v7/x-pack/functionbeat/config" - "github.com/elastic/beats/v7/x-pack/functionbeat/manager/beater" -) - -// Name of this beat -var Name = "functionbeat" - -// RootCmd to handle functionbeat -var RootCmd *cmd.BeatsRootCmd - -func init() { - RootCmd = cmd.GenRootCmdWithSettings(beater.New, instance.Settings{ - Name: Name, - HasDashboards: false, - ConfigOverrides: config.Overrides, - ElasticLicensed: true, - }) - - RootCmd.RemoveCommand(RootCmd.RunCmd) - RootCmd.Run = func(_ *cobra.Command, _ []string) { - - RootCmd.Usage() - os.Exit(1) - } - - RootCmd.AddCommand(genDeployCmd()) - RootCmd.AddCommand(genUpdateCmd()) - RootCmd.AddCommand(genRemoveCmd()) - RootCmd.AddCommand(genPackageCmd()) - - addBeatSpecificSubcommands() -} - -func addBeatSpecificSubcommands() { - RootCmd.ExportCmd.Short = "Export current config, index template or function" - RootCmd.ExportCmd.AddCommand(genExportFunctionCmd()) -} diff --git a/x-pack/functionbeat/manager/core/bundle/bundle.go b/x-pack/functionbeat/manager/core/bundle/bundle.go deleted file mode 100644 index f034c4400f49..000000000000 --- a/x-pack/functionbeat/manager/core/bundle/bundle.go +++ /dev/null @@ -1,243 +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 bundle - -import ( - "archive/zip" - "bufio" - "bytes" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" -) - -// ReadCloserWith takes a reader and a closer for the specific reader and return an io.ReaderCloser. -func ReadCloserWith(reader io.Reader, closer io.Closer) io.ReadCloser { - return &ReadCloser{reader: reader, closer: closer} -} - -// ReadCloser wraps a io.Reader and a file handle into a FileReadCloser interface, -// this leave the responsability on the consumer to close the handle when its done consuming the -// io.Reader. -type ReadCloser struct { - reader io.Reader - closer io.Closer -} - -// Read proxies the Read to the original io.Reader. -func (f *ReadCloser) Read(p []byte) (int, error) { - return f.reader.Read(p) -} - -// Close closes the file handle this must be called after consuming the io.Reader to make sure we -// don't leak any file handle. -func (f *ReadCloser) Close() error { - return f.closer.Close() -} - -// Resource is the interface used to bundle the resource, a resource can be a local or a remote file. -// Reader must be a io.ReadCloser, this make it easier to deal with streaming of remote data. -type Resource interface { - // Open return an io.ReadCloser of the original resource, this will be used to stream content to - // The compressed file. - Open() (io.ReadCloser, error) - - // Name return the string that will be used as the file name inside the Zip file. - Name() string - - // Mode returns the permission of the file. - Mode() os.FileMode -} - -// Folder returns a list of files in a folder. -func Folder(folder, root string, filemode os.FileMode) []Resource { - resources := make([]Resource, 0) - err := filepath.Walk(folder, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - if info.IsDir() { - return nil - } - - resources = append(resources, &RelativeFile{LocalFile{Path: path, FileMode: filemode}, root}) - - return nil - }) - - if err != nil { - return nil - } - - return resources -} - -// LocalFile represents a local file on disk. -type LocalFile struct { - Path string - FileMode os.FileMode -} - -// Open return a reader for the opened file. -func (l *LocalFile) Open() (io.ReadCloser, error) { - fd, err := os.Open(l.Path) - if err != nil { - return nil, err - } - - reader := bufio.NewReader(fd) - return ReadCloserWith(reader, fd), nil -} - -// Name return the basename of the file to be used as the name of the file in the archive. -func (l *LocalFile) Name() string { - return filepath.Base(l.Path) -} - -// Mode return the permissions of the file in the zip. -func (l *LocalFile) Mode() os.FileMode { - return l.FileMode -} - -// RelativeFile is a Localfile which needs to be placed relatively in the -// root of the bundle. -type RelativeFile struct { - LocalFile - root string -} - -// Name returns the name of the file. -func (r *RelativeFile) Name() string { - if r.root == "" { - return r.LocalFile.Path - } - return r.LocalFile.Path[len(r.root)+1:] -} - -// MemoryFile an in-memory representation of a physical file. -type MemoryFile struct { - Path string - FileMode os.FileMode - Raw []byte -} - -// Open the reader for the raw byte slice. -func (m *MemoryFile) Open() (io.ReadCloser, error) { - reader := bytes.NewReader(m.Raw) - return ioutil.NopCloser(reader), nil -} - -// Name returns the path to use in the zip. -func (m *MemoryFile) Name() string { - return m.Path -} - -// Mode returns the permission of the file. -func (m *MemoryFile) Mode() os.FileMode { - return m.FileMode -} - -// ZipBundle accepts a set of local files to bundle them into a zip file, it also accept size limits -// for the uncompressed and the compressed data. -type ZipBundle struct { - resources []Resource - maxSizeUncompressed int64 - maxSizeCompressed int64 -} - -// NewZipWithoutLimits creates a bundle that doesn't impose any limit on the uncompressed data and the -// compressed data. -func NewZipWithoutLimits(resources ...Resource) *ZipBundle { - return NewZipWithLimits(-1, -1, resources...) -} - -// NewZipWithLimits creates a Bundle that impose limit for the uncompressed data and the compressed data, -// using a limit of -1 with desactivate the check. -func NewZipWithLimits(maxSizeUncompressed, maxSizeCompressed int64, resources ...Resource) *ZipBundle { - return &ZipBundle{ - resources: resources, - maxSizeUncompressed: maxSizeUncompressed, - maxSizeCompressed: maxSizeCompressed, - } -} - -// Bytes takes the resources and bundle them into a zip and validates if needed that the -// created resources doesn't go over any predefined size limits. -func (p *ZipBundle) Bytes() ([]byte, error) { - buf := new(bytes.Buffer) - zipWriter := zip.NewWriter(buf) - - var uncompressed int64 - for _, file := range p.resources { - l, err := zipAddFile(zipWriter, file) - if err != nil { - return nil, err - } - - uncompressed = uncompressed + l - if p.maxSizeUncompressed != -1 && uncompressed > p.maxSizeUncompressed { - // Close the current zip, the zip has incomplete data. - zipWriter.Close() - return nil, fmt.Errorf( - "max uncompressed size reached, size %d, limit is %d", - uncompressed, - p.maxSizeUncompressed, - ) - } - - if l == 0 { - continue - } - - // Force a flush to accurately check for the size of the bytes.Buffer and see if - // we are over the limit. - if err := zipWriter.Flush(); err != nil { - return nil, err - } - - if p.maxSizeCompressed != -1 && int64(buf.Len()) > p.maxSizeCompressed { - // Close the current zip, the zip has incomplete data. - zipWriter.Close() - return nil, fmt.Errorf( - "max compressed size reached, size %d, limit is %d", - buf.Len(), - p.maxSizeCompressed, - ) - } - } - - // Flush bytes/writes headers, the zip is valid at this point. - zipWriter.Close() - return buf.Bytes(), nil -} - -func zipAddFile(zipWriter *zip.Writer, r Resource) (int64, error) { - f, err := r.Open() - if err != nil { - return 0, err - } - defer f.Close() - - header := &zip.FileHeader{ - Name: r.Name(), - Method: zip.Deflate, - } - - header.SetMode(r.Mode()) - w, err := zipWriter.CreateHeader(header) - if err != nil { - return 0, err - } - - l, err := io.Copy(w, f) - if err != nil { - return 0, err - } - - return l, nil -} diff --git a/x-pack/functionbeat/manager/core/bundle/bundle_test.go b/x-pack/functionbeat/manager/core/bundle/bundle_test.go deleted file mode 100644 index 89d010522b77..000000000000 --- a/x-pack/functionbeat/manager/core/bundle/bundle_test.go +++ /dev/null @@ -1,150 +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 bundle - -import ( - "archive/zip" - "bytes" - "io/ioutil" - "os" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/elastic/beats/v7/libbeat/common" -) - -func newFixedResource(name string, length int64) *MemoryFile { - paddingData, err := common.RandomBytes(int(length)) - if err != nil { - // fatal, This mean something is wrong with the random number generator. - panic(err) - } - return &MemoryFile{Path: name, Raw: paddingData, FileMode: 0755} -} - -func TestZipBundle(t *testing.T) { - t.Run("with limits", testWithLimits) - t.Run("with no limits", testArtifact(-1, -1)) -} - -func testWithLimits(t *testing.T) { - t.Run("uncompressed size is over limit", func(t *testing.T) { - limit := int64(50) - bundle := NewZipWithLimits(limit, -1, newFixedResource("ok.yml", limit+1)) - _, err := bundle.Bytes() - assert.Error(t, err) - }) - - t.Run("compressed size is over limit", func(t *testing.T) { - limit := int64(10) - bundle := NewZipWithLimits(-1, limit, newFixedResource("ok.yml", 2*limit)) - _, err := bundle.Bytes() - assert.Error(t, err) - }) - - t.Run("zip artifact is under limit and valid", testArtifact(1000, 1000)) -} - -func testArtifact(maxSizeUncompressed, maxSizeCompressed int64) func(t *testing.T) { - return func(t *testing.T) { - m := map[string]*MemoryFile{ - "f1.txt": newFixedResource("f1.txt", 65), - "f2.txt": newFixedResource("f2.txt", 100), - } - - resources := make([]Resource, len(m)) - var idx int - for _, r := range m { - resources[idx] = r - idx++ - } - - bundle := NewZipWithLimits(maxSizeUncompressed, maxSizeCompressed, resources...) - b, err := bundle.Bytes() - if !assert.NoError(t, err) { - return - } - - zip, err := zip.NewReader(bytes.NewReader(b), int64(len(b))) - if !assert.NoError(t, err) { - return - } - - if !assert.Equal(t, 2, len(zip.File)) { - return - } - - for _, file := range zip.File { - r, ok := m[file.Name] - if !assert.True(t, ok) { - t.Fatal("unknown file present in the zip") - } - - reader, err := file.Open() - if !assert.NoError(t, err) { - return - } - defer reader.Close() - - raw, err := ioutil.ReadAll(reader) - if !assert.NoError(t, err) { - return - } - - assert.True(t, bytes.Equal(r.Raw, raw), "bytes doesn't match") - } - } -} - -func TestLocalFile(t *testing.T) { - local := LocalFile{Path: "testdata/lipsum.txt", FileMode: 755} - - assert.Equal(t, "lipsum.txt", local.Name()) - assert.Equal(t, os.FileMode(755), local.Mode()) - - reader, err := local.Open() - if !assert.NoError(t, err) { - return - } - - defer func() { - err := reader.Close() - assert.NoError(t, err) - }() - - content, err := ioutil.ReadAll(reader) - if !assert.NoError(t, err) { - return - } - - raw, _ := ioutil.ReadFile("testdata/lipsum.txt") - assert.Equal(t, raw, content) -} - -func TestMemoryFile(t *testing.T) { - raw := []byte("hello world") - memory := MemoryFile{Path: "lipsum.txt", FileMode: 755, Raw: raw} - - assert.Equal(t, "lipsum.txt", memory.Name()) - assert.Equal(t, os.FileMode(755), memory.Mode()) - - reader, err := memory.Open() - if !assert.NoError(t, err) { - return - } - - defer func() { - err := reader.Close() - assert.NoError(t, err) - }() - - content, err := ioutil.ReadAll(reader) - if !assert.NoError(t, err) { - return - } - - assert.Equal(t, raw, content) -} diff --git a/x-pack/functionbeat/manager/core/bundle/testdata/lipsum.txt b/x-pack/functionbeat/manager/core/bundle/testdata/lipsum.txt deleted file mode 100644 index d86bac9de59a..000000000000 --- a/x-pack/functionbeat/manager/core/bundle/testdata/lipsum.txt +++ /dev/null @@ -1 +0,0 @@ -OK diff --git a/x-pack/functionbeat/manager/core/makezip.go b/x-pack/functionbeat/manager/core/makezip.go deleted file mode 100644 index 6f5c2c2d5309..000000000000 --- a/x-pack/functionbeat/manager/core/makezip.go +++ /dev/null @@ -1,115 +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 core - -import ( - "fmt" - - yaml "gopkg.in/yaml.v2" - - "github.com/elastic/beats/v7/libbeat/cfgfile" - "github.com/elastic/beats/v7/libbeat/cmd/instance" - "github.com/elastic/beats/v7/x-pack/functionbeat/config" - "github.com/elastic/beats/v7/x-pack/functionbeat/manager/core/bundle" - "github.com/elastic/elastic-agent-libs/keystore" -) - -func rawYaml() ([]byte, error) { - // Load the configuration file from disk with all the settings, - // the function takes care of using -c. - rawConfig, err := cfgfile.Load("", config.Overrides) - if err != nil { - return nil, err - } - var config map[string]interface{} - if err := rawConfig.Unpack(&config); err != nil { - return nil, err - } - - res, err := yaml.Marshal(config) - if err != nil { - return nil, err - } - - return res, nil -} - -// MakeZip creates a zip from the the current artifacts and the currently available configuration. -func MakeZip( - packageUncompressedLimit int64, - packageCompressedLimit int64, - providerResources []bundle.Resource, -) ([]byte, error) { - if len(providerResources) == 0 { - return nil, fmt.Errorf("no provider specific resources are set") - } - - rawConfig, err := rawYaml() - if err != nil { - return nil, err - } - - resources := append( - providerResources, - &bundle.MemoryFile{Path: "functionbeat.yml", Raw: rawConfig, FileMode: 0766}, - ) - - resources, err = addKeystoreIfConfigured(resources) - if err != nil { - return nil, err - } - - bundle := bundle.NewZipWithLimits( - packageUncompressedLimit, - packageCompressedLimit, - resources...) - - content, err := bundle.Bytes() - if err != nil { - return nil, err - } - return content, nil -} - -func addKeystoreIfConfigured(resources []bundle.Resource) ([]bundle.Resource, error) { - ksPackager, err := keystorePackager() - if err != nil { - return nil, err - } - - rawKeystore, err := ksPackager.Package() - if err != nil { - return nil, err - } - - if len(rawKeystore) > 0 { - resources = append(resources, &bundle.MemoryFile{ - Path: ksPackager.ConfiguredPath(), - Raw: rawKeystore, - FileMode: 0600, - }) - } - - return resources, nil -} - -func keystorePackager() (keystore.Packager, error) { - cfg, err := cfgfile.Load("", config.Overrides) - if err != nil { - return nil, fmt.Errorf("error loading config file: %v", err) - } - - store, err := instance.LoadKeystore(cfg, "functionbeat") - if err != nil { - return nil, fmt.Errorf("cannot load the keystore for packaging: %w", err) - } - - packager, ok := store.(keystore.Packager) - if !ok { - return nil, fmt.Errorf("the configured keystore cannot be packaged") - } - - return packager, nil -} diff --git a/x-pack/functionbeat/manager/executor/executor.go b/x-pack/functionbeat/manager/executor/executor.go deleted file mode 100644 index 75de2d776b1c..000000000000 --- a/x-pack/functionbeat/manager/executor/executor.go +++ /dev/null @@ -1,112 +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 executor - -import ( - "errors" - - "github.com/elastic/elastic-agent-libs/logp" -) - -var ( - // ErrNeverRun is returned if the step was never run. - ErrNeverRun = errors.New("executor was never executed") - // ErrCannotAdd is returned if the executor had already ran and a new operation is added. - ErrCannotAdd = errors.New("cannot add to an already executed executor") - // ErrAlreadyExecuted is returned if it has already run. - ErrAlreadyExecuted = errors.New("executor already executed") -) - -// Context holds the information of each execution step. -type Context interface{} - -// Executor tries to execute operations. If an operation fails, everything is rolled back. -type Executor struct { - operations []doer - undos []undoer - completed bool - log *logp.Logger -} - -type doer interface { - Execute(Context) error -} - -type undoer interface { - Rollback(Context) error -} - -// NewExecutor return a new executor. -func NewExecutor(log *logp.Logger) *Executor { - if log == nil { - log = logp.NewLogger("") - } - - log = log.Named("executor") - return &Executor{log: log} -} - -// Execute executes all operations. If something fail it rolls back. -func (e *Executor) Execute(ctx Context) (err error) { - e.log.Debugf("The executor is executing '%d' operations for converging state", len(e.operations)) - if e.IsCompleted() { - return ErrAlreadyExecuted - } - for _, operation := range e.operations { - err = operation.Execute(ctx) - if err != nil { - break - } - v, ok := operation.(undoer) - if ok { - e.undos = append(e.undos, v) - } - } - if err == nil { - e.log.Debug("All operations successful") - } - e.markCompleted() - return err -} - -// Rollback rolls back executed operations. -func (e *Executor) Rollback(ctx Context) (err error) { - e.log.Debugf("The executor is rolling back previous execution, '%d' operations to rollback", len(e.undos)) - if !e.IsCompleted() { - return ErrNeverRun - } - for i := len(e.undos) - 1; i >= 0; i-- { - operation := e.undos[i] - err = operation.Rollback(ctx) - if err != nil { - break - } - } - - if err == nil { - e.log.Debug("The rollback is successful") - } else { - e.log.Debug("The rollback is incomplete") - } - return err -} - -// Add adds new operation to execute. -func (e *Executor) Add(operation ...doer) error { - if e.IsCompleted() { - return ErrCannotAdd - } - e.operations = append(e.operations, operation...) - return nil -} - -func (e *Executor) markCompleted() { - e.completed = true -} - -// IsCompleted returns if all operations are completed. -func (e *Executor) IsCompleted() bool { - return e.completed -} diff --git a/x-pack/functionbeat/manager/executor/executor_test.go b/x-pack/functionbeat/manager/executor/executor_test.go deleted file mode 100644 index 024ef79af1d5..000000000000 --- a/x-pack/functionbeat/manager/executor/executor_test.go +++ /dev/null @@ -1,181 +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 executor - -import ( - "errors" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -type MockUndoer struct { - mock.Mock -} - -func (m *MockUndoer) Execute(_ Context) error { - args := m.Called() - return args.Error(0) -} - -func (m *MockUndoer) Rollback(_ Context) error { - args := m.Called() - return args.Error(0) -} - -type MockDoer struct { - mock.Mock -} - -func (m *MockDoer) Execute(_ Context) error { - args := m.Called() - return args.Error(0) -} - -func TestExecutor(t *testing.T) { - t.Run("executes all the tasks", testAll) - t.Run("stop execution on first error", testError) - t.Run("stop execution and allow rollback on undoer", testUndoer) - t.Run("stop rollback if one rollback fail", testFailRollback) - t.Run("an execution cannot be run twice", testCannotRunTwice) - t.Run("cannot add operation to a completed execution", testCannotAddCompleted) -} - -func testAll(t *testing.T) { - ctx := struct{}{} - executor := NewExecutor(nil) - m1 := &MockDoer{} - m1.On("Execute").Return(nil) - - m2 := &MockDoer{} - m2.On("Execute").Return(nil) - - executor.Add(m1, m2) - err := executor.Execute(ctx) - if !assert.NoError(t, err) { - return - } - - m1.AssertExpectations(t) - m2.AssertExpectations(t) -} - -func testError(t *testing.T) { - ctx := struct{}{} - executor := NewExecutor(nil) - m1 := &MockDoer{} - m1.On("Execute").Return(nil) - - m2 := &MockDoer{} - e := errors.New("something bad") - m2.On("Execute").Return(e) - - m3 := &MockDoer{} - executor.Add(m1, m2, m3) - err := executor.Execute(ctx) - if assert.Equal(t, e, err) { - return - } - - m1.AssertExpectations(t) - m2.AssertExpectations(t) - m3.AssertExpectations(t) -} - -func testUndoer(t *testing.T) { - ctx := struct{}{} - executor := NewExecutor(nil) - m1 := &MockUndoer{} - m1.On("Execute").Return(nil) - m1.On("Rollback").Return(nil) - - m2 := &MockDoer{} - e := errors.New("something bad") - m2.On("Execute").Return(e) - - m3 := &MockDoer{} - executor.Add(m1, m2, m3) - err := executor.Execute(ctx) - if !assert.Equal(t, e, err) { - return - } - - err = executor.Rollback(ctx) - if !assert.NoError(t, err) { - return - } - - m1.AssertExpectations(t) - m2.AssertExpectations(t) - m3.AssertExpectations(t) -} - -func testFailRollback(t *testing.T) { - ctx := struct{}{} - e := errors.New("error on execution") - e2 := errors.New("error on rollback") - - executor := NewExecutor(nil) - m1 := &MockUndoer{} - m1.On("Execute").Return(nil) - - m2 := &MockUndoer{} - m2.On("Execute").Return(nil) - m2.On("Rollback").Return(e2) - - m3 := &MockUndoer{} - m3.On("Execute").Return(e) - - executor.Add(m1, m2, m3) - - err := executor.Execute(ctx) - if !assert.Equal(t, e, err) { - return - } - - err = executor.Rollback(ctx) - if !assert.Error(t, err) { - return - } - - m1.AssertExpectations(t) - m2.AssertExpectations(t) - m3.AssertExpectations(t) -} - -func testCannotRunTwice(t *testing.T) { - ctx := struct{}{} - executor := NewExecutor(nil) - m1 := &MockDoer{} - m1.On("Execute").Return(nil) - - executor.Add(m1) - err := executor.Execute(ctx) - if !assert.NoError(t, err) { - return - } - - m1.AssertExpectations(t) - - assert.True(t, executor.IsCompleted()) - assert.Error(t, ErrAlreadyExecuted, executor.Execute(ctx)) -} - -func testCannotAddCompleted(t *testing.T) { - executor := NewExecutor(nil) - m1 := &MockDoer{} - m1.On("Execute").Return(nil) - - executor.Add(m1) - err := executor.Execute(struct{}{}) - if !assert.NoError(t, err) { - return - } - - m1.AssertExpectations(t) - - assert.Error(t, executor.Add(&MockDoer{})) -} diff --git a/x-pack/functionbeat/provider/aws/aws/api_gateway_proxy.go b/x-pack/functionbeat/provider/aws/aws/api_gateway_proxy.go deleted file mode 100644 index 5b9cd9734a5f..000000000000 --- a/x-pack/functionbeat/provider/aws/aws/api_gateway_proxy.go +++ /dev/null @@ -1,96 +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 aws - -import ( - "context" - "encoding/json" - "net/http" - - "github.com/aws/aws-lambda-go/events" - "github.com/aws/aws-lambda-go/lambda" - - "github.com/elastic/beats/v7/libbeat/common/cfgwarn" - "github.com/elastic/beats/v7/libbeat/feature" - "github.com/elastic/beats/v7/libbeat/publisher/pipeline" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/provider" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/telemetry" - "github.com/elastic/beats/v7/x-pack/functionbeat/provider/aws/aws/transformer" - conf "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/logp" -) - -type message struct { - RequestID string `json:"request_id"` - Status int `json:"status"` - Message string `json:"message"` -} - -// APIGatewayProxy receives events from the web service and forward them to elasticsearch. -type APIGatewayProxy struct { - log *logp.Logger -} - -// NewAPIGatewayProxy creates a new function to receives events from the web api gateway. -func NewAPIGatewayProxy(provider provider.Provider, config *conf.C) (provider.Function, error) { - cfgwarn.Experimental("The api_gateway_proxy trigger is experimental.") - return &APIGatewayProxy{log: logp.NewLogger("api gateway proxy")}, nil -} - -// APIGatewayProxyDetails returns the details of the feature. -func APIGatewayProxyDetails() feature.Details { - return feature.MakeDetails("API Gateway proxy trigger", "receive events from the api gateway proxy", feature.Experimental) -} - -// Run starts the lambda function and wait for web triggers. -func (a *APIGatewayProxy) Run(_ context.Context, client pipeline.ISyncClient, telemetry telemetry.T) error { - telemetry.AddTriggeredFunction() - - lambda.Start(a.createHandler(client)) - return nil -} - -func (a *APIGatewayProxy) createHandler( - client pipeline.ISyncClient, -) func(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { - return func(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { - a.log.Debugf("The handler receives a new event from the gateway (requestID: %s)", request.RequestContext.RequestID) - event := transformer.APIGatewayProxyRequest(request) - - if err := client.Publish(event); err != nil { - a.log.Errorf("could not publish event to the pipeline, error: %+v", err) - return buildResponse( - http.StatusInternalServerError, - "an error occurred when sending the event.", - request.RequestContext.RequestID, - ), err - } - client.Wait() - return buildResponse( - http.StatusOK, - "event received successfully.", - request.RequestContext.RequestID, - ), nil - } -} - -func buildResponse( - statusCode int, - responseMsg string, - requestID string, -) events.APIGatewayProxyResponse { - body, _ := json.Marshal(message{Status: statusCode, Message: responseMsg, RequestID: requestID}) - - return events.APIGatewayProxyResponse{ - StatusCode: statusCode, - Headers: map[string]string{"Content-Type": "application/json"}, - Body: string(body), - } -} - -// Name return the name of the lambda function. -func (a *APIGatewayProxy) Name() string { - return "api_gateway_proxy" -} diff --git a/x-pack/functionbeat/provider/aws/aws/api_gateway_proxy_test.go b/x-pack/functionbeat/provider/aws/aws/api_gateway_proxy_test.go deleted file mode 100644 index 640dc949e0cc..000000000000 --- a/x-pack/functionbeat/provider/aws/aws/api_gateway_proxy_test.go +++ /dev/null @@ -1,92 +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 aws - -import ( - "encoding/json" - "errors" - "net/http" - "testing" - - "github.com/aws/aws-lambda-go/events" - "github.com/stretchr/testify/assert" - - "github.com/elastic/beats/v7/x-pack/functionbeat/function/provider" - conf "github.com/elastic/elastic-agent-libs/config" -) - -func TestAPIGatewayProxy(t *testing.T) { - cfg := conf.MustNewConfigFrom(map[string]interface{}{ - "name": "foobar", - }) - - t.Run("when publish is succesful", func(t *testing.T) { - t.SkipNow() - client := &arrayBackedClient{} - s, err := NewAPIGatewayProxy(&provider.DefaultProvider{}, cfg) - if !assert.NoError(t, err) { - return - } - - c, _ := s.(*APIGatewayProxy) - handler := c.createHandler(client) - res, err := handler(generateAPIGatewayProxyEvent()) - assert.NoError(t, err) - assert.Equal(t, res.StatusCode, http.StatusOK) - ty, _ := res.Headers["Content-Type"] - assert.Equal(t, "application/json", ty) - - message, err := unserializeResponse(res.Body) - if !assert.NoError(t, err) { - return - } - - assert.Equal(t, "1234", message.RequestID) - assert.Equal(t, "event received successfully.", message.Message) - assert.Equal(t, http.StatusOK, message.Status) - }) - - t.Run("when publish is not succesful", func(t *testing.T) { - e := errors.New("something bad") - client := &arrayBackedClient{err: e} - - s, err := NewAPIGatewayProxy(&provider.DefaultProvider{}, cfg) - if !assert.NoError(t, err) { - return - } - - c, _ := s.(*APIGatewayProxy) - res, err := c.createHandler(client)(generateAPIGatewayProxyEvent()) - assert.Equal(t, e, err) - assert.Equal(t, http.StatusInternalServerError, res.StatusCode) - ty, _ := res.Headers["Content-Type"] - assert.Equal(t, "application/json", ty) - - message, err := unserializeResponse(res.Body) - if !assert.NoError(t, err) { - return - } - - assert.Equal(t, "1234", message.RequestID) - assert.Equal(t, "an error occurred when sending the event.", message.Message) - assert.Equal(t, http.StatusInternalServerError, message.Status) - }) -} - -func generateAPIGatewayProxyEvent() events.APIGatewayProxyRequest { - return events.APIGatewayProxyRequest{ - RequestContext: events.APIGatewayProxyRequestContext{ - RequestID: "1234", - }, - } -} - -func unserializeResponse(raw string) (*message, error) { - message := &message{} - if err := json.Unmarshal([]byte(raw), message); err != nil { - return nil, err - } - return message, nil -} diff --git a/x-pack/functionbeat/provider/aws/aws/cloudwatch_kinesis.go b/x-pack/functionbeat/provider/aws/aws/cloudwatch_kinesis.go deleted file mode 100644 index adde8793ec5e..000000000000 --- a/x-pack/functionbeat/provider/aws/aws/cloudwatch_kinesis.go +++ /dev/null @@ -1,117 +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 aws - -import ( - "context" - - "github.com/aws/aws-lambda-go/events" - lambdarunner "github.com/aws/aws-lambda-go/lambda" - "github.com/awslabs/goformation/v7/cloudformation" - "github.com/awslabs/goformation/v7/cloudformation/iam" - - "github.com/elastic/beats/v7/libbeat/feature" - "github.com/elastic/beats/v7/libbeat/publisher/pipeline" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/provider" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/telemetry" - "github.com/elastic/beats/v7/x-pack/functionbeat/provider/aws/aws/transformer" - conf "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/logp" -) - -// CloudwatchKinesis receives events from a kinesis stream and forward them to elasticsearch. -type CloudwatchKinesis struct { - *Kinesis - log *logp.Logger - config *CloudwatchKinesisConfig -} - -// CloudwatchKinesisConfig stores the configuration of Kinesis and additional options on decompressing data. -type CloudwatchKinesisConfig struct { - *KinesisConfig `config:",inline"` - Base64Encoded bool `config:"base64_encoded"` - Compressed bool `config:"compressed"` -} - -// NewCloudwatchKinesis creates a new function to receives events from a kinesis stream. -func NewCloudwatchKinesis(provider provider.Provider, cfg *conf.C) (provider.Function, error) { - config := defaultCloudwatchKinesisConfig() - if err := cfg.Unpack(config); err != nil { - return nil, err - } - - logger := logp.NewLogger("cloudwatch_logs_kinesis") - - return &CloudwatchKinesis{ - Kinesis: &Kinesis{ - config: config.KinesisConfig, - log: logger, - }, - log: logger, - config: config, - }, nil -} - -func defaultCloudwatchKinesisConfig() *CloudwatchKinesisConfig { - return &CloudwatchKinesisConfig{ - &KinesisConfig{ - LambdaConfig: DefaultLambdaConfig, - }, - false, - true, - } -} - -// CloudwatchKinesisDetails returns the details of the feature. -func CloudwatchKinesisDetails() feature.Details { - return feature.MakeDetails("Cloudwatch logs via Kinesis trigger", "receive Cloudwatch logs from a Kinesis stream", feature.Experimental) -} - -// Run starts the lambda function and wait for web triggers. -func (c *CloudwatchKinesis) Run(_ context.Context, client pipeline.ISyncClient, t telemetry.T) error { - t.AddTriggeredFunction() - - lambdarunner.Start(c.createHandler(client)) - return nil -} - -func (c *CloudwatchKinesis) createHandler(client pipeline.ISyncClient) func(request events.KinesisEvent) error { - return func(request events.KinesisEvent) error { - c.log.Debugf("The handler receives %d events", len(request.Records)) - - events, err := transformer.CloudwatchKinesisEvent(request, c.config.Base64Encoded, c.config.Compressed) - if err != nil { - return err - } - - if err := client.PublishAll(events); err != nil { - c.log.Errorf("Could not publish events to the pipeline, error: %+v", err) - return err - } - client.Wait() - return nil - } -} - -// Name return the name of the lambda function. -func (c *CloudwatchKinesis) Name() string { - return "cloudwatch_logs_kinesis" -} - -// LambdaConfig returns the configuration to use when creating the lambda. -func (c *CloudwatchKinesis) LambdaConfig() *LambdaConfig { - return c.config.LambdaConfig -} - -// Template returns the cloudformation template for configuring the service with the specified -// triggers. -func (c *CloudwatchKinesis) Template() *cloudformation.Template { - return c.Kinesis.Template() -} - -// Policies returns a slice of policy to add to the lambda role. -func (c *CloudwatchKinesis) Policies() []iam.Role_Policy { - return c.Kinesis.Policies() -} diff --git a/x-pack/functionbeat/provider/aws/aws/cloudwatch_logs.go b/x-pack/functionbeat/provider/aws/aws/cloudwatch_logs.go deleted file mode 100644 index 83f8f0117042..000000000000 --- a/x-pack/functionbeat/provider/aws/aws/cloudwatch_logs.go +++ /dev/null @@ -1,230 +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 aws - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "regexp" - "strconv" - - "github.com/aws/aws-lambda-go/events" - lambdarunner "github.com/aws/aws-lambda-go/lambda" - "github.com/awslabs/goformation/v7/cloudformation" - "github.com/awslabs/goformation/v7/cloudformation/iam" - "github.com/awslabs/goformation/v7/cloudformation/lambda" - "github.com/awslabs/goformation/v7/cloudformation/policies" - - "github.com/elastic/beats/v7/libbeat/feature" - "github.com/elastic/beats/v7/libbeat/publisher/pipeline" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/provider" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/telemetry" - "github.com/elastic/beats/v7/x-pack/functionbeat/provider/aws/aws/transformer" - conf "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/logp" -) - -var ( - logGroupNamePattern = "^[\\.\\-_/#A-Za-z0-9]+$" - logGroupNameRE = regexp.MustCompile(logGroupNamePattern) -) - -// CloudwatchLogsConfig is the configuration for the cloudwatchlogs event type. -type CloudwatchLogsConfig struct { - Triggers []*CloudwatchLogsTriggerConfig `config:"triggers"` - Description string `config:"description"` - Name string `config:"name" validate:"nonzero,required"` - LambdaConfig *LambdaConfig `config:",inline"` -} - -// CloudwatchLogsTriggerConfig is the configuration for the specific triggers for cloudwatch. -type CloudwatchLogsTriggerConfig struct { - LogGroupName logGroupName `config:"log_group_name" validate:"nonzero,required"` - FilterPattern string `config:"filter_pattern"` -} - -// Validate validates the configuration. -func (cfg *CloudwatchLogsConfig) Validate() error { - if len(cfg.Triggers) == 0 { - return errors.New("you need to specify at least one trigger") - } - return nil -} - -// DOC: see validations rules at https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html -type logGroupName string - -// Unpack takes a string and validate the log group format. -func (l *logGroupName) Unpack(s string) error { - const max = 512 - const min = 1 - - if len(s) > max { - return fmt.Errorf("log group name '%s' is too long, maximum length is %d", s, max) - } - - if len(s) < min { - return fmt.Errorf("log group name too short, minimum length is %d", min) - } - - if !logGroupNameRE.MatchString(s) { - return fmt.Errorf( - "invalid characters in log group name '%s', name must match regular expression: '%s'", - s, - logGroupNamePattern, - ) - } - *l = logGroupName(s) - return nil -} - -// CloudwatchLogs receives CloudwatchLogs events from a lambda function and forward the logs to -// an Elasticsearch cluster. -type CloudwatchLogs struct { - log *logp.Logger - config *CloudwatchLogsConfig -} - -// NewCloudwatchLogs create a new function to listen to cloudwatch logs events. -func NewCloudwatchLogs(provider provider.Provider, cfg *conf.C) (provider.Function, error) { - config := &CloudwatchLogsConfig{ - LambdaConfig: DefaultLambdaConfig, - } - if err := cfg.Unpack(config); err != nil { - return nil, err - } - return &CloudwatchLogs{log: logp.NewLogger("cloudwatch_logs"), config: config}, nil -} - -// CloudwatchLogsDetails returns the details of the feature. -func CloudwatchLogsDetails() feature.Details { - return feature.MakeDetails("Cloudwatch Logs trigger", "receive events from cloudwatch logs.", feature.Stable) -} - -// Run start the AWS lambda handles and will transform any events received to the pipeline. -func (c *CloudwatchLogs) Run(_ context.Context, client pipeline.ISyncClient, t telemetry.T) error { - t.AddTriggeredFunction() - - lambdarunner.Start(c.createHandler(client)) - return nil -} - -func (c *CloudwatchLogs) createHandler( - client pipeline.ISyncClient, -) func(request events.CloudwatchLogsEvent) error { - return func(request events.CloudwatchLogsEvent) error { - parsedEvent, err := request.AWSLogs.Parse() - if err != nil { - c.log.Errorf("Could not parse events from cloudwatch logs, error: %+v", err) - return err - } - - c.log.Debugf( - "The handler receives %d events (logStream: %s, owner: %s, logGroup: %s, messageType: %s)", - len(parsedEvent.LogEvents), - parsedEvent.LogStream, - parsedEvent.Owner, - parsedEvent.LogGroup, - parsedEvent.MessageType, - ) - - events := transformer.CloudwatchLogs(parsedEvent) - - if err := client.PublishAll(events); err != nil { - c.log.Errorf("Could not publish events to the pipeline, error: %+v", err) - return err - } - client.Wait() - return nil - } -} - -// Name returns the name of the function. -func (c CloudwatchLogs) Name() string { - return "cloudwatch_logs" -} - -// AWSLogsSubscriptionFilter overrides the type from goformation to allow to pass an empty string. -// The API support an empty string, but requires one, the original type does not permit that. -type AWSLogsSubscriptionFilter struct { - DestinationArn string `json:"DestinationArn,omitempty"` - FilterPattern string `json:"FilterPattern"` - LogGroupName string `json:"LogGroupName,omitempty"` -} - -// MarshalJSON is a custom JSON marshalling hook that embeds this object into -// an AWS CloudFormation JSON resource's 'Properties' field and adds a 'Type'. -func (r AWSLogsSubscriptionFilter) MarshalJSON() ([]byte, error) { - type Properties AWSLogsSubscriptionFilter - return json.Marshal(&struct { - Type string - Properties Properties - DeletionPolicy policies.DeletionPolicy `json:"DeletionPolicy,omitempty"` - }{ - Type: r.AWSCloudFormationType(), - Properties: (Properties)(r), - }) -} - -// AWSCloudFormationType return the AWS type. -func (r *AWSLogsSubscriptionFilter) AWSCloudFormationType() string { - return "AWS::Logs::SubscriptionFilter" -} - -// Template returns the cloudformation template for configuring the service with the specified triggers. -func (c *CloudwatchLogs) Template() *cloudformation.Template { - prefix := func(suffix string) string { - return NormalizeResourceName("fnb" + c.config.Name + suffix) - } - - template := cloudformation.NewTemplate() - for idx, trigger := range c.config.Triggers { - // doc: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-permission.html - template.Resources[prefix("Permission"+strconv.Itoa(idx))] = &lambda.Permission{ - Action: "lambda:InvokeFunction", - FunctionName: cloudformation.GetAtt(prefix(""), "Arn"), - Principal: cloudformation.Join("", []string{ - "logs.", - cloudformation.Ref("AWS::Region"), // Use the configuration region. - ".", - cloudformation.Ref("AWS::URLSuffix"), // awsamazon.com or .com.ch - }), - SourceArn: cloudformation.JoinPtr( - "", - []string{ - "arn:", - cloudformation.Ref("AWS::Partition"), - ":logs:", - cloudformation.Ref("AWS::Region"), - ":", - cloudformation.Ref("AWS::AccountId"), - ":log-group:", - string(trigger.LogGroupName), - ":*", - }, - ), - } - - // doc: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-subscriptionfilter.html - template.Resources[prefix("SF")+NormalizeResourceName(string(trigger.LogGroupName))] = &AWSLogsSubscriptionFilter{ - DestinationArn: cloudformation.GetAtt(prefix(""), "Arn"), - FilterPattern: trigger.FilterPattern, - LogGroupName: string(trigger.LogGroupName), - } - } - return template -} - -// LambdaConfig returns the configuration to use when creating the lambda. -func (c *CloudwatchLogs) LambdaConfig() *LambdaConfig { - return c.config.LambdaConfig -} - -// Policies returns a slice of policy to add to the lambda. -func (c *CloudwatchLogs) Policies() []iam.Role_Policy { - return []iam.Role_Policy{} -} diff --git a/x-pack/functionbeat/provider/aws/aws/cloudwatch_logs_test.go b/x-pack/functionbeat/provider/aws/aws/cloudwatch_logs_test.go deleted file mode 100644 index b9613720b838..000000000000 --- a/x-pack/functionbeat/provider/aws/aws/cloudwatch_logs_test.go +++ /dev/null @@ -1,153 +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 aws - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "encoding/json" - "errors" - "testing" - "time" - - "github.com/aws/aws-lambda-go/events" - "github.com/stretchr/testify/assert" - - "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/common" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/provider" - conf "github.com/elastic/elastic-agent-libs/config" -) - -type arrayBackedClient struct { - Events []beat.Event - err error -} - -func (a *arrayBackedClient) Publish(event beat.Event) error { - if a.err != nil { - return a.err - } - a.Events = append(a.Events, event) - return nil -} - -func (a *arrayBackedClient) PublishAll(events []beat.Event) error { - if a.err != nil { - return a.err - } - a.Events = append(a.Events, events...) - return nil -} - -func (a *arrayBackedClient) Wait() { return } -func (a *arrayBackedClient) Close() error { return nil } - -func TestCloudwatchLogs(t *testing.T) { - cfg := conf.MustNewConfigFrom(map[string]interface{}{ - "name": "foobar", - "description": "my long description", - "role": "arn:aws:iam::000000000000:role/functionbeat", - "triggers": []map[string]interface{}{ - map[string]interface{}{ - "log_group_name": "foo", - "filter_name": "bar", - }, - }, - }) - - t.Run("when publish is succesful", func(t *testing.T) { - client := &arrayBackedClient{} - cwl, err := NewCloudwatchLogs(&provider.DefaultProvider{}, cfg) - if !assert.NoError(t, err) { - return - } - - c, _ := cwl.(*CloudwatchLogs) - handler := c.createHandler(client) - - err = handler(generateCloudwatchLogRawEvent()) - - assert.NoError(t, err) - }) - - t.Run("when publish is not succesful", func(t *testing.T) { - e := errors.New("something bad") - client := &arrayBackedClient{err: e} - cwl, err := NewCloudwatchLogs(&provider.DefaultProvider{}, cfg) - if !assert.NoError(t, err) { - return - } - - c, _ := cwl.(*CloudwatchLogs) - handler := c.createHandler(client) - - err = handler(generateCloudwatchLogRawEvent()) - - assert.Equal(t, e, err) - }) -} - -func generateCloudwatchLogRawEvent() events.CloudwatchLogsEvent { - rawEvent := events.CloudwatchLogsData{ - Owner: "foobar", - LogGroup: "foo", - LogStream: "/var/foobar", - LogEvents: []events.CloudwatchLogsLogEvent{ - events.CloudwatchLogsLogEvent{ - ID: "1234", - Timestamp: time.Now().Unix(), - Message: "hello world", - }, - }, - } - - b, _ := json.Marshal(&rawEvent) - - data := new(bytes.Buffer) - encoder := base64.NewEncoder(base64.StdEncoding, data) - zw := gzip.NewWriter(encoder) - zw.Write(b) - zw.Close() - encoder.Close() - - return events.CloudwatchLogsEvent{ - AWSLogs: events.CloudwatchLogsRawData{ - Data: data.String(), - }, - } -} - -func TestLogGroupName(t *testing.T) { - t.Run("valid name", func(t *testing.T) { - l := logGroupName("") - err := l.Unpack("helloworld") - if !assert.NoError(t, err) { - return - } - - assert.Equal(t, logGroupName("helloworld"), l) - }) - - t.Run("fail if contains invalid chars", func(t *testing.T) { - l := logGroupName("") - err := l.Unpack("hello world") - assert.Error(t, err) - }) - - t.Run("fail if too short", func(t *testing.T) { - l := logGroupName("") - err := l.Unpack("") - assert.Error(t, err) - }) - - t.Run("fail if above 512 chars", func(t *testing.T) { - r, _ := common.RandomBytes(513) - l := logGroupName("") - err := l.Unpack(string(r[:513])) - assert.Error(t, err) - }) -} diff --git a/x-pack/functionbeat/provider/aws/aws/config.go b/x-pack/functionbeat/provider/aws/aws/config.go deleted file mode 100644 index c7a7486d7362..000000000000 --- a/x-pack/functionbeat/provider/aws/aws/config.go +++ /dev/null @@ -1,186 +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 aws - -import ( - "fmt" - "regexp" - "strings" - "time" - "unicode" - "unicode/utf8" - - "github.com/dustin/go-humanize" - - "github.com/elastic/beats/v7/libbeat/common/cfgwarn" - awscommon "github.com/elastic/beats/v7/x-pack/libbeat/common/aws" -) - -// Config expose the configuration option the AWS provider. -type Config struct { - DeployBucket bucket `config:"deploy_bucket" validate:"nonzero,required"` - Region string `config:"region"` - Credentials awscommon.ConfigAWS `config:",inline"` -} - -func DefaultConfig() *Config { - return &Config{ - Credentials: awscommon.ConfigAWS{ - Endpoint: "s3.amazonaws.com", - }, - } -} - -func (c *Config) Validate() error { - if c.Credentials.Endpoint == "" { - return fmt.Errorf("functionbeat.providers.aws.endpoint cannot be empty") - } - return nil -} - -// maxMegabytes maximums memory that a lambda can use. -const maxMegabytes = 3008 - -// DefaultLambdaConfig confguration for AWS lambda function. -var ( - DefaultLambdaConfig = &LambdaConfig{ - MemorySize: 128 * 1024 * 1024, - Timeout: time.Second * 3, - Concurrency: 5, - } - - // Source: https://docs.aws.amazon.com/lambda/latest/dg/API_CreateFunction.html#SSS-CreateFunction-request-Role - arnRolePattern = "arn:(aws[a-zA-Z-]*)?:iam::\\d{12}:role/?[a-zA-Z_0-9+=,.@\\-_/]+" - roleRE = regexp.MustCompile(arnRolePattern) - - // Chars for resource name anything else will be replaced. - validChars = regexp.MustCompile("[^a-zA-Z0-9]") -) - -// LambdaConfig stores the common configuration of Lambda functions. -type LambdaConfig struct { - Concurrency int `config:"concurrency" validate:"min=0,max=1000"` - DeadLetterConfig *deadLetterConfig `config:"dead_letter_config"` - Description string `config:"description"` - MemorySize MemSizeFactor64 `config:"memory_size"` - Timeout time.Duration `config:"timeout" validate:"nonzero,positive"` - Role string `config:"role"` - VPCConfig *vpcConfig `config:"virtual_private_cloud"` - Tags map[string]string `config:"tags"` -} - -// Validate checks a LambdaConfig -func (c *LambdaConfig) Validate() error { - if c.MemorySize.Megabytes() == 0 { - return fmt.Errorf("'memory_size' need to be higher than 0 and must be a factor 64") - } - - if c.MemorySize.Megabytes() > maxMegabytes { - return fmt.Errorf("'memory_size' must be lower than %d", maxMegabytes) - } - - if c.Role != "" && !roleRE.MatchString(c.Role) { - return fmt.Errorf("invalid role: '%s', name must match pattern %s", c.Role, arnRolePattern) - } - - return validateTags(c.Tags) -} - -type deadLetterConfig struct { - TargetArn string `config:"target_arn"` -} - -type vpcConfig struct { - SecurityGroupIDs []string `config:"security_group_ids" validate:"required"` - SubnetIDs []string `config:"subnet_ids" validate:"required"` -} - -func validateTags(tags map[string]string) error { - for key, val := range tags { - if strings.HasPrefix(key, "aws:") { - return fmt.Errorf("key '%s' cannot be prefixed with 'aws:'", key) - } - if strings.HasPrefix(val, "aws:") { - return fmt.Errorf("value '%s' cannot be prefixed with 'aws:'", val) - } - keyLen := utf8.RuneCountInString(key) - if keyLen > 127 { - return fmt.Errorf("too long key; expected 127 chars, but got %d", keyLen) - } - valLen := utf8.RuneCountInString(val) - if valLen > 255 { - return fmt.Errorf("too long value; expected 255 chars, but got %d", valLen) - } - } - - return nil -} - -// MemSizeFactor64 implements a human understandable format for bytes but also make sure that all -// values used are a factor of 64. -type MemSizeFactor64 int - -// Unpack converts a size defined from a human readable format into bytes and verifies that the value -// is a multiple of 64. If the value is not multple of 64, it returns an error. -func (m *MemSizeFactor64) Unpack(v string) error { - sz, err := humanize.ParseBytes(v) - if isRawBytes(v) { - cfgwarn.Deprecate("7.0.0", "size now requires a unit (KiB, MiB, etc...), current value: %s.", v) - } - if err != nil { - return err - } - - if sz%64 != 0 { - return fmt.Errorf("number is not a multiple of 64, %d bytes (user value: %s)", sz, v) - } - - *m = MemSizeFactor64(sz) - return nil -} - -// Megabytes return the value in megabytes. -func (m *MemSizeFactor64) Megabytes() int { - return int(*m) / 1024 / 1024 -} - -func isRawBytes(v string) bool { - for _, c := range v { - if !unicode.IsDigit(c) { - return false - } - } - return true -} - -type bucket string - -// Do some high level validation on the bucket name, they have strict validations on the name on the API side. -// DOC: https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html#bucketnamingrules -func (b *bucket) Unpack(s string) error { - const max = 63 - const min = 3 - if len(s) > max { - return fmt.Errorf("bucket name '%s' is too long, name are restricted to %d chars", s, max) - } - - if len(s) < min { - return fmt.Errorf("bucket name '%s' is too short, name need to be at least %d chars long", s, min) - } - - const bucketNamePattern = "^[a-z0-9][a-z0-9.\\-]{1,61}[a-z0-9]$" - var bucketRE = regexp.MustCompile(bucketNamePattern) - if !bucketRE.MatchString(s) { - return fmt.Errorf("invalid bucket name: '%s', bucket name must match pattern: '%s'", s, bucketNamePattern) - } - - *b = bucket(s) - return nil -} - -// NormalizeResourceName extracts invalid chars. -func NormalizeResourceName(s string) string { - return validChars.ReplaceAllString(s, "") -} diff --git a/x-pack/functionbeat/provider/aws/aws/config_test.go b/x-pack/functionbeat/provider/aws/aws/config_test.go deleted file mode 100644 index ef1045f188ed..000000000000 --- a/x-pack/functionbeat/provider/aws/aws/config_test.go +++ /dev/null @@ -1,135 +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 aws - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestMemSizeFactor64(t *testing.T) { - t.Run("human format", func(t *testing.T) { - t.Run("value is a factor of 64", func(t *testing.T) { - v := MemSizeFactor64(0) - err := v.Unpack("128MiB") - if !assert.NoError(t, err) { - return - } - assert.Equal(t, MemSizeFactor64(128*1024*1024), v) - }) - }) - - t.Run("raw value", func(t *testing.T) { - t.Run("value is a factor of 64", func(t *testing.T) { - v := MemSizeFactor64(0) - err := v.Unpack(fmt.Sprintf("%d", 128*1024*1024)) - if !assert.NoError(t, err) { - return - } - assert.Equal(t, MemSizeFactor64(128*1024*1024), v) - }) - - t.Run("value is not a factor of 64", func(t *testing.T) { - v := MemSizeFactor64(0) - err := v.Unpack("121") - assert.Error(t, err) - }) - }) - - t.Run("returns the value in megabyte", func(t *testing.T) { - v := MemSizeFactor64(128 * 1024 * 1024) - assert.Equal(t, 128, v.Megabytes()) - }) -} -func TestBucket(t *testing.T) { - t.Run("valid bucket name", func(t *testing.T) { - b := bucket("") - err := b.Unpack("hello-bucket") - if !assert.NoError(t, err) { - return - } - assert.Equal(t, bucket("hello-bucket"), b) - }) - - t.Run("too long", func(t *testing.T) { - b := bucket("") - err := b.Unpack("hello-bucket-abc12345566789012345678901234567890123456789012345678901234567890") - assert.Error(t, err) - }) - - t.Run("too short", func(t *testing.T) { - b := bucket("") - err := b.Unpack("he") - assert.Error(t, err) - }) - - t.Run("bucket regex pattern, disallows semi-colon", func(t *testing.T) { - b := bucket("") - err := b.Unpack("asdfdaf;dfadsfadsf") - assert.Error(t, err) - }) - - t.Run("bucket regex pattern, disallows slash", func(t *testing.T) { - b := bucket("") - err := b.Unpack("asdfdaf/dfadsfadsf") - assert.Error(t, err) - }) - - t.Run("bucket regex pattern, allows dots", func(t *testing.T) { - b := bucket("") - err := b.Unpack("this.is.a.bucket") - if !assert.NoError(t, err) { - return - } - assert.Equal(t, bucket("this.is.a.bucket"), b) - }) - - t.Run("bucket regex pattern, allows hyphens", func(t *testing.T) { - b := bucket("") - err := b.Unpack("this-is-a-bucket") - if !assert.NoError(t, err) { - return - } - assert.Equal(t, bucket("this-is-a-bucket"), b) - }) -} - -func TestNormalize(t *testing.T) { - tests := []struct { - title string - candidate string - chars string - expected string - }{ - { - title: "when the string contains invalid chars", - candidate: "/var/log-alpha/tmp:ok", - expected: "varlogalphatmpok", - }, - { - title: "when we have an empty string", - candidate: "", - expected: "", - }, - { - title: "when we don't have any invalid chars", - candidate: "hello", - expected: "hello", - }, - { - title: "when the string contains underscore", - candidate: "/var/log-alpha/tmp:ok_moreok", - expected: "varlogalphatmpokmoreok", - }, - } - - for _, test := range tests { - t.Run(test.title, func(t *testing.T) { - assert.Equal(t, test.expected, NormalizeResourceName(test.candidate)) - }) - } -} diff --git a/x-pack/functionbeat/provider/aws/aws/kinesis.go b/x-pack/functionbeat/provider/aws/aws/kinesis.go deleted file mode 100644 index b286ab214d91..000000000000 --- a/x-pack/functionbeat/provider/aws/aws/kinesis.go +++ /dev/null @@ -1,226 +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 aws - -import ( - "context" - "errors" - "fmt" - "sort" - "strings" - - "github.com/aws/aws-lambda-go/events" - lambdarunner "github.com/aws/aws-lambda-go/lambda" - "github.com/awslabs/goformation/v7/cloudformation" - "github.com/awslabs/goformation/v7/cloudformation/iam" - "github.com/awslabs/goformation/v7/cloudformation/lambda" - - "github.com/elastic/beats/v7/libbeat/feature" - "github.com/elastic/beats/v7/libbeat/publisher/pipeline" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/provider" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/telemetry" - "github.com/elastic/beats/v7/x-pack/functionbeat/provider/aws/aws/transformer" - conf "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/logp" -) - -type startingPosition uint - -const ( - // Looking at the documentation, Kinesis should also support `AT_TIMESTAMP` but looking at the - // request format for cloudformation, I don't see a way to define the timestamp. - // I've looked at other frameworks, and it seems a bug in the cloudformation API. - // doc: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-eventsourcemapping.html - trimHorizonPos startingPosition = iota + 1 - latestPos -) - -var ( - mapStartingPosition = map[string]startingPosition{ - "trim_horizon": trimHorizonPos, - "latest": latestPos, - } - - mapStartingPositionReverse = make(map[startingPosition]string, len(mapStartingPosition)) -) - -func init() { - for k, v := range mapStartingPosition { - mapStartingPositionReverse[v] = strings.ToUpper(k) - } -} - -func (s *startingPosition) Unpack(str string) error { - v, ok := mapStartingPosition[str] - if !ok { - validValues := make([]string, len(mapStartingPosition)) - pos := 0 - for k := range mapStartingPosition { - validValues[pos] = k - pos++ - } - return fmt.Errorf("unknown value %s, valid values are: %s", str, strings.Join(validValues, ", ")) - } - *s = v - return nil -} - -func (s *startingPosition) String() string { - v, ok := mapStartingPositionReverse[*s] - if !ok { - panic("unknown starting position: " + fmt.Sprint(*s)) - } - return v -} - -// KinesisConfig is the configuration for the Kinesis event type. -type KinesisConfig struct { - Description string `config:"description"` - Name string `config:"name" validate:"nonzero,required"` - Triggers []*KinesisTriggerConfig `config:"triggers"` - LambdaConfig *LambdaConfig `config:",inline"` -} - -// Validate validates the configuration. -func (cfg *KinesisConfig) Validate() error { - if len(cfg.Triggers) == 0 { - return errors.New("you need to specify at least one trigger") - } - return nil -} - -// KinesisTriggerConfig configuration for the current trigger. -type KinesisTriggerConfig struct { - EventSourceArn string `config:"event_source_arn" validate:"required"` - BatchSize int `config:"batch_size" validate:"min=100,max=10000"` - StartingPosition startingPosition `config:"starting_position"` - ParallelizationFactor int `config:"parallelization_factor" validate:"min=1,max=10"` -} - -// Unpack unpacks the trigger and make sure the defaults settings are correctly sets. -func (c *KinesisTriggerConfig) Unpack(cfg *conf.C) error { - type tmpConfig KinesisTriggerConfig - config := tmpConfig{ - BatchSize: 100, - StartingPosition: trimHorizonPos, - ParallelizationFactor: 1, - } - if err := cfg.Unpack(&config); err != nil { - return err - } - *c = KinesisTriggerConfig(config) - return nil -} - -// Kinesis receives events from a kinesis stream and forward them to elasticsearch. -type Kinesis struct { - log *logp.Logger - config *KinesisConfig -} - -// NewKinesis creates a new function to receives events from a kinesis stream. -func NewKinesis(provider provider.Provider, cfg *conf.C) (provider.Function, error) { - config := &KinesisConfig{LambdaConfig: DefaultLambdaConfig} - if err := cfg.Unpack(config); err != nil { - return nil, err - } - return &Kinesis{log: logp.NewLogger("kinesis"), config: config}, nil -} - -// KinesisDetails returns the details of the feature. -func KinesisDetails() feature.Details { - return feature.MakeDetails("Kinesis trigger", "receive events from a Kinesis stream", feature.Stable) -} - -// Run starts the lambda function and wait for web triggers. -func (k *Kinesis) Run(_ context.Context, client pipeline.ISyncClient, t telemetry.T) error { - t.AddTriggeredFunction() - - lambdarunner.Start(k.createHandler(client)) - return nil -} - -func (k *Kinesis) createHandler(client pipeline.ISyncClient) func(request events.KinesisEvent) error { - return func(request events.KinesisEvent) error { - k.log.Debugf("The handler receives %d events", len(request.Records)) - - events, err := transformer.KinesisEvent(request) - if err != nil { - return err - } - - if err = client.PublishAll(events); err != nil { - k.log.Errorf("Could not publish events to the pipeline, error: %+v", err) - return err - } - client.Wait() - return nil - } -} - -// Name return the name of the lambda function. -func (k *Kinesis) Name() string { - return "kinesis" -} - -// LambdaConfig returns the configuration to use when creating the lambda. -func (k *Kinesis) LambdaConfig() *LambdaConfig { - return k.config.LambdaConfig -} - -// Template returns the cloudformation template for configuring the service with the specified -// triggers. -func (k *Kinesis) Template() *cloudformation.Template { - template := cloudformation.NewTemplate() - prefix := func(suffix string) string { - return NormalizeResourceName("fnb" + k.config.Name + suffix) - } - - for _, trigger := range k.config.Triggers { - resourceName := prefix(k.Name() + trigger.EventSourceArn) - template.Resources[resourceName] = &lambda.EventSourceMapping{ - BatchSize: cloudformation.Int(trigger.BatchSize), - ParallelizationFactor: cloudformation.Int(trigger.ParallelizationFactor), - EventSourceArn: cloudformation.String(trigger.EventSourceArn), - FunctionName: cloudformation.GetAtt(prefix(""), "Arn"), - StartingPosition: cloudformation.String(trigger.StartingPosition.String()), - } - } - - return template -} - -// Policies returns a slice of policy to add to the lambda role. -func (k *Kinesis) Policies() []iam.Role_Policy { - resources := make([]string, len(k.config.Triggers)) - for idx, trigger := range k.config.Triggers { - resources[idx] = trigger.EventSourceArn - } - - // Give us a chance to generate the same document indenpendant of the changes, - // to help with updates. - sort.Strings(resources) - - policies := []iam.Role_Policy{ - iam.Role_Policy{ - PolicyName: cloudformation.Join("-", []string{"fnb", "kinesis", k.config.Name}), - PolicyDocument: map[string]interface{}{ - "Statement": []map[string]interface{}{ - map[string]interface{}{ - "Action": []string{ - "kinesis:GetRecords", - "kinesis:GetShardIterator", - "Kinesis:DescribeStream", - }, - "Effect": "Allow", - "Resource": resources, - }, - }, - }, - }, - } - - return policies -} diff --git a/x-pack/functionbeat/provider/aws/aws/kinesis_test.go b/x-pack/functionbeat/provider/aws/aws/kinesis_test.go deleted file mode 100644 index 20d92ce36060..000000000000 --- a/x-pack/functionbeat/provider/aws/aws/kinesis_test.go +++ /dev/null @@ -1,302 +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 aws - -import ( - "crypto/md5" - "errors" - "fmt" - "strconv" - "testing" - - "github.com/aws/aws-lambda-go/events" - "github.com/awslabs/kinesis-aggregation/go/v2/deaggregator" - aggRecProto "github.com/awslabs/kinesis-aggregation/go/v2/records" - "github.com/stretchr/testify/assert" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/runtime/protoimpl" - - "github.com/elastic/beats/v7/x-pack/functionbeat/function/provider" - conf "github.com/elastic/elastic-agent-libs/config" -) - -func TestKinesis(t *testing.T) { - cfg := conf.MustNewConfigFrom(map[string]interface{}{ - "name": "foobar", - "triggers": []map[string]interface{}{ - map[string]interface{}{ - "event_source_arn": "abc123", - }, - }, - }) - - t.Run("when publish is successful", func(t *testing.T) { - client := &arrayBackedClient{} - k, err := NewKinesis(&provider.DefaultProvider{}, cfg) - if !assert.NoError(t, err) { - return - } - - c, _ := k.(*Kinesis) - handler := c.createHandler(client) - err = handler(generateKinesisEvent()) - assert.NoError(t, err) - }) - - t.Run("when publish with agg is successful", func(t *testing.T) { - client := &arrayBackedClient{} - k, err := NewKinesis(&provider.DefaultProvider{}, cfg) - if !assert.NoError(t, err) { - return - } - - c, _ := k.(*Kinesis) - handler := c.createHandler(client) - err = handler(generateAggregatedKinesisEvent(true)) - assert.NoError(t, err) - }) - - t.Run("when publish is not successful", func(t *testing.T) { - e := errors.New("something bad") - client := &arrayBackedClient{err: e} - - k, err := NewKinesis(&provider.DefaultProvider{}, cfg) - if !assert.NoError(t, err) { - return - } - - c, _ := k.(*Kinesis) - handler := c.createHandler(client) - err = handler(generateKinesisEvent()) - assert.Equal(t, e, err) - }) - - t.Run("when publish with agg is not successful", func(t *testing.T) { - client := &arrayBackedClient{} - k, err := NewKinesis(&provider.DefaultProvider{}, cfg) - if !assert.NoError(t, err) { - return - } - - c, _ := k.(*Kinesis) - handler := c.createHandler(client) - err = handler(generateAggregatedKinesisEvent(false)) - assert.Error(t, err) - }) - - t.Run("test config validation", testKinesisConfig) - t.Run("test starting position", testStartingPosition) -} - -func generateKinesisEvent() events.KinesisEvent { - return events.KinesisEvent{ - Records: []events.KinesisEventRecord{ - events.KinesisEventRecord{ - AwsRegion: "east-1", - EventID: "1234", - EventName: "connect", - EventSource: "web", - EventSourceArn: "arn:aws:iam::00000000:role/functionbeat", - Kinesis: events.KinesisRecord{ - Data: []byte("hello world"), - PartitionKey: "abc123", - SequenceNumber: "12345", - KinesisSchemaVersion: "v1", - }, - }, - }, - } -} - -func generateAggregatedKinesisEvent(validRec bool) events.KinesisEvent { - // Heavily based on https://github.com/awslabs/kinesis-aggregation/blob/master/go/deaggregator/deaggregator_test.go - aggRec := &aggRecProto.AggregatedRecord{} - unquotedHeader, err := strconv.Unquote(deaggregator.KplMagicHeader) - if err != nil { - panic(err) - } - aggRecBytes := []byte(unquotedHeader) - partKeyTable := make([]string, 0) - partKey := uint64(0) - hashKey := uint64(0) - r := &aggRecProto.Record{ - ExplicitHashKeyIndex: &hashKey, - Data: []byte("hello world"), - Tags: make([]*aggRecProto.Tag, 0), - } - // This seems to be the only way to trigger the deaggregation module to return an error when needed - if validRec { - r.PartitionKeyIndex = &partKey - } - aggRec.Records = append(aggRec.Records, r) - partKeyTable = append(partKeyTable, "0") - - aggRec.PartitionKeyTable = partKeyTable - data, _ := proto.Marshal(protoimpl.X.ProtoMessageV2Of(aggRec)) - md5Hash := md5.Sum(data) - aggRecBytes = append(aggRecBytes, data...) - aggRecBytes = append(aggRecBytes, md5Hash[:]...) - - return events.KinesisEvent{ - Records: []events.KinesisEventRecord{ - { - AwsRegion: "east-1", - EventID: "1234", - EventName: "connect", - EventSource: "web", - EventSourceArn: "arn:aws:iam::00000000:role/functionbeat", - Kinesis: events.KinesisRecord{ - Data: aggRecBytes, - PartitionKey: "abc123", - SequenceNumber: "12345", - KinesisSchemaVersion: "v1", - }, - }, - }, - } -} - -func testKinesisConfig(t *testing.T) { - tests := map[string]struct { - valid bool - rawConfig map[string]interface{} - expected *KinesisConfig - }{ - "minimal valid configuration": { - valid: true, - rawConfig: map[string]interface{}{ - "name": "mysuperfunctionname", - "description": "mylong description", - "triggers": []map[string]interface{}{ - map[string]interface{}{ - "event_source_arn": "mycustomarn", - }, - }, - }, - }, - "missing event triggers": { - valid: false, - rawConfig: map[string]interface{}{ - "name": "mysuperfunctionname", - "description": "mylong description", - }, - }, - "empty or missing event source arn": { - valid: false, - rawConfig: map[string]interface{}{ - "name": "mysuperfunctionname", - "description": "mylong description", - "triggers": []map[string]interface{}{ - map[string]interface{}{ - "event_source_arn": "", - }, - }, - }, - }, - "test upper bound batch size limit": { - valid: false, - rawConfig: map[string]interface{}{ - "name": "mysuperfunctionname", - "description": "mylong description", - "triggers": []map[string]interface{}{ - map[string]interface{}{ - "event_source_arn": "abc123", - "batch_size": 20000, - }, - }, - }, - }, - "test lower bound batch size limit": { - valid: false, - rawConfig: map[string]interface{}{ - "name": "mysuperfunctionname", - "description": "mylong description", - "triggers": []map[string]interface{}{ - map[string]interface{}{ - "event_source_arn": "abc123", - "batch_size": 10, - }, - }, - }, - }, - "test upper bound parallelization factor limit": { - valid: false, - rawConfig: map[string]interface{}{ - "name": "mysuperfunctionname", - "description": "mylong description", - "triggers": []map[string]interface{}{ - map[string]interface{}{ - "event_source_arn": "abc123", - "parallelization_factor": 13, - }, - }, - }, - }, - "test lower bound parallelization factor limit": { - valid: false, - rawConfig: map[string]interface{}{ - "name": "mysuperfunctionname", - "description": "mylong description", - "triggers": []map[string]interface{}{ - map[string]interface{}{ - "event_source_arn": "abc123", - "parallelization_factor": 0, - }, - }, - }, - }, - "test default values": { - valid: true, - rawConfig: map[string]interface{}{ - "name": "mysuperfunctionname", - "description": "mylongdescription", - "triggers": []map[string]interface{}{ - map[string]interface{}{ - "event_source_arn": "abc123", - }, - }, - }, - expected: &KinesisConfig{ - Name: "mysuperfunctionname", - Description: "mylongdescription", - LambdaConfig: DefaultLambdaConfig, - Triggers: []*KinesisTriggerConfig{ - &KinesisTriggerConfig{ - EventSourceArn: "abc123", - BatchSize: 100, - StartingPosition: trimHorizonPos, - ParallelizationFactor: 1, - }, - }, - }, - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - cfg := conf.MustNewConfigFrom(test.rawConfig) - config := &KinesisConfig{LambdaConfig: DefaultLambdaConfig} - err := cfg.Unpack(config) - if !assert.Equal(t, test.valid, err == nil, fmt.Sprintf("error: %+v", err)) { - return - } - - if test.expected != nil { - assert.Equal(t, test.expected, config) - } - }) - } -} - -func testStartingPosition(t *testing.T) { - // NOTE(ph) when adding support for at_timestamp we also need to make sure the cloudformation - // template send the timestamp. - // doc: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-eventsourcemapping.html - t.Run("AT_TIMESTAMP is not supported yet", func(t *testing.T) { - var s startingPosition - err := s.Unpack("at_timestamp") - assert.Error(t, err) - }) -} diff --git a/x-pack/functionbeat/provider/aws/aws/sqs.go b/x-pack/functionbeat/provider/aws/aws/sqs.go deleted file mode 100644 index adf5f5a16de8..000000000000 --- a/x-pack/functionbeat/provider/aws/aws/sqs.go +++ /dev/null @@ -1,164 +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 aws - -import ( - "context" - "errors" - "sort" - - "github.com/aws/aws-lambda-go/events" - lambdarunner "github.com/aws/aws-lambda-go/lambda" - "github.com/awslabs/goformation/v7/cloudformation" - "github.com/awslabs/goformation/v7/cloudformation/iam" - "github.com/awslabs/goformation/v7/cloudformation/lambda" - - "github.com/elastic/beats/v7/libbeat/feature" - "github.com/elastic/beats/v7/libbeat/publisher/pipeline" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/provider" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/telemetry" - "github.com/elastic/beats/v7/x-pack/functionbeat/provider/aws/aws/transformer" - conf "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/logp" -) - -const batchSize = 10 - -// SQSConfig is the configuration for the SQS event type. -type SQSConfig struct { - Triggers []*SQSTriggerConfig `config:"triggers"` - Description string `config:"description"` - Name string `config:"name" validate:"nonzero,required"` - LambdaConfig *LambdaConfig `config:",inline"` -} - -// SQSTriggerConfig configuration for the current trigger. -type SQSTriggerConfig struct { - EventSourceArn string `config:"event_source_arn"` -} - -// Validate validates the configuration. -func (cfg *SQSConfig) Validate() error { - if len(cfg.Triggers) == 0 { - return errors.New("you need to specify at least one trigger") - } - return nil -} - -// SQS receives events from the web service and forward them to elasticsearch. -type SQS struct { - log *logp.Logger - config *SQSConfig -} - -// NewSQS creates a new function to receives events from a SQS queue. -func NewSQS(provider provider.Provider, cfg *conf.C) (provider.Function, error) { - config := &SQSConfig{LambdaConfig: DefaultLambdaConfig} - if err := cfg.Unpack(config); err != nil { - return nil, err - } - return &SQS{log: logp.NewLogger("sqs"), config: config}, nil -} - -// SQSDetails returns the details of the feature. -func SQSDetails() feature.Details { - return feature.MakeDetails("SQS trigger", "receive events from a SQS queue", feature.Stable) -} - -// Run starts the lambda function and wait for web triggers. -func (s *SQS) Run(_ context.Context, client pipeline.ISyncClient, t telemetry.T) error { - t.AddTriggeredFunction() - - lambdarunner.Start(s.createHandler(client)) - return nil -} - -func (s *SQS) createHandler(client pipeline.ISyncClient) func(request events.SQSEvent) error { - return func(request events.SQSEvent) error { - s.log.Debugf("The handler receives %d events", len(request.Records)) - - events := transformer.SQS(request) - - if err := client.PublishAll(events); err != nil { - s.log.Errorf("Could not publish events to the pipeline, error: %+v", err) - return err - } - client.Wait() - return nil - } -} - -// Name return the name of the lambda function. -func (s *SQS) Name() string { - return "sqs" -} - -// Template returns the cloudformation template for configuring the service with the specified triggers. -func (s *SQS) Template() *cloudformation.Template { - template := cloudformation.NewTemplate() - - prefix := func(suffix string) string { - return NormalizeResourceName("fnb" + s.config.Name + suffix) - } - - for _, trigger := range s.config.Triggers { - resourceName := prefix("SQS") + NormalizeResourceName(trigger.EventSourceArn) - template.Resources[resourceName] = &lambda.EventSourceMapping{ - BatchSize: cloudformation.Int(batchSize), - EventSourceArn: cloudformation.String(trigger.EventSourceArn), - FunctionName: cloudformation.GetAtt(prefix(""), "Arn"), - } - } - return template -} - -// Policies returns a slice of policies to add to the lambda role. -func (s *SQS) Policies() []iam.Role_Policy { - resources := make([]string, len(s.config.Triggers)) - for idx, trigger := range s.config.Triggers { - resources[idx] = trigger.EventSourceArn - } - - // Give us a chance to generate the same document indenpendant of the changes, - // to help with updates. - sort.Strings(resources) - - // SQS Roles permissions: - // - lambda:CreateEventSourceMapping - // - lambda:ListEventSourceMappings - // - lambda:ListFunctions - // - // Lambda Role permission - // - sqs:ChangeMessageVisibility - // - sqs:DeleteMessage - // - sqs:GetQueueAttributes - // - sqs:ReceiveMessage - policies := []iam.Role_Policy{ - iam.Role_Policy{ - PolicyName: cloudformation.Join("-", []string{"fnb", "sqs", s.config.Name}), - PolicyDocument: map[string]interface{}{ - "Statement": []map[string]interface{}{ - map[string]interface{}{ - "Action": []string{ - "sqs:ChangeMessageVisibility", - "sqs:DeleteMessage", - "sqs:GetQueueAttributes", - "sqs:ReceiveMessage", - }, - "Effect": "Allow", - "Resource": resources, - }, - }, - }, - }, - } - - return policies -} - -// LambdaConfig returns the configuration to use when creating the lambda. -func (s *SQS) LambdaConfig() *LambdaConfig { - return s.config.LambdaConfig -} diff --git a/x-pack/functionbeat/provider/aws/aws/sqs_test.go b/x-pack/functionbeat/provider/aws/aws/sqs_test.go deleted file mode 100644 index 88a45cb97930..000000000000 --- a/x-pack/functionbeat/provider/aws/aws/sqs_test.go +++ /dev/null @@ -1,67 +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 aws - -import ( - "errors" - "testing" - - "github.com/aws/aws-lambda-go/events" - "github.com/stretchr/testify/assert" - - "github.com/elastic/beats/v7/x-pack/functionbeat/function/provider" - conf "github.com/elastic/elastic-agent-libs/config" -) - -func TestSQS(t *testing.T) { - cfg := conf.MustNewConfigFrom(map[string]interface{}{ - "name": "foobar", - "triggers": []map[string]interface{}{ - map[string]interface{}{ - "event_source_arn": "abc1234", - }, - }, - }) - - t.Run("when publish is succesful", func(t *testing.T) { - client := &arrayBackedClient{} - s, err := NewSQS(&provider.DefaultProvider{}, cfg) - if !assert.NoError(t, err) { - return - } - - c, _ := s.(*SQS) - handler := c.createHandler(client) - err = handler(generateSQSEvent()) - assert.NoError(t, err) - }) - - t.Run("when publish is not succesful", func(t *testing.T) { - e := errors.New("something bad") - client := &arrayBackedClient{err: e} - - s, err := NewSQS(&provider.DefaultProvider{}, cfg) - if !assert.NoError(t, err) { - return - } - - c, _ := s.(*SQS) - handler := c.createHandler(client) - err = handler(generateSQSEvent()) - assert.Equal(t, e, err) - }) -} - -func generateSQSEvent() events.SQSEvent { - return events.SQSEvent{ - Records: []events.SQSMessage{ - events.SQSMessage{ - MessageId: "1234", - ReceiptHandle: "12345", - Body: "hello world", - }, - }, - } -} diff --git a/x-pack/functionbeat/provider/aws/aws/transformer/transformer.go b/x-pack/functionbeat/provider/aws/aws/transformer/transformer.go deleted file mode 100644 index 3bf464317a0a..000000000000 --- a/x-pack/functionbeat/provider/aws/aws/transformer/transformer.go +++ /dev/null @@ -1,234 +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 transformer - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "encoding/json" - "errors" - "io" - "time" - - "github.com/aws/aws-lambda-go/events" - "github.com/aws/aws-sdk-go-v2/service/kinesis/types" - "github.com/awslabs/kinesis-aggregation/go/v2/deaggregator" - - "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/elastic-agent-libs/mapstr" -) - -// Centralize anything related to ECS into a common file. -// TODO: Look at the fields to align them with ECS. -// TODO: how to keep the fields in sync with AWS? -// TODO: api gateway proxy a lot more information is available. - -// CloudwatchLogs takes an CloudwatchLogsData and transform it into a beat event. -func CloudwatchLogs(request events.CloudwatchLogsData) []beat.Event { - beatEvents := make([]beat.Event, len(request.LogEvents)) - - for idx, logEvent := range request.LogEvents { - beatEvents[idx] = beat.Event{ - Timestamp: time.Unix(0, logEvent.Timestamp*1000000), - Fields: mapstr.M{ - "event": mapstr.M{ - "kind": "event", - }, - "cloud": mapstr.M{ - "provider": "aws", - }, - "message": logEvent.Message, - "id": logEvent.ID, - "owner": request.Owner, - "log_stream": request.LogStream, - "log_group": request.LogGroup, - "message_type": request.MessageType, - "subscription_filters": request.SubscriptionFilters, - }, - } - } - - return beatEvents -} - -// APIGatewayProxyRequest takes a web request on the api gateway proxy and transform it into a beat event. -func APIGatewayProxyRequest(request events.APIGatewayProxyRequest) beat.Event { - return beat.Event{ - Timestamp: time.Now(), - Fields: mapstr.M{ - "event": mapstr.M{ - "kind": "event", - "category": []string{"network"}, - "type": []string{"connection", "protocol"}, - }, - "cloud": mapstr.M{ - "provider": "aws", - "account.id": request.RequestContext.AccountID, - }, - "network": mapstr.M{ - "transport": "tcp", - "protocol": "http", - }, - "resource": request.Resource, - "path": request.Path, - "method": request.HTTPMethod, - "headers": request.Headers, // TODO: ECS map[string] - "query_string": request.QueryStringParameters, // TODO: map[string], might conflict with ECS - "path_parameters": request.PathParameters, - "body": request.Body, // TODO: could be JSON, json processor? could be used by other functions. - "is_base64_encoded": request.IsBase64Encoded, - }, - } -} - -// KinesisEvent takes a kinesis event and create multiples beat events. -// DOCS: https://docs.aws.amazon.com/lambda/latest/dg/with-kinesis.html -func KinesisEvent(request events.KinesisEvent) ([]beat.Event, error) { - var beatEvents []beat.Event - for _, record := range request.Records { - kr := types.Record{ - ApproximateArrivalTimestamp: &record.Kinesis.ApproximateArrivalTimestamp.Time, - Data: record.Kinesis.Data, - EncryptionType: types.EncryptionType(record.Kinesis.EncryptionType), - PartitionKey: &record.Kinesis.PartitionKey, - SequenceNumber: &record.Kinesis.SequenceNumber, - } - deaggRecords, err := deaggregator.DeaggregateRecords([]types.Record{kr}) - if err != nil { - return nil, err - } - - for _, deaggRecord := range deaggRecords { - beatEvents = append(beatEvents, beat.Event{ - Timestamp: *deaggRecord.ApproximateArrivalTimestamp, - Fields: mapstr.M{ - "event": mapstr.M{ - "kind": "event", - }, - "cloud": mapstr.M{ - "provider": "aws", - "region": record.AwsRegion, - }, - "event_id": record.EventID, - "event_name": record.EventName, - "event_source": record.EventSource, - "event_source_arn": record.EventSourceArn, - "event_version": record.EventVersion, - "aws_region": record.AwsRegion, - "message": string(deaggRecord.Data), - "kinesis_partition_key": *deaggRecord.PartitionKey, - "kinesis_schema_version": record.Kinesis.KinesisSchemaVersion, - "kinesis_sequence_number": *deaggRecord.SequenceNumber, - "kinesis_encryption_type": deaggRecord.EncryptionType, - }, - }) - } - } - return beatEvents, nil -} - -// CloudwatchKinesisEvent takes a Kinesis event containing Cloudwatch logs and creates events for all -// Cloudwatch logs. -func CloudwatchKinesisEvent(request events.KinesisEvent, base64Encoded, compressed bool) ([]beat.Event, error) { - var evts []beat.Event - for _, record := range request.Records { - envelopeFields := mapstr.M{ - "event": mapstr.M{ - "kind": "event", - }, - "cloud": mapstr.M{ - "provider": "aws", - "region": record.AwsRegion, - }, - "event_id": record.EventID, - "event_name": record.EventName, - "event_source": record.EventSource, - "event_source_arn": record.EventSourceArn, - "event_version": record.EventVersion, - "aws_region": record.AwsRegion, - "kinesis_partition_key": record.Kinesis.PartitionKey, - "kinesis_schema_version": record.Kinesis.KinesisSchemaVersion, - "kinesis_sequence_number": record.Kinesis.SequenceNumber, - "kinesis_encryption_type": record.Kinesis.EncryptionType, - } - - kinesisData := record.Kinesis.Data - if base64Encoded { - var err error - kinesisData, err = base64.StdEncoding.DecodeString(string(kinesisData)) - if err != nil { - return nil, err - } - } - - if compressed { - inBuf := bytes.NewBuffer(record.Kinesis.Data) - r, err := gzip.NewReader(inBuf) - if err != nil { - return nil, err - } - - var outBuf bytes.Buffer - for { - _, err := io.CopyN(&outBuf, r, 1024) - if err != nil { - if errors.Is(err, io.EOF) { - break - } - _ = r.Close() - return nil, err - } - } - - err = r.Close() - if err != nil { - return nil, err - } - kinesisData = outBuf.Bytes() - } - - var cloudwatchEvents events.CloudwatchLogsData - err := json.Unmarshal(kinesisData, &cloudwatchEvents) - if err != nil { - return nil, err - } - - cwEvts := CloudwatchLogs(cloudwatchEvents) - for _, cwe := range cwEvts { - cwe.Fields.DeepUpdate(envelopeFields) - evts = append(evts, cwe) - } - } - return evts, nil -} - -// SQS takes a SQS event and create multiples beat events. -func SQS(request events.SQSEvent) []beat.Event { - beatEvents := make([]beat.Event, len(request.Records)) - for idx, record := range request.Records { - beatEvents[idx] = beat.Event{ - Timestamp: time.Now(), - Fields: mapstr.M{ - "event": mapstr.M{ - "kind": "event", - }, - "cloud": mapstr.M{ - "provider": "aws", - "region": record.AWSRegion, - }, - "message_id": record.MessageId, - "receipt_handle": record.ReceiptHandle, - "message": record.Body, - "attributes": record.Attributes, - "event_source": record.EventSource, - "event_source_arn": record.EventSourceARN, - "aws_region": record.AWSRegion, - }, - // TODO: SQS message attributes missing, need to check doc - } - } - return beatEvents -} diff --git a/x-pack/functionbeat/provider/aws/aws/transformer/transformer_test.go b/x-pack/functionbeat/provider/aws/aws/transformer/transformer_test.go deleted file mode 100644 index ae0dcb12eee4..000000000000 --- a/x-pack/functionbeat/provider/aws/aws/transformer/transformer_test.go +++ /dev/null @@ -1,403 +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 transformer - -import ( - "crypto/md5" - "encoding/base64" - "fmt" - "math/rand" - "strconv" - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/service/kinesis/types" - "google.golang.org/protobuf/runtime/protoimpl" - - "github.com/aws/aws-lambda-go/events" - "github.com/awslabs/kinesis-aggregation/go/v2/deaggregator" - aggRecProto "github.com/awslabs/kinesis-aggregation/go/v2/records" - "github.com/stretchr/testify/assert" - "google.golang.org/protobuf/proto" - - "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/elastic-agent-libs/mapstr" -) - -func TestCloudwatch(t *testing.T) { - logsData := events.CloudwatchLogsData{ - Owner: "me", - LogGroup: "my-group", - LogStream: "stream", - SubscriptionFilters: []string{"MyFilter"}, - MessageType: "DATA_MESSAGE", - LogEvents: []events.CloudwatchLogsLogEvent{ - { - ID: "1234567890123456789", - Timestamp: 1566908691193, - Message: "my interesting message", - }, - }, - } - - events := CloudwatchLogs(logsData) - assert.Equal(t, 1, len(events)) - - expectedTime, err := time.ParseInLocation(time.RFC3339, "2019-08-27T12:24:51.193+00:00", time.UTC) - assert.NoError(t, err) - - expectedEvent := beat.Event{ - Timestamp: expectedTime, - Fields: mapstr.M{ - "event": mapstr.M{ - "kind": "event", - }, - "cloud": mapstr.M{ - "provider": "aws", - }, - "message": "my interesting message", - "id": "1234567890123456789", - "owner": "me", - "log_stream": "stream", - "log_group": "my-group", - "message_type": "DATA_MESSAGE", - "subscription_filters": []string{"MyFilter"}, - }, - } - - assert.Equal(t, expectedEvent.Fields, events[0].Fields) - assert.Equal(t, expectedEvent.Timestamp, events[0].Timestamp.UTC()) -} - -func TestKinesis(t *testing.T) { - t.Run("when kinesis event is successful", func(t *testing.T) { - request := events.KinesisEvent{ - Records: []events.KinesisEventRecord{ - events.KinesisEventRecord{ - AwsRegion: "us-east-1", - EventID: "1234", - EventName: "connect", - EventSource: "web", - EventVersion: "1.0", - EventSourceArn: "arn:aws:iam::00000000:role/functionbeat", - Kinesis: events.KinesisRecord{ - Data: []byte("hello world"), - PartitionKey: "abc123", - SequenceNumber: "12345", - KinesisSchemaVersion: "1.0", - EncryptionType: "test", - }, - }, - }, - } - - events, err := KinesisEvent(request) - assert.NoError(t, err) - assert.Equal(t, 1, len(events)) - - fields := mapstr.M{ - "cloud": mapstr.M{ - "provider": "aws", - "region": "us-east-1", - }, - "event": mapstr.M{ - "kind": "event", - }, - "event_id": "1234", - "event_name": "connect", - "event_source": "web", - "event_source_arn": "arn:aws:iam::00000000:role/functionbeat", - "event_version": "1.0", - "aws_region": "us-east-1", - "message": "hello world", - "kinesis_partition_key": "abc123", - "kinesis_schema_version": "1.0", - "kinesis_sequence_number": "12345", - "kinesis_encryption_type": types.EncryptionType("test"), - } - - assert.Equal(t, fields, events[0].Fields) - }) - - t.Run("when kinesis event with agg is successful", func(t *testing.T) { - rand.Seed(time.Now().UnixNano()) - min, max := 2, 20 - numRecords := rand.Intn(max-min) + min - aggRecBytes := generateKinesisAggregateRecord(numRecords, true) - - request := events.KinesisEvent{ - Records: []events.KinesisEventRecord{ - events.KinesisEventRecord{ - AwsRegion: "us-east-1", - EventID: "1234", - EventName: "connect", - EventSource: "web", - EventVersion: "1.0", - EventSourceArn: "arn:aws:iam::00000000:role/functionbeat", - Kinesis: events.KinesisRecord{ - Data: aggRecBytes, - PartitionKey: "ignored", - SequenceNumber: "12345", - KinesisSchemaVersion: "1.0", - EncryptionType: "test", - }, - }, - }, - } - - events, err := KinesisEvent(request) - assert.NoError(t, err) - assert.Equal(t, numRecords, len(events)) - - envelopeFields := mapstr.M{ - "cloud": mapstr.M{ - "provider": "aws", - "region": "us-east-1", - }, - "event": mapstr.M{ - "kind": "event", - }, - "event_id": "1234", - "event_name": "connect", - "event_source": "web", - "event_source_arn": "arn:aws:iam::00000000:role/functionbeat", - "event_version": "1.0", - "aws_region": "us-east-1", - "kinesis_schema_version": "1.0", - "kinesis_sequence_number": "12345", - "kinesis_encryption_type": types.EncryptionType("test"), - } - - var expectedInnerFields []mapstr.M - for i := 0; i < numRecords; i++ { - expectedInnerFields = append(expectedInnerFields, mapstr.M{ - "message": fmt.Sprintf("%s %d", "hello world", i), - "kinesis_partition_key": fmt.Sprintf("%s %d", "partKey", i), - }) - } - - for i, expectedFields := range expectedInnerFields { - expectedFields.Update(envelopeFields) - assert.Equal(t, expectedFields, events[i].Fields) - } - }) - - t.Run("when kinesis event with agg is not successful", func(t *testing.T) { - aggRecBytes := generateKinesisAggregateRecord(2, false) - - request := events.KinesisEvent{ - Records: []events.KinesisEventRecord{ - events.KinesisEventRecord{ - AwsRegion: "us-east-1", - EventID: "1234", - EventName: "connect", - EventSource: "web", - EventVersion: "1.0", - EventSourceArn: "arn:aws:iam::00000000:role/functionbeat", - Kinesis: events.KinesisRecord{ - Data: aggRecBytes, - PartitionKey: "abc123", - SequenceNumber: "12345", - KinesisSchemaVersion: "1.0", - EncryptionType: "test", - }, - }, - }, - } - - events, err := KinesisEvent(request) - assert.Error(t, err) - assert.Nil(t, events) - }) - - t.Run("when kinesis event with real example agg payload is successful", func(t *testing.T) { - rand.Seed(time.Now().UnixNano()) - numRecords := 10 - aggRecBytes, err := base64.StdEncoding.DecodeString("84mawgoIejJKSjl6dFgaEwgAGg97ImtleSI6InZhbHVlIn0aEwgAGg9" + - "7ImtleSI6InZhbHVlIn0aEwgAGg97ImtleSI6InZhbHVlIn0aEwgAGg97ImtleSI6InZhbHVlIn0aEwgAGg97ImtleSI6InZhbHVlIn" + - "0aEwgAGg97ImtleSI6InZhbHVlIn0aEwgAGg97ImtleSI6InZhbHVlIn0aEwgAGg97ImtleSI6InZhbHVlIn0aEwgAGg97ImtleSI6I" + - "nZhbHVlIn0aEwgAGg97ImtleSI6InZhbHVlIn3xj2DFMGZ0aNQC7aexsnkU") - assert.NoError(t, err) - - request := events.KinesisEvent{ - Records: []events.KinesisEventRecord{ - events.KinesisEventRecord{ - AwsRegion: "us-east-1", - EventID: "1234", - EventName: "connect", - EventSource: "web", - EventVersion: "1.0", - EventSourceArn: "arn:aws:iam::00000000:role/functionbeat", - Kinesis: events.KinesisRecord{ - Data: aggRecBytes, - PartitionKey: "ignored", - SequenceNumber: "12345", - KinesisSchemaVersion: "1.0", - EncryptionType: "test", - }, - }, - }, - } - - events, err := KinesisEvent(request) - assert.NoError(t, err) - assert.Equal(t, numRecords, len(events)) - - envelopeFields := mapstr.M{ - "cloud": mapstr.M{ - "provider": "aws", - "region": "us-east-1", - }, - "event": mapstr.M{ - "kind": "event", - }, - "event_id": "1234", - "event_name": "connect", - "event_source": "web", - "event_source_arn": "arn:aws:iam::00000000:role/functionbeat", - "event_version": "1.0", - "aws_region": "us-east-1", - "kinesis_schema_version": "1.0", - "kinesis_sequence_number": "12345", - "kinesis_encryption_type": types.EncryptionType("test"), - "kinesis_partition_key": "z2JJ9ztX", - "message": `{"key":"value"}`, - } - - for i := 0; i < numRecords; i++ { - assert.Equal(t, envelopeFields, events[i].Fields) - } - }) -} - -func TestCloudwatchKinesis(t *testing.T) { - request := events.KinesisEvent{ - Records: []events.KinesisEventRecord{ - events.KinesisEventRecord{ - AwsRegion: "us-east-1", - EventID: "1234", - EventName: "connect", - EventSource: "web", - EventVersion: "1.0", - EventSourceArn: "arn:aws:iam::00000000:role/functionbeat", - Kinesis: events.KinesisRecord{ - Data: []byte(`eyJtZXNzYWdlVHlwZSI6IkRBVEFfTUVTU0FHRSIsIm93bmVyIjoiMDc5NzA5NzYxMTUyIiwibG9n -R3JvdXAiOiJ0ZXN0ZW0iLCJsb2dTdHJlYW0iOiJmb2x5b21hbnkiLCJzdWJzY3JpcHRpb25GaWx0 -ZXJzIjpbIk1pbmRlbiJdLCJsb2dFdmVudHMiOlt7ImlkIjoiMzQ5MzM1ODk4NzM5NzIwNDAzMDgy -ODAzMDIzMTg1MjMxODU5NjA1NTQxODkxNjg4NzMyNDI2MjQiLCJ0aW1lc3RhbXAiOjE1NjY0NzYz -NDcwMDAsIm1lc3NhZ2UiOiJUZXN0IGV2ZW50IDMifSx7ImlkIjoiMzQ5MzM1ODk4NzM5OTQzNDEw -NTM0Nzg4MzI5NDE2NjQ3MjE2Nzg4MjY4Mzc1MzAzNzkyMjMwNDEiLCJ0aW1lc3RhbXAiOjE1NjY0 -NzYzNDcwMDEsIm1lc3NhZ2UiOiJUZXN0IGV2ZW50IDQifSx7ImlkIjoiMzQ5MzM1ODk4NzQwMTY2 -NDE3OTg2NzczNjM1NjQ4MDYyNTczOTcwOTk0ODU4OTE4ODUyMDM0NTgiLCJ0aW1lc3RhbXAiOjE1 -NjY0NzYzNDcwMDIsIm1lc3NhZ2UiOiJUaGlzIG1lc3NhZ2UgYWxzbyBjb250YWlucyBhbiBFcnJv -ciJ9XX0=`), - PartitionKey: "abc123", - SequenceNumber: "12345", - KinesisSchemaVersion: "1.0", - EncryptionType: "test", - }, - }, - }, - } - - events, err := CloudwatchKinesisEvent(request, true, false) - assert.NoError(t, err) - assert.Equal(t, 3, len(events)) - - envelopeFields := mapstr.M{ - "cloud": mapstr.M{ - "provider": "aws", - "region": "us-east-1", - }, - "event": mapstr.M{ - "kind": "event", - }, - "event_id": "1234", - "event_name": "connect", - "event_source": "web", - "event_source_arn": "arn:aws:iam::00000000:role/functionbeat", - "event_version": "1.0", - "aws_region": "us-east-1", - "kinesis_partition_key": "abc123", - "kinesis_schema_version": "1.0", - "kinesis_sequence_number": "12345", - "kinesis_encryption_type": "test", - } - - expectedInnerFields := []mapstr.M{ - mapstr.M{ - "id": "34933589873972040308280302318523185960554189168873242624", - "log_group": "testem", - "log_stream": "folyomany", - "owner": "079709761152", - "message": "Test event 3", - "message_type": "DATA_MESSAGE", - "subscription_filters": []string{ - "Minden", - }, - }, - mapstr.M{ - "id": "34933589873994341053478832941664721678826837530379223041", - "log_group": "testem", - "log_stream": "folyomany", - "owner": "079709761152", - "message": "Test event 4", - "message_type": "DATA_MESSAGE", - "subscription_filters": []string{ - "Minden", - }, - }, - mapstr.M{ - "id": "34933589874016641798677363564806257397099485891885203458", - "log_group": "testem", - "log_stream": "folyomany", - "owner": "079709761152", - "message": "This message also contains an Error", - "message_type": "DATA_MESSAGE", - "subscription_filters": []string{ - "Minden", - }, - }, - } - - for i, expectedFields := range expectedInnerFields { - expectedFields.Update(envelopeFields) - assert.Equal(t, expectedFields, events[i].Fields) - } -} - -func generateKinesisAggregateRecord(numRecords int, valid bool) []byte { - // Heavily based on https://github.com/awslabs/kinesis-aggregation/blob/master/go/deaggregator/deaggregator_test.go - aggRec := &aggRecProto.AggregatedRecord{} - unquotedHeader, err := strconv.Unquote(deaggregator.KplMagicHeader) - if err != nil { - panic(err) - } - aggRecBytes := []byte(unquotedHeader) - partKeyTable := make([]string, 0) - for i := 0; i < numRecords; i++ { - partKey := uint64(i) - hashKey := uint64(i) - r := &aggRecProto.Record{ - ExplicitHashKeyIndex: &hashKey, - Data: []byte(fmt.Sprintf("%s %d", "hello world", i)), - Tags: make([]*aggRecProto.Tag, 0), - } - // This seems to be the only way to trigger the deaggregation module to return an error when needed - if valid { - r.PartitionKeyIndex = &partKey - } - aggRec.Records = append(aggRec.Records, r) - partKeyTable = append(partKeyTable, fmt.Sprintf("%s %d", "partKey", i)) - } - - aggRec.PartitionKeyTable = partKeyTable - data, _ := proto.Marshal(protoimpl.X.ProtoMessageV2Of(aggRec)) - md5Hash := md5.Sum(data) - aggRecBytes = append(aggRecBytes, data...) - aggRecBytes = append(aggRecBytes, md5Hash[:]...) - - return aggRecBytes -} diff --git a/x-pack/functionbeat/provider/aws/cmd/root.go b/x-pack/functionbeat/provider/aws/cmd/root.go deleted file mode 100644 index c8e7ba17d62b..000000000000 --- a/x-pack/functionbeat/provider/aws/cmd/root.go +++ /dev/null @@ -1,29 +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 cmd - -import ( - "flag" - - "github.com/elastic/beats/v7/libbeat/cfgfile" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/beater" - funcmd "github.com/elastic/beats/v7/x-pack/functionbeat/function/cmd" -) - -// Name of this beat -var Name = "functionbeat" - -// RootCmd to handle functionbeat -var RootCmd *funcmd.FunctionCmd - -func init() { - RootCmd = funcmd.NewFunctionCmd(Name, beater.New) - RootCmd.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("d")) - cfgfile.AddAllowedBackwardsCompatibleFlag("d") - RootCmd.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("v")) - cfgfile.AddAllowedBackwardsCompatibleFlag("v") - RootCmd.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("e")) - cfgfile.AddAllowedBackwardsCompatibleFlag("e") -} diff --git a/x-pack/functionbeat/provider/aws/include/feature.go b/x-pack/functionbeat/provider/aws/include/feature.go deleted file mode 100644 index 990134484393..000000000000 --- a/x-pack/functionbeat/provider/aws/include/feature.go +++ /dev/null @@ -1,37 +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 include - -import ( - "github.com/elastic/beats/v7/libbeat/feature" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/provider" - "github.com/elastic/beats/v7/x-pack/functionbeat/provider/aws/aws" -) - -// Bundle exposes the trigger supported by the AWS provider. -var features = provider.Builder( - "aws", - provider.NewDefaultProvider("aws", provider.NewNullCli, provider.NewNullTemplateBuilder), - feature.MakeDetails("AWS Lambda", "listen to events on AWS lambda", feature.Stable), -).AddFunction("cloudwatch_logs", - aws.NewCloudwatchLogs, - aws.CloudwatchLogsDetails(), -).AddFunction("api_gateway_proxy", - aws.NewAPIGatewayProxy, - aws.APIGatewayProxyDetails(), -).AddFunction("kinesis", - aws.NewKinesis, - aws.KinesisDetails(), -).AddFunction("sqs", - aws.NewSQS, - aws.SQSDetails(), -).AddFunction("cloudwatch_logs_kinesis", - aws.NewCloudwatchKinesis, - aws.CloudwatchKinesisDetails(), -).Features() - -func init() { - feature.MustRegister(features...) -} diff --git a/x-pack/functionbeat/provider/aws/main.go b/x-pack/functionbeat/provider/aws/main.go deleted file mode 100644 index 9ee80bb48942..000000000000 --- a/x-pack/functionbeat/provider/aws/main.go +++ /dev/null @@ -1,18 +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 main - -import ( - "os" - - "github.com/elastic/beats/v7/x-pack/functionbeat/provider/aws/cmd" - _ "github.com/elastic/beats/v7/x-pack/functionbeat/provider/aws/include" -) - -func main() { - if err := cmd.RootCmd.Execute(); err != nil { - os.Exit(1) - } -} diff --git a/x-pack/functionbeat/provider/aws/main_test.go b/x-pack/functionbeat/provider/aws/main_test.go deleted file mode 100644 index f180fd28275d..000000000000 --- a/x-pack/functionbeat/provider/aws/main_test.go +++ /dev/null @@ -1,35 +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 main - -// This file is mandatory as otherwise the functionbeat.test binary is not generated correctly. - -import ( - "flag" - "testing" - - "github.com/elastic/beats/v7/libbeat/cfgfile" - "github.com/elastic/beats/v7/x-pack/functionbeat/provider/aws/cmd" -) - -var systemTest *bool - -func init() { - testing.Init() - systemTest = flag.Bool("systemTest", false, "Set to true when running system tests") - - cmd.RootCmd.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("systemTest")) - cfgfile.AddAllowedBackwardsCompatibleFlag("systemTest") - cmd.RootCmd.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("test.coverprofile")) - cfgfile.AddAllowedBackwardsCompatibleFlag("test.coverprofile") -} - -// Test started when the test binary is started. Only calls main. -func TestSystem(t *testing.T) { - cfgfile.ConvertFlagsForBackwardsCompatibility() - if *systemTest { - main() - } -} diff --git a/x-pack/functionbeat/provider/local/cmd/root.go b/x-pack/functionbeat/provider/local/cmd/root.go deleted file mode 100644 index 11307a141b19..000000000000 --- a/x-pack/functionbeat/provider/local/cmd/root.go +++ /dev/null @@ -1,20 +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 cmd - -import ( - funcmd "github.com/elastic/beats/v7/x-pack/functionbeat/function/cmd" - "github.com/elastic/beats/v7/x-pack/functionbeat/manager/beater" -) - -// Name of this beat -var Name = "functionbeat" - -// RootCmd to handle functionbeat -var RootCmd *funcmd.FunctionCmd - -func init() { - RootCmd = funcmd.NewFunctionCmd(Name, beater.New) -} diff --git a/x-pack/functionbeat/provider/local/local/local.go b/x-pack/functionbeat/provider/local/local/local.go deleted file mode 100644 index 76edf380846c..000000000000 --- a/x-pack/functionbeat/provider/local/local/local.go +++ /dev/null @@ -1,103 +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 local - -import ( - "bufio" - "context" - "os" - "time" - - "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/feature" - "github.com/elastic/beats/v7/libbeat/publisher/pipeline" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/provider" - "github.com/elastic/beats/v7/x-pack/functionbeat/function/telemetry" - conf "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/mapstr" -) - -const stdinName = "stdin" - -// Features exposes the local provider and the STDIN function. -var Features = provider.Builder( - "local", - provider.NewDefaultProvider("local", provider.NewNullCli, provider.NewNullTemplateBuilder), - feature.MakeDetails("local events", "allows to trigger events locally.", feature.Experimental), -).AddFunction( - stdinName, - NewStdinFunction, - feature.MakeDetails(stdinName, "read events from stdin", feature.Experimental), -).Features() - -// StdinFunction reads events from STIN and terminates when stdin is completed. -type StdinFunction struct{} - -// NewStdinFunction creates a new StdinFunction -func NewStdinFunction( - provider provider.Provider, - functionConfig *conf.C, -) (provider.Function, error) { - return &StdinFunction{}, nil -} - -// Run reads events from the STDIN and send them to the publisher pipeline, will stop reading by -// either by an external signal to stop or by reaching EOF. When EOF is reached functionbeat will shutdown. -func (s *StdinFunction) Run(ctx context.Context, client pipeline.ISyncClient, _ telemetry.T) error { - errChan := make(chan error) - defer close(errChan) - lineChan := make(chan string) - defer close(lineChan) - - // Make the os.Stdin interruptable, the shutdown cleanup will unblock the os.Stdin and the goroutine. - go func(ctx context.Context, lineChan chan string, errChan chan error) { - buf := bufio.NewReader(os.Stdin) - scanner := bufio.NewScanner(buf) - scanner.Split(bufio.ScanLines) - - for scanner.Scan() { - if err := scanner.Err(); err != nil { - errChan <- err - return - } - - select { - case <-ctx.Done(): - return - case lineChan <- scanner.Text(): - } - } - }(ctx, lineChan, errChan) - - for { - select { - case <-ctx.Done(): - return os.Stdin.Close() - case err := <-errChan: - return err - case line := <-lineChan: - event := s.newEvent(line) - err := client.Publish(event) - if err != nil { - return err - } - } - } -} - -func (s *StdinFunction) newEvent(line string) beat.Event { - event := beat.Event{ - Timestamp: time.Now(), - Fields: mapstr.M{ - "message": line, - }, - } - return event -} - -// Name returns the name of the stdin function. -func (s *StdinFunction) Name() string { - return stdinName -} diff --git a/x-pack/functionbeat/provider/local/main.go b/x-pack/functionbeat/provider/local/main.go deleted file mode 100644 index 35284d4a716f..000000000000 --- a/x-pack/functionbeat/provider/local/main.go +++ /dev/null @@ -1,18 +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 main - -import ( - "os" - - "github.com/elastic/beats/v7/x-pack/functionbeat/provider/local/cmd" - _ "github.com/elastic/beats/v7/x-pack/functionbeat/provider/local/include" // imports features -) - -func main() { - if err := cmd.RootCmd.Execute(); err != nil { - os.Exit(1) - } -} diff --git a/x-pack/functionbeat/provider/local/main_test.go b/x-pack/functionbeat/provider/local/main_test.go deleted file mode 100644 index 7c617b300a65..000000000000 --- a/x-pack/functionbeat/provider/local/main_test.go +++ /dev/null @@ -1,35 +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 main - -// This file is mandatory as otherwise the functionbeat.test binary is not generated correctly. - -import ( - "flag" - "testing" - - "github.com/elastic/beats/v7/libbeat/cfgfile" - "github.com/elastic/beats/v7/x-pack/functionbeat/provider/local/cmd" -) - -var systemTest *bool - -func init() { - testing.Init() - systemTest = flag.Bool("systemTest", false, "Set to true when running system tests") - - cmd.RootCmd.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("systemTest")) - cfgfile.AddAllowedBackwardsCompatibleFlag("systemTest") - cmd.RootCmd.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("test.coverprofile")) - cfgfile.AddAllowedBackwardsCompatibleFlag("test.coverprofile") -} - -// Test started when the test binary is started. Only calls main. -func TestSystem(t *testing.T) { - cfgfile.ConvertFlagsForBackwardsCompatibility() - if *systemTest { - main() - } -} diff --git a/x-pack/functionbeat/scripts/mage/config.go b/x-pack/functionbeat/scripts/mage/config.go deleted file mode 100644 index 1d3e773d602f..000000000000 --- a/x-pack/functionbeat/scripts/mage/config.go +++ /dev/null @@ -1,23 +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 mage - -import ( - devtools "github.com/elastic/beats/v7/dev-tools/mage" -) - -// XPackConfigFileParams returns the configuration of sample and reference configuration data. -func XPackConfigFileParams() devtools.ConfigFileParams { - p := devtools.DefaultConfigFileParams() - p.Templates = append(p.Templates, "_meta/config/*.tmpl") - p.ExtraVars = map[string]interface{}{ - "ExcludeConsole": false, - "ExcludeFileOutput": true, - "ExcludeKafka": true, - "ExcludeRedis": true, - "UseDockerMetadataProcessor": false, - } - return p -} diff --git a/x-pack/functionbeat/scripts/mage/providers.go b/x-pack/functionbeat/scripts/mage/providers.go deleted file mode 100644 index d77c1da548df..000000000000 --- a/x-pack/functionbeat/scripts/mage/providers.go +++ /dev/null @@ -1,55 +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 mage - -import ( - "fmt" - "os" - "strings" -) - -var ( - availableProviders = []ProviderDetails{ - {Name: "aws", Buildable: true, GOOS: "linux", GOARCH: "amd64"}, - } -) - -// ProviderDetails stores information about the available cloud providers. -type ProviderDetails struct { - Name string - Buildable bool - GOOS string - GOARCH string -} - -// SelectedProviders is the list of selected providers -// Can be configured by setting PROVIDERS enviroment variable. -func SelectedProviders() ([]ProviderDetails, error) { - providers := os.Getenv("PROVIDERS") - if len(providers) == 0 { - return availableProviders, nil - } - - names := strings.Split(providers, ",") - providerDetails := make([]ProviderDetails, len(names)) - for i, name := range names { - p, err := findProviderDetails(name) - if err != nil { - return nil, err - } - providerDetails[i] = p - } - return providerDetails, nil -} - -func findProviderDetails(name string) (ProviderDetails, error) { - for _, p := range availableProviders { - if p.Name == name { - return p, nil - } - } - - return ProviderDetails{}, fmt.Errorf("no such provider") -} diff --git a/x-pack/functionbeat/scripts/mage/update.go b/x-pack/functionbeat/scripts/mage/update.go deleted file mode 100644 index 468bdafbe0fd..000000000000 --- a/x-pack/functionbeat/scripts/mage/update.go +++ /dev/null @@ -1,48 +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 mage - -import ( - "github.com/magefile/mage/mg" - - devtools "github.com/elastic/beats/v7/dev-tools/mage" -) - -// Update target namespace. -type Update mg.Namespace - -// Aliases stores aliases for the targets. -var Aliases = map[string]interface{}{ - "update": Update.All, -} - -// All updates all generated content. -func (Update) All() { - mg.Deps(Update.Fields, Update.IncludeFields, Update.Config, Update.FieldDocs) -} - -// Config generates both the short and reference configs. -func (Update) Config() error { - return devtools.Config(devtools.ShortConfigType|devtools.ReferenceConfigType, XPackConfigFileParams(), ".") -} - -// Fields generates a fields.yml for the Beat. -func (Update) Fields() error { - return devtools.GenerateFieldsYAML() -} - -// FieldDocs collects all fields by provider and generates documentation for them. -func (Update) FieldDocs() error { - mg.Deps(Update.Fields) - - return devtools.Docs.FieldDocs("fields.yml") -} - -// IncludeFields generates include/fields.go by provider. -func (Update) IncludeFields() error { - mg.Deps(Update.Fields) - - return devtools.GenerateAllInOneFieldsGo() -} diff --git a/x-pack/functionbeat/tests/system/config/functionbeat.yml.j2 b/x-pack/functionbeat/tests/system/config/functionbeat.yml.j2 deleted file mode 100644 index 64a69bceab97..000000000000 --- a/x-pack/functionbeat/tests/system/config/functionbeat.yml.j2 +++ /dev/null @@ -1,101 +0,0 @@ -################### Beat Configuration ######################### -{% if local %} -functionbeat.provider.local: - functions: - - type: stdin - enabled: true -{% endif %} - -{% if cloudwatch %} -functionbeat.provider.aws.endpoint: {{ cloudwatch.endpoint | default("s3.amazonaws.com") }} -functionbeat.provider.aws.deploy_bucket: {{ cloudwatch.bucket | default("functionbeat-deploy") }} -functionbeat.provider.aws.functions: - - name: {{ cloudwatch.name }} - enabled: true - type: cloudwatch_logs - description: "lambda function for cloudwatch logs" - {% if cloudwatch.role %}role: {{ cloudwatch.role }}{% endif %} - {% if cloudwatch.virtual_private_cloud %} - virtual_private_cloud: - security_group_ids: {{ cloudwatch.virtual_private_cloud.security_group_ids }} - subnet_ids: {{ cloudwatch.virtual_private_cloud.subnet_ids }} - {% endif %} - - triggers: - - log_group_name: {{ cloudwatch.log_group | default("/aws/lambda/functionbeat-cloudwatch") }} -{% endif %} - -############################# Output ########################################## - -# Configure what outputs to use when sending the data collected by the beat. -# You can enable one or multiple outputs by setting enabled option to true. -output: - - ### File as output - file: - # Enabling file output - enabled: true - - # Path to the directory where to save the generated files. The option is mandatory. - path: {{ output_file_path|default(beat.working_dir + "/output") }} - - - # Name of the generated files. The default is `functionbeat` and it generates - # files: `functionbeat`, `functionbeat.1`, `functionbeat.2`, etc. - filename: {{ output_file_filename|default("functionbeat") }} - - # Maximum size in kilobytes of each file. When this size is reached, the files are - # rotated. The default value is 10 MB. - #rotate_every_kb: 10000 - - # Maximum number of files under path. When this number of files is reached, the - # oldest file is deleted and the rest are shifted from last to first. The default - # is 7 files. - #number_of_files: 7 - - - -############################# Beat ######################################### - -# The name of the shipper that publishes the network data. It can be used to group -# all the transactions sent by a single shipper in the web interface. -# If this options is not defined, the hostname is used. -#name: - -# The tags of the shipper are included in their own field with each -# transaction published. Tags make it easy to group servers by different -# logical properties. -#tags: ["service-X", "web-tier"] - - - -############################# Logging ######################################### - -#logging: - # Send all logging output to syslog. On Windows default is false, otherwise - # default is true. - #to_syslog: true - - # Write all logging output to files. Beats automatically rotate files if configurable - # limit is reached. - #to_files: false - - # Enable debug output for selected components. - #selectors: [] - - # Set log level - #level: error - - #files: - # The directory where the log files will written to. - #path: /var/log/functionbeat - - # The name of the files where the logs are written to. - #name: functionbeat - - # Configure log file size limit. If limit is reached, log file will be - # automatically rotated - #rotateeverybytes: 10485760 # = 10MB - - # Number of rotated log files to keep. Oldest files will be deleted first. - #keepfiles: 7 diff --git a/x-pack/functionbeat/tests/system/functionbeat.py b/x-pack/functionbeat/tests/system/functionbeat.py deleted file mode 100644 index 24327363aefc..000000000000 --- a/x-pack/functionbeat/tests/system/functionbeat.py +++ /dev/null @@ -1,12 +0,0 @@ -import os -import sys -from beat.beat import TestCase - - -class BaseTest(TestCase): - - @classmethod - def setUpClass(self): - self.beat_name = "functionbeat" - self.beat_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../")) - super(BaseTest, self).setUpClass() diff --git a/x-pack/functionbeat/tests/system/requirements.txt b/x-pack/functionbeat/tests/system/requirements.txt deleted file mode 100644 index c2399b66f80b..000000000000 --- a/x-pack/functionbeat/tests/system/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -protobuf==3.19.5 #Temporary change because of protobuf new version bug: https://github.com/protocolbuffers/protobuf/issues/10051 diff --git a/x-pack/functionbeat/tests/system/test_base.py b/x-pack/functionbeat/tests/system/test_base.py deleted file mode 100644 index 39a1051f8061..000000000000 --- a/x-pack/functionbeat/tests/system/test_base.py +++ /dev/null @@ -1,118 +0,0 @@ -from functionbeat import BaseTest - -import json -import os -import unittest -from beat import common_tests - - -class Test(BaseTest, common_tests.TestExportsMixin): - @unittest.skip("temporarily disabled") - def test_base(self): - """ - Basic test with exiting Functionbeat normally - """ - self.render_config_template( - path=os.path.abspath(self.working_dir) + "/log/*", - local=True, - ) - - functionbeat_proc = self.start_beat() - self.wait_until(lambda: self.log_contains("functionbeat is running")) - exit_code = functionbeat_proc.kill_and_wait() - assert exit_code == 0 - - def test_export_function(self): - """ - Test if the template can be exported - """ - - function_name = "testcloudwatchlogs" - bucket_name = "my-bucket-name" - fnb_name = "fnb" + function_name - role = "arn:aws:iam::123456789012:role/MyFunction" - security_group_ids = ["sg-ABCDEFGHIJKL"] - subnet_ids = ["subnet-ABCDEFGHIJKL"] - log_group = "/aws/lambda/functionbeat-cloudwatch" - - self._generate_dummy_binary_for_template_checksum() - - self.render_config_template( - path=os.path.abspath(self.working_dir) + "/log/*", - cloudwatch={ - "name": function_name, - "bucket": bucket_name, - "role": role, - "virtual_private_cloud": { - "security_group_ids": security_group_ids, - "subnet_ids": subnet_ids, - }, - "log_group": log_group, - }, - ) - functionbeat_proc = self.start_beat( - logging_args=["-d", "*"], - extra_args=["export", "function", function_name] - ) - - self.wait_until(lambda: self.log_contains("PASS")) - functionbeat_proc.check_wait() - - function_template = self._get_generated_function_template() - function_properties = function_template["Resources"][fnb_name]["Properties"] - - assert function_properties["FunctionName"] == function_name - assert function_properties["Code"]["S3Bucket"] == bucket_name - assert function_properties["Role"] == role - assert function_properties["VpcConfig"]["SecurityGroupIds"] == security_group_ids - assert function_properties["VpcConfig"]["SubnetIds"] == subnet_ids - - def test_export_function_invalid_conf(self): - """ - Test if invalid configuration is exportable - """ - function_name = "INVALID_$_FUNCTION_$_NAME" - bucket_name = "my-bucket-name" - - self._generate_dummy_binary_for_template_checksum() - - self.render_config_template( - path=os.path.abspath(self.working_dir) + "/log/*", - cloudwatch={ - "name": function_name, - "bucket": bucket_name, - }, - ) - functionbeat_proc = self.start_beat( - logging_args=["-d", "*"], - extra_args=["export", "function", function_name] - ) - - self.wait_until( - lambda: self.log_contains("error while finding enabled functions: invalid name: '{}'".format(function_name)) - ) - - exit_code = functionbeat_proc.kill_and_wait() - assert exit_code != 0 - - def _generate_dummy_binary_for_template_checksum(self): - fnbeat_pkg = os.path.join("pkg", "functionbeat") - fnbeat_aws_pkg = os.path.join("pkg", "functionbeat-aws") - bins_to_gen = [fnbeat_pkg, fnbeat_aws_pkg] - - if not os.path.exists("pkg"): - os.mkdir("pkg") - - for fb in bins_to_gen: - if os.path.exists(fb): - continue - with open(fb, "w") as f: - f.write("my dummy functionbeat binary\n") - - def _get_generated_function_template(self): - log = self.get_log() - # Trim the extra output from the Go test wrapper (like PASS/FAIL and - # coverage information). - log = log[:log.rindex('}') + 1] - function_template = json.loads(log) - return function_template diff --git a/x-pack/heartbeat/monitors/browser/synthexec/execmultiplexer.go b/x-pack/heartbeat/monitors/browser/synthexec/execmultiplexer.go index f3684398a513..fe384ae15b23 100644 --- a/x-pack/heartbeat/monitors/browser/synthexec/execmultiplexer.go +++ b/x-pack/heartbeat/monitors/browser/synthexec/execmultiplexer.go @@ -5,12 +5,10 @@ package synthexec -import ( - "github.com/elastic/beats/v7/libbeat/common/atomic" -) +import "sync/atomic" type ExecMultiplexer struct { - eventCounter *atomic.Int + eventCounter *atomic.Int64 synthEvents chan *SynthEvent done chan struct{} } @@ -27,7 +25,7 @@ func (e *ExecMultiplexer) writeSynthEvent(se *SynthEvent) { if se.Type == JourneyStart { e.eventCounter.Store(-1) } - se.index = e.eventCounter.Inc() + se.index = int(e.eventCounter.Add(1)) e.synthEvents <- se } @@ -48,8 +46,10 @@ func (e *ExecMultiplexer) Wait() { } func NewExecMultiplexer() *ExecMultiplexer { + c := &atomic.Int64{} + c.Store(-1) // Start from -1 so first call to Inc returns 0 return &ExecMultiplexer{ - eventCounter: atomic.NewInt(-1), // Start from -1 so first call to Inc returns 0 + eventCounter: c, synthEvents: make(chan *SynthEvent), done: make(chan struct{}), } diff --git a/x-pack/heartbeat/scenarios/framework/framework.go b/x-pack/heartbeat/scenarios/framework/framework.go index a2fb77e63070..6119f549e997 100644 --- a/x-pack/heartbeat/scenarios/framework/framework.go +++ b/x-pack/heartbeat/scenarios/framework/framework.go @@ -30,11 +30,13 @@ import ( beatversion "github.com/elastic/beats/v7/libbeat/version" ) -type ScenarioRun func(t *testing.T) (config mapstr.M, meta ScenarioRunMeta, close func(), err error) -type ScenarioRunMeta struct { - URL *url.URL - Status monitorstate.StateStatus -} +type ( + ScenarioRun func(t *testing.T) (config mapstr.M, meta ScenarioRunMeta, close func(), err error) + ScenarioRunMeta struct { + URL *url.URL + Status monitorstate.StateStatus + } +) type Scenario struct { Name string @@ -155,7 +157,6 @@ func NewScenarioDB() *ScenarioDB { ByTag: map[string][]Scenario{}, All: []Scenario{}, } - } func (sdb *ScenarioDB) Init() { @@ -250,7 +251,9 @@ func runMonitorOnce(t *testing.T, monitorConfig mapstr.M, meta ScenarioRunMeta, mIface, err := f.Create(pipe, conf) require.NoError(t, err) - mtr.monitor = mIface.(*monitors.Monitor) + mon, ok := mIface.(*monitors.Monitor) + require.True(t, ok, "type assertion didn't succeed") + mtr.monitor = mon require.NotNil(t, mtr.monitor, "could not convert to monitor %v", mIface) mtr.Events = pipe.PublishedEvents @@ -281,12 +284,8 @@ func setupFactoryAndSched(location *hbconfig.LocationWithID, stateLoader monitor EphemeralID: eid, FirstStart: time.Now(), StartTime: time.Now(), - Monitoring: struct { - DefaultUsername string - }{ - DefaultUsername: "test", - }, } + info.Monitoring.DefaultUsername = "test" sched = scheduler.Create( 1, diff --git a/x-pack/libbeat/docs/aws-credentials-config.asciidoc b/x-pack/libbeat/docs/aws-credentials-config.asciidoc index 423e241f8963..451980c28b7d 100644 --- a/x-pack/libbeat/docs/aws-credentials-config.asciidoc +++ b/x-pack/libbeat/docs/aws-credentials-config.asciidoc @@ -120,10 +120,6 @@ ifeval::["{beatname_lc}"=="metricbeat"] include::../../../metricbeat/docs/aws-credentials-examples.asciidoc[] endif::[] -ifeval::["{beatname_lc}"=="functionbeat"] -include::../../../filebeat/docs/aws-credentials-examples.asciidoc[] -endif::[] - [float] ==== AWS Credentials Types There are two different types of AWS credentials can be used: diff --git a/x-pack/libbeat/management/managerV2.go b/x-pack/libbeat/management/managerV2.go index e39b394bf2b3..288f28ae0de5 100644 --- a/x-pack/libbeat/management/managerV2.go +++ b/x-pack/libbeat/management/managerV2.go @@ -893,6 +893,13 @@ func (cm *BeatV2Manager) reloadAPM(unit *agentUnit) { apmConfig = expected.APMConfig } } + + if (cm.lastAPMCfg == nil && apmConfig == nil) || (cm.lastAPMCfg != nil && gproto.Equal(cm.lastAPMCfg, apmConfig)) { + // configuration for the APM tracing did not change; do nothing + cm.logger.Debug("Skipped reloading APM tracing; configuration didn't change") + return + } + if apmConfig == nil { // APM tracing is being stopped cm.logger.Debug("Stopping APM tracing") @@ -907,12 +914,6 @@ func (cm *BeatV2Manager) reloadAPM(unit *agentUnit) { return } - if cm.lastAPMCfg != nil && gproto.Equal(cm.lastAPMCfg, apmConfig) { - // configuration for the APM tracing did not change; do nothing - cm.logger.Debug("Skipped reloading APM tracing; configuration didn't change") - return - } - uconfig, err := conf.NewConfigFrom(apmConfig) if err != nil { cm.logger.Errorf("Failed to create uconfig from APM configuration: %s", err) diff --git a/x-pack/libbeat/management/managerV2_test.go b/x-pack/libbeat/management/managerV2_test.go index f1b32b15d82d..e7515266b0bc 100644 --- a/x-pack/libbeat/management/managerV2_test.go +++ b/x-pack/libbeat/management/managerV2_test.go @@ -13,6 +13,7 @@ import ( "time" "github.com/joeshaw/multierror" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" "google.golang.org/grpc" @@ -266,6 +267,141 @@ func TestManagerV2(t *testing.T) { }, 15*time.Second, 300*time.Millisecond) } +func TestManagerV2_ReloadCount(t *testing.T) { + r := reload.NewRegistry() + + output := &reloadable{} + r.MustRegisterOutput(output) + inputs := &reloadableList{} + r.MustRegisterInput(inputs) + apm := &reloadable{} + r.MustRegisterAPM(apm) + + inputConfigUpdated := make(chan struct{}) + onObserved := func(observed *proto.CheckinObserved, currentIdx int) { + if currentIdx == 1 { + period, err := inputs.Configs()[0].Config.String("period", -1) + require.NoError(t, err) + if period == "10m" { + select { + case <-inputConfigUpdated: + default: + close(inputConfigUpdated) + } + } + } + } + + agentInfo := &proto.AgentInfo{ + Id: "elastic-agent-id", + Version: version.GetDefaultVersion(), + Snapshot: true, + } + srv := integration.NewMockServer([]*proto.CheckinExpected{ + { + AgentInfo: agentInfo, + Units: []*proto.UnitExpected{ + { + Id: "output-unit", + Type: proto.UnitType_OUTPUT, + ConfigStateIdx: 1, + Config: &proto.UnitExpectedConfig{ + Id: "default", + Type: "elasticsearch", + Name: "elasticsearch", + }, + State: proto.State_HEALTHY, + LogLevel: proto.UnitLogLevel_INFO, + }, + { + Id: "input-unit-1", + Type: proto.UnitType_INPUT, + ConfigStateIdx: 1, + Config: &proto.UnitExpectedConfig{ + Id: "system/metrics-system-default-system-1", + Type: "system/metrics", + Name: "system-1", + Streams: []*proto.Stream{ + { + Id: "system/metrics-system.filesystem-default-system-1", + Source: integration.RequireNewStruct(t, map[string]interface{}{ + "metricsets": []interface{}{"filesystem"}, + "period": "1m", + }), + }, + }, + }, + State: proto.State_HEALTHY, + LogLevel: proto.UnitLogLevel_INFO, + }, + }, + Features: nil, + FeaturesIdx: 1, + }, + { + AgentInfo: agentInfo, + Units: []*proto.UnitExpected{ + { + Id: "output-unit", + Type: proto.UnitType_OUTPUT, + ConfigStateIdx: 1, + State: proto.State_HEALTHY, + LogLevel: proto.UnitLogLevel_INFO, + }, + { + Id: "input-unit-1", + Type: proto.UnitType_INPUT, + ConfigStateIdx: 2, + Config: &proto.UnitExpectedConfig{ + Id: "system/metrics-system-default-system-1", + Type: "system/metrics", + Name: "system-1", + Streams: []*proto.Stream{ + { + Id: "system/metrics-system.filesystem-default-system-1", + Source: integration.RequireNewStruct(t, map[string]interface{}{ + "metricsets": []interface{}{"filesystem"}, + "period": "10m", + }), + }, + }, + }, + State: proto.State_HEALTHY, + LogLevel: proto.UnitLogLevel_INFO, + }, + }, + Features: nil, + FeaturesIdx: 1, + }, + }, + onObserved, + 500*time.Millisecond, + ) + require.NoError(t, srv.Start()) + defer srv.Stop() + + client := client.NewV2(fmt.Sprintf(":%d", srv.Port), "", client.VersionInfo{ + Name: "program", + Meta: map[string]string{ + "key": "value", + }, + }, client.WithGRPCDialOptions(grpc.WithTransportCredentials(insecure.NewCredentials()))) + + m, err := NewV2AgentManagerWithClient(&Config{ + Enabled: true, + }, r, client) + require.NoError(t, err) + + err = m.Start() + require.NoError(t, err) + defer m.Stop() + + <-inputConfigUpdated + assert.Equal(t, 1, output.reloadCount) // initial load + assert.Equal(t, 2, inputs.reloadCount) // initial load + config update + assert.Equal(t, 0, apm.reloadCount) // no apm tracing config applied +} + func TestOutputError(t *testing.T) { // Uncomment the line below to see the debug logs for this test // logp.DevelopmentSetup(logp.WithLevel(logp.DebugLevel), logp.WithSelectors("*")) @@ -553,19 +689,22 @@ func TestErrorPerUnit(t *testing.T) { } type reloadable struct { - mx sync.Mutex - config *reload.ConfigWithMeta + mx sync.Mutex + config *reload.ConfigWithMeta + reloadCount int } type reloadableList struct { - mx sync.Mutex - configs []*reload.ConfigWithMeta + mx sync.Mutex + configs []*reload.ConfigWithMeta + reloadCount int } func (r *reloadable) Reload(config *reload.ConfigWithMeta) error { r.mx.Lock() defer r.mx.Unlock() r.config = config + r.reloadCount++ return nil } @@ -579,6 +718,7 @@ func (r *reloadableList) Reload(configs []*reload.ConfigWithMeta) error { r.mx.Lock() defer r.mx.Unlock() r.configs = configs + r.reloadCount++ return nil } diff --git a/x-pack/libbeat/management/tests/mbtest/metricbeat_v2_test.go b/x-pack/libbeat/management/tests/mbtest/metricbeat_v2_test.go index fb8542514c2c..4ffa583120b4 100644 --- a/x-pack/libbeat/management/tests/mbtest/metricbeat_v2_test.go +++ b/x-pack/libbeat/management/tests/mbtest/metricbeat_v2_test.go @@ -34,8 +34,9 @@ var expectedMBStreams = &proto.UnitExpectedConfig{ } func TestSingleMetricbeatMetricsetWithProcessors(t *testing.T) { - tests.InitBeatsForTest(t, cmd.RootCmd) - var mbStreams = []*proto.Stream{ + mbCmd := cmd.Initialize() + tests.InitBeatsForTest(t, mbCmd) + mbStreams := []*proto.Stream{ { Id: "system/metrics-system.cpu-default-system", DataStream: &proto.DataStream{ @@ -79,7 +80,7 @@ func TestSingleMetricbeatMetricsetWithProcessors(t *testing.T) { go func() { t.Logf("Running beats...") - err := cmd.RootCmd.Execute() + err := mbCmd.Execute() require.NoError(t, err) }() diff --git a/x-pack/libbeat/management/tests/mbtest/system/process_integration_test.go b/x-pack/libbeat/management/tests/mbtest/system/process_integration_test.go index 660e95255582..3f9361823337 100644 --- a/x-pack/libbeat/management/tests/mbtest/system/process_integration_test.go +++ b/x-pack/libbeat/management/tests/mbtest/system/process_integration_test.go @@ -37,7 +37,8 @@ func TestProcessStatusReporter(t *testing.T) { unitOutID := mock.NewID() token := mock.NewID() - tests.InitBeatsForTest(t, cmd.RootCmd) + mbCmd := cmd.Initialize() + tests.InitBeatsForTest(t, mbCmd) filename := fmt.Sprintf("test-%d", time.Now().Unix()) outPath := filepath.Join(t.TempDir(), filename) @@ -122,7 +123,7 @@ func TestProcessStatusReporter(t *testing.T) { go func() { t.Logf("Running beats...") - err := cmd.RootCmd.Execute() + err := mbCmd.Execute() require.NoError(t, err) }() diff --git a/x-pack/libbeat/reader/parquet/parquet.go b/x-pack/libbeat/reader/parquet/parquet.go index 3fbe357b2126..356e6846422f 100644 --- a/x-pack/libbeat/reader/parquet/parquet.go +++ b/x-pack/libbeat/reader/parquet/parquet.go @@ -10,10 +10,10 @@ import ( "fmt" "io" - "github.com/apache/arrow/go/v14/arrow/memory" - "github.com/apache/arrow/go/v14/parquet" - "github.com/apache/arrow/go/v14/parquet/file" - "github.com/apache/arrow/go/v14/parquet/pqarrow" + "github.com/apache/arrow/go/v17/arrow/memory" + "github.com/apache/arrow/go/v17/parquet" + "github.com/apache/arrow/go/v17/parquet/file" + "github.com/apache/arrow/go/v17/parquet/pqarrow" "github.com/elastic/elastic-agent-libs/logp" ) diff --git a/x-pack/libbeat/reader/parquet/parquet_test.go b/x-pack/libbeat/reader/parquet/parquet_test.go index 61f4936d1f87..9749998e6f57 100644 --- a/x-pack/libbeat/reader/parquet/parquet_test.go +++ b/x-pack/libbeat/reader/parquet/parquet_test.go @@ -14,10 +14,10 @@ import ( "path/filepath" "testing" - "github.com/apache/arrow/go/v14/arrow" - "github.com/apache/arrow/go/v14/arrow/array" - "github.com/apache/arrow/go/v14/arrow/memory" - "github.com/apache/arrow/go/v14/parquet/pqarrow" + "github.com/apache/arrow/go/v17/arrow" + "github.com/apache/arrow/go/v17/arrow/array" + "github.com/apache/arrow/go/v17/arrow/memory" + "github.com/apache/arrow/go/v17/parquet/pqarrow" "github.com/stretchr/testify/assert" "github.com/elastic/elastic-agent-libs/logp" diff --git a/x-pack/metricbeat/cmd/root.go b/x-pack/metricbeat/cmd/root.go index 47e169b1c956..76ca40ddf131 100644 --- a/x-pack/metricbeat/cmd/root.go +++ b/x-pack/metricbeat/cmd/root.go @@ -33,9 +33,6 @@ const ( Name = "metricbeat" ) -// RootCmd to handle beats cli -var RootCmd *cmd.BeatsRootCmd - // withECSVersion is a modifier that adds ecs.version to events. var withECSVersion = processing.WithFields(mapstr.M{ "ecs": mapstr.M{ @@ -43,7 +40,7 @@ var withECSVersion = processing.WithFields(mapstr.M{ }, }) -func init() { +func Initialize() *cmd.BeatsRootCmd { globalProcs, err := processors.NewPluginConfigFromList(defaultProcessors()) if err != nil { // these are hard-coded, shouldn't fail panic(fmt.Errorf("error creating global processors: %w", err)) @@ -51,12 +48,13 @@ func init() { settings := mbcmd.MetricbeatSettings("") settings.ElasticLicensed = true settings.Processing = processing.MakeDefaultSupport(true, globalProcs, withECSVersion, processing.WithHost, processing.WithAgentMeta()) - RootCmd = cmd.GenRootCmdWithSettings(beater.DefaultCreator(), settings) - RootCmd.AddCommand(cmd.GenModulesCmd(Name, "", mbcmd.BuildModulesManager)) - RootCmd.TestCmd.AddCommand(test.GenTestModulesCmd(Name, "", beater.DefaultTestModulesCreator())) - RootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) { + rootCmd := cmd.GenRootCmdWithSettings(beater.DefaultCreator(), settings) + rootCmd.AddCommand(cmd.GenModulesCmd(Name, "", mbcmd.BuildModulesManager)) + rootCmd.TestCmd.AddCommand(test.GenTestModulesCmd(Name, "", beater.DefaultTestModulesCreator())) + rootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) { management.ConfigTransform.SetTransform(metricbeatCfg) } + return rootCmd } func defaultProcessors() []mapstr.M { diff --git a/x-pack/metricbeat/include/list.go b/x-pack/metricbeat/include/list.go index 01ce86edf78c..af3b1e9425d8 100644 --- a/x-pack/metricbeat/include/list.go +++ b/x-pack/metricbeat/include/list.go @@ -21,6 +21,8 @@ import ( _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/azure/billing" _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/azure/monitor" _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/azure/storage" + _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/benchmark" + _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/benchmark/info" _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/cloudfoundry" _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/cloudfoundry/container" _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/cloudfoundry/counter" @@ -53,6 +55,8 @@ import ( _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/mssql" _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/mssql/performance" _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/mssql/transaction_log" + _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/openai" + _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/openai/usage" _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/oracle" _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/oracle/performance" _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/oracle/sysmetric" diff --git a/x-pack/metricbeat/main.go b/x-pack/metricbeat/main.go index 92469da9c174..08afded3254f 100644 --- a/x-pack/metricbeat/main.go +++ b/x-pack/metricbeat/main.go @@ -19,7 +19,7 @@ import ( ) func main() { - if err := cmd.RootCmd.Execute(); err != nil { + if err := cmd.Initialize().Execute(); err != nil { os.Exit(1) } } diff --git a/x-pack/metricbeat/main_test.go b/x-pack/metricbeat/main_test.go index e96a9932765c..906782e1f5a5 100644 --- a/x-pack/metricbeat/main_test.go +++ b/x-pack/metricbeat/main_test.go @@ -6,21 +6,27 @@ package main // This file is mandatory as otherwise the metricbeat.test binary is not generated correctly. import ( "flag" + "os" "testing" "github.com/elastic/beats/v7/libbeat/cfgfile" + cmd "github.com/elastic/beats/v7/libbeat/cmd" "github.com/elastic/beats/v7/libbeat/tests/system/template" - "github.com/elastic/beats/v7/x-pack/metricbeat/cmd" + mbcmd "github.com/elastic/beats/v7/x-pack/metricbeat/cmd" ) -var systemTest *bool +var ( + systemTest *bool + mbCommand *cmd.BeatsRootCmd +) func init() { testing.Init() systemTest = flag.Bool("systemTest", false, "Set to true when running system tests") - cmd.RootCmd.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("systemTest")) + mbCommand = mbcmd.Initialize() + mbCommand.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("systemTest")) cfgfile.AddAllowedBackwardsCompatibleFlag("systemTest") - cmd.RootCmd.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("test.coverprofile")) + mbCommand.PersistentFlags().AddGoFlag(flag.CommandLine.Lookup("test.coverprofile")) cfgfile.AddAllowedBackwardsCompatibleFlag("test.coverprofile") } @@ -28,10 +34,12 @@ func init() { func TestSystem(t *testing.T) { cfgfile.ConvertFlagsForBackwardsCompatibility() if *systemTest { - main() + if err := mbCommand.Execute(); err != nil { + os.Exit(1) + } } } func TestTemplate(t *testing.T) { - template.TestTemplate(t, cmd.Name, true) + template.TestTemplate(t, mbCommand.Name(), true) } diff --git a/x-pack/metricbeat/mbreceiver/config.go b/x-pack/metricbeat/mbreceiver/config.go new file mode 100644 index 000000000000..e8fdbbce2e31 --- /dev/null +++ b/x-pack/metricbeat/mbreceiver/config.go @@ -0,0 +1,25 @@ +// 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 mbreceiver + +import "fmt" + +// Config is config settings for metricbeat receiver. The structure of +// which is the same as the metricbeat.yml configuration file. +type Config struct { + Beatconfig map[string]interface{} `mapstructure:",remain"` +} + +// Validate checks if the configuration in valid +func (cfg *Config) Validate() error { + if len(cfg.Beatconfig) == 0 { + return fmt.Errorf("Configuration is required") + } + _, prs := cfg.Beatconfig["metricbeat"] + if !prs { + return fmt.Errorf("Configuration key 'metricbeat' is required") + } + return nil +} diff --git a/x-pack/metricbeat/mbreceiver/config_test.go b/x-pack/metricbeat/mbreceiver/config_test.go new file mode 100644 index 000000000000..25bcc101568f --- /dev/null +++ b/x-pack/metricbeat/mbreceiver/config_test.go @@ -0,0 +1,44 @@ +// 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 mbreceiver + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestValidate(t *testing.T) { + tests := map[string]struct { + c *Config + hasError bool + errorString string + }{ + "Empty config": { + c: &Config{Beatconfig: map[string]interface{}{}}, + hasError: true, + errorString: "Configuration is required", + }, + "No metricbeat section": { + c: &Config{Beatconfig: map[string]interface{}{"other": map[string]interface{}{}}}, + hasError: true, + errorString: "Configuration key 'metricbeat' is required", + }, + "Valid config": { + c: &Config{Beatconfig: map[string]interface{}{"metricbeat": map[string]interface{}{}}}, + hasError: false, + errorString: "", + }, + } + for name, tc := range tests { + err := tc.c.Validate() + if tc.hasError { + assert.NotNilf(t, err, "%s failed, should have had error", name) + assert.Equalf(t, err.Error(), tc.errorString, "%s failed, error not equal", name) + } else { + assert.Nilf(t, err, "%s failed, should not have error", name) + } + } +} diff --git a/x-pack/metricbeat/mbreceiver/factory.go b/x-pack/metricbeat/mbreceiver/factory.go new file mode 100644 index 000000000000..62ea8f5c9b5f --- /dev/null +++ b/x-pack/metricbeat/mbreceiver/factory.go @@ -0,0 +1,61 @@ +// 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 mbreceiver + +import ( + "context" + "fmt" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/consumer" + "go.opentelemetry.io/collector/receiver" + + "github.com/elastic/beats/v7/libbeat/cmd/instance" + "github.com/elastic/beats/v7/metricbeat/beater" + "github.com/elastic/beats/v7/metricbeat/cmd" +) + +const ( + Name = "metricbeatreceiver" +) + +func createDefaultConfig() component.Config { + return &Config{} +} + +func createReceiver(_ context.Context, set receiver.Settings, baseCfg component.Config, consumer consumer.Logs) (receiver.Logs, error) { + cfg, ok := baseCfg.(*Config) + if !ok { + return nil, fmt.Errorf("could not convert otel config to metricbeat config") + } + settings := cmd.MetricbeatSettings(Name) + settings.ElasticLicensed = true + + b, err := instance.NewBeatReceiver(settings, cfg.Beatconfig, consumer, set.Logger.Core()) + if err != nil { + return nil, fmt.Errorf("error creating %s: %w", Name, err) + } + + beatCreator := beater.DefaultCreator() + + beatConfig, err := b.BeatConfig() + if err != nil { + return nil, fmt.Errorf("error getting beat config: %w", err) + } + + mbBeater, err := beatCreator(&b.Beat, beatConfig) + if err != nil { + return nil, fmt.Errorf("error getting %s creator:%w", Name, err) + } + + return &metricbeatReceiver{beat: &b.Beat, beater: mbBeater, logger: set.Logger}, nil +} + +func NewFactory() receiver.Factory { + return receiver.NewFactory( + component.MustNewType(Name), + createDefaultConfig, + receiver.WithLogs(createReceiver, component.StabilityLevelAlpha)) +} diff --git a/x-pack/metricbeat/mbreceiver/receiver.go b/x-pack/metricbeat/mbreceiver/receiver.go new file mode 100644 index 000000000000..848ca9347aab --- /dev/null +++ b/x-pack/metricbeat/mbreceiver/receiver.go @@ -0,0 +1,37 @@ +// 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 mbreceiver + +import ( + "context" + + "github.com/elastic/beats/v7/libbeat/beat" + + "go.opentelemetry.io/collector/component" + "go.uber.org/zap" +) + +type metricbeatReceiver struct { + beat *beat.Beat + beater beat.Beater + logger *zap.Logger +} + +func (mb *metricbeatReceiver) Start(ctx context.Context, host component.Host) error { + go func() { + mb.logger.Info("starting metricbeat receiver") + err := mb.beater.Run(mb.beat) + if err != nil { + mb.logger.Error("metricbeat receiver run error", zap.Error(err)) + } + }() + return nil +} + +func (mb *metricbeatReceiver) Shutdown(ctx context.Context) error { + mb.logger.Info("stopping metricbeat receiver") + mb.beater.Stop() + return nil +} diff --git a/x-pack/metricbeat/mbreceiver/receiver_test.go b/x-pack/metricbeat/mbreceiver/receiver_test.go new file mode 100644 index 000000000000..b7dac8c488e8 --- /dev/null +++ b/x-pack/metricbeat/mbreceiver/receiver_test.go @@ -0,0 +1,92 @@ +// 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 mbreceiver + +import ( + "bytes" + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/consumer" + "go.opentelemetry.io/collector/pdata/plog" + "go.opentelemetry.io/collector/receiver" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +func TestNewReceiver(t *testing.T) { + config := Config{ + Beatconfig: map[string]interface{}{ + "metricbeat": map[string]interface{}{ + "modules": []map[string]interface{}{ + { + "module": "system", + "enabled": true, + "period": "1s", + "processes": []string{".*"}, + "metricsets": []string{"cpu"}, + }, + }, + }, + "output": map[string]interface{}{ + "otelconsumer": map[string]interface{}{}, + }, + "logging": map[string]interface{}{ + "level": "debug", + "selectors": []string{ + "*", + }, + }, + "path.home": t.TempDir(), + }, + } + + var zapLogs bytes.Buffer + core := zapcore.NewCore( + zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()), + zapcore.AddSync(&zapLogs), + zapcore.DebugLevel) + + receiverSettings := receiver.Settings{} + receiverSettings.Logger = zap.New(core) + + var countLogs int + logConsumer, err := consumer.NewLogs(func(ctx context.Context, ld plog.Logs) error { + countLogs = countLogs + ld.LogRecordCount() + return nil + }) + require.NoError(t, err, "Error creating log consumer") + + r, err := createReceiver(context.Background(), receiverSettings, &config, logConsumer) + require.NoErrorf(t, err, "Error creating receiver. Logs:\n %s", zapLogs.String()) + err = r.Start(context.Background(), nil) + require.NoError(t, err, "Error starting metricbeatreceiver") + + ch := make(chan bool, 1) + timer := time.NewTimer(120 * time.Second) + defer timer.Stop() + ticker := time.NewTicker(1 * time.Second) + defer ticker.Stop() + + for tick := ticker.C; ; { + select { + case <-timer.C: + t.Fatalf("consumed logs didn't increase\nCount: %d\nLogs: %s\n", countLogs, zapLogs.String()) + case <-tick: + tick = nil + go func() { ch <- countLogs > 0 }() + case v := <-ch: + if v { + goto found + } + tick = ticker.C + } + } +found: + err = r.Shutdown(context.Background()) + require.NoError(t, err, "Error shutting down metricbeatreceiver") +} diff --git a/x-pack/metricbeat/metricbeat.reference.yml b/x-pack/metricbeat/metricbeat.reference.yml index 24a41cedb699..4870d37c2a43 100644 --- a/x-pack/metricbeat/metricbeat.reference.yml +++ b/x-pack/metricbeat/metricbeat.reference.yml @@ -142,6 +142,11 @@ metricbeat.modules: # Filter systemd services based on a name pattern #service.pattern_filter: ["ssh*", "nfs*"] + # This option enables the use of performance counters to collect data for cpu/core metricset. + # Only effective for Windows. + # You should use this option if running beats on machins with more than 64 cores. + #use_performance_counters: true + #------------------------------- ActiveMQ Module ------------------------------- - module: activemq metricsets: ['broker', 'queue', 'topic'] @@ -404,6 +409,14 @@ metricbeat.modules: # Monitoring instead of metricbeat-* indices. #xpack.enabled: false +#------------------------------ Benchmark Module ------------------------------ +- module: benchmark + metricsets: + - info + enabled: false + period: 10s + + #--------------------------------- Ceph Module --------------------------------- # Metricsets depending on the Ceph REST API (default port: 5000) - module: ceph @@ -513,6 +526,9 @@ metricbeat.modules: # If set to true, replace dots in labels with `_`. #labels.dedot: false + # Docker module supports metrics collection from podman's docker compatible API. In case of podman set to true. + # podman: false + # Skip metrics for certain device major numbers in docker/diskio. # Necessary on systems with software RAID, device mappers, # or other configurations where virtual disks will sum metrics from other disks. @@ -618,6 +634,7 @@ metricbeat.modules: credentials_file_path: "your JSON credentials file path" exclude_labels: false period: 1m + location_label: "resource.labels.zone" metrics: - aligner: ALIGN_NONE service: compute @@ -1267,6 +1284,42 @@ metricbeat.modules: # Path to server status. Default nginx_status server_status_path: "nginx_status" +#-------------------------------- Openai Module -------------------------------- +- module: openai + metricsets: ["usage"] + enabled: false + period: 1h + + # # Project API Keys - Multiple API keys can be specified for different projects + # api_keys: + # - key: "api_key1" + # - key: "api_key2" + + # # API Configuration + # ## Base URL for the OpenAI usage API endpoint + # api_url: "https://api.openai.com/v1/usage" + # ## Custom headers to be included in API requests + # headers: + # - "k1: v1" + # - "k2: v2" + ## Rate Limiting Configuration + # rate_limit: + # limit: 12 # seconds between requests + # burst: 1 # max concurrent requests + # ## Request Timeout Duration + # timeout: 30s + + # # Data Collection Configuration + # collection: + # ## Number of days to look back when collecting usage data + # lookback_days: 30 + # ## Whether to collect usage data in realtime. Defaults to false as how + # # OpenAI usage data is collected will end up adding duplicate data to ES + # # and also making it harder to do analytics. Best approach is to avoid + # # realtime collection and collect only upto last day (in UTC). So, there's + # # at most 24h delay. + # realtime: false + #----------------------------- Openmetrics Module ----------------------------- - module: openmetrics metricsets: ['collector'] diff --git a/x-pack/metricbeat/module/benchmark/_meta/config.yml b/x-pack/metricbeat/module/benchmark/_meta/config.yml new file mode 100644 index 000000000000..535ce486754d --- /dev/null +++ b/x-pack/metricbeat/module/benchmark/_meta/config.yml @@ -0,0 +1,6 @@ +- module: benchmark + metricsets: + - info + enabled: false + period: 10s + diff --git a/x-pack/metricbeat/module/benchmark/_meta/docs.asciidoc b/x-pack/metricbeat/module/benchmark/_meta/docs.asciidoc new file mode 100644 index 000000000000..5b0dbf829fcc --- /dev/null +++ b/x-pack/metricbeat/module/benchmark/_meta/docs.asciidoc @@ -0,0 +1,31 @@ +include::{libbeat-dir}/shared/integration-link.asciidoc[] + +:modulename!: + +The `benchmark` module is used to generate synthetic metrics at a predictable rate. This can be useful when you want to test output settings or test system sizing without using real data. + +The `benchmark` module metricset is `info`. + +[source,yaml] +---- +- module: benchmark + metricsets: + - info + enabled: true + period: 10s +---- + +[float] +== Metricsets + +[float] +=== `info` +A metric that includes a `counter` field which is used to keep the metric unique. + +[float] +=== Module-specific configuration notes + +`count`:: number, the number of metrics to emit per fetch. + + + diff --git a/x-pack/metricbeat/module/benchmark/_meta/fields.yml b/x-pack/metricbeat/module/benchmark/_meta/fields.yml new file mode 100644 index 000000000000..308834cb5dc8 --- /dev/null +++ b/x-pack/metricbeat/module/benchmark/_meta/fields.yml @@ -0,0 +1,10 @@ +- key: benchmark + title: "Benchmark" + release: beta + description: > + benchmark module + fields: + - name: benchmark + type: group + description: > + fields: diff --git a/x-pack/metricbeat/module/benchmark/doc.go b/x-pack/metricbeat/module/benchmark/doc.go new file mode 100644 index 000000000000..461045f17c20 --- /dev/null +++ b/x-pack/metricbeat/module/benchmark/doc.go @@ -0,0 +1,6 @@ +// 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 benchmark is a Metricbeat module that contains MetricSets. +package benchmark diff --git a/x-pack/metricbeat/module/benchmark/fields.go b/x-pack/metricbeat/module/benchmark/fields.go new file mode 100644 index 000000000000..30fa60460d80 --- /dev/null +++ b/x-pack/metricbeat/module/benchmark/fields.go @@ -0,0 +1,23 @@ +// 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. + +// Code generated by beats/dev-tools/cmd/asset/asset.go - DO NOT EDIT. + +package benchmark + +import ( + "github.com/elastic/beats/v7/libbeat/asset" +) + +func init() { + if err := asset.SetFields("metricbeat", "benchmark", asset.ModuleFieldsPri, AssetBenchmark); err != nil { + panic(err) + } +} + +// AssetBenchmark returns asset data. +// This is the base64 encoded zlib format compressed contents of module/benchmark. +func AssetBenchmark() string { + return "eJx8kM1txCAUhO9UMdr7NsAhh9SQBliYDcj8WPhZEd1HOHFiEyvf8Q36ZsQdE5vGg9n6ZOqkAAkSqXF73W83BVRGmoX9pRgFOC62hllCyRovCsCvA6m4NVIBz8DoFr3Fd2STeK7qSJup8V7LOn9fLtxn1VEX8rP8HK9snXH9zmXTF4N3rD9OsGXNwnrK9iUT20epbsj+6e28eSKL3zYgUWqwYAoidHg0iOffz/4MAAD//xhTfdM=" +} diff --git a/x-pack/metricbeat/module/benchmark/info/_meta/data.json b/x-pack/metricbeat/module/benchmark/info/_meta/data.json new file mode 100644 index 000000000000..a64b394dfd98 --- /dev/null +++ b/x-pack/metricbeat/module/benchmark/info/_meta/data.json @@ -0,0 +1,23 @@ +{ + "@timestamp": "2016-05-23T08:05:34.853Z", + "metricset": { + "name": "info", + "period": 1000 + }, + "event": { + "duration": 27000, + "dataset": "benchmark.info", + "module": "benchmark" + }, + "service": { + "type": "benchmark" + }, + "service": { + "type": "benchmark" + }, + "benchmark": { + "info": { + "counter": 42 + } + } +} diff --git a/x-pack/metricbeat/module/benchmark/info/_meta/docs.asciidoc b/x-pack/metricbeat/module/benchmark/info/_meta/docs.asciidoc new file mode 100644 index 000000000000..a8f407cf7f39 --- /dev/null +++ b/x-pack/metricbeat/module/benchmark/info/_meta/docs.asciidoc @@ -0,0 +1 @@ +This is the info metricset of the module benchmark. diff --git a/x-pack/metricbeat/module/benchmark/info/_meta/fields.yml b/x-pack/metricbeat/module/benchmark/info/_meta/fields.yml new file mode 100644 index 000000000000..0068b75bcf0f --- /dev/null +++ b/x-pack/metricbeat/module/benchmark/info/_meta/fields.yml @@ -0,0 +1,10 @@ +- name: info + type: group + release: beta + description: > + info + fields: + - name: counter + type: keyword + description: > + The nth info metric emitted by the benchmark module diff --git a/x-pack/metricbeat/module/benchmark/info/config.go b/x-pack/metricbeat/module/benchmark/info/config.go new file mode 100644 index 000000000000..424a8a5c60c2 --- /dev/null +++ b/x-pack/metricbeat/module/benchmark/info/config.go @@ -0,0 +1,24 @@ +// 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 info + +import ( + "errors" +) + +type infoConfig struct { + Count uint `config:"count"` +} + +var defaultConfig = infoConfig{ + Count: 1, +} + +func (c *infoConfig) Validate() error { + if c.Count == 0 { + return errors.New("benchmark module 'count' must be greater than 0") + } + return nil +} diff --git a/x-pack/metricbeat/module/benchmark/info/config_test.go b/x-pack/metricbeat/module/benchmark/info/config_test.go new file mode 100644 index 000000000000..95030443b017 --- /dev/null +++ b/x-pack/metricbeat/module/benchmark/info/config_test.go @@ -0,0 +1,37 @@ +// 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 info + +import ( + "strings" + "testing" +) + +func TestValidate(t *testing.T) { + tests := map[string]struct { + cfg infoConfig + expectError bool + errorString string + }{ + "default": {cfg: defaultConfig}, + "empty": {cfg: infoConfig{}, expectError: true, errorString: "benchmark module 'count' must be greater than 0"}, + "counter 0": {cfg: infoConfig{Count: 0}, expectError: true, errorString: "benchmark module 'count' must be greater than 0"}, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + err := tc.cfg.Validate() + if err == nil && tc.expectError == true { + t.Fatalf("expected validation error, didn't get it") + } + if err != nil && tc.expectError == false { + t.Fatalf("unexpected validation error: %s", err) + } + if err != nil && !strings.Contains(err.Error(), tc.errorString) { + t.Fatalf("error: '%s' didn't contain expected string: '%s'", err, tc.errorString) + } + }) + } +} diff --git a/x-pack/metricbeat/module/benchmark/info/info.go b/x-pack/metricbeat/module/benchmark/info/info.go new file mode 100644 index 000000000000..bd4ca1e6272a --- /dev/null +++ b/x-pack/metricbeat/module/benchmark/info/info.go @@ -0,0 +1,62 @@ +// 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 info + +import ( + "github.com/elastic/beats/v7/libbeat/common/cfgwarn" + "github.com/elastic/beats/v7/metricbeat/mb" + "github.com/elastic/elastic-agent-libs/mapstr" +) + +// init registers the MetricSet with the central registry as soon as the program +// starts. The New function will be called later to instantiate an instance of +// the MetricSet for each host is defined in the module's configuration. After the +// MetricSet has been created then Fetch will begin to be called periodically. +func init() { + mb.Registry.MustAddMetricSet("benchmark", "info", New) +} + +// MetricSet holds any configuration or state information. It must implement +// the mb.MetricSet interface. And this is best achieved by embedding +// mb.BaseMetricSet because it implements all of the required mb.MetricSet +// interface methods except for Fetch. +type MetricSet struct { + mb.BaseMetricSet + counter uint + eventsPerFetch uint +} + +// New creates a new instance of the MetricSet. New is responsible for unpacking +// any MetricSet specific configuration options if there are any. +func New(base mb.BaseMetricSet) (mb.MetricSet, error) { + cfgwarn.Beta("The benchmark info metricset is beta.") + + config := defaultConfig + if err := base.Module().UnpackConfig(&config); err != nil { + return nil, err + } + + return &MetricSet{ + BaseMetricSet: base, + counter: 1, + eventsPerFetch: config.Count, + }, nil +} + +// Fetch method implements the data gathering and data conversion to the right +// format. It publishes the event which is then forwarded to the output. In case +// of an error set the Error field of mb.Event or simply call report.Error(). +func (m *MetricSet) Fetch(report mb.ReporterV2) error { + for i := uint(0); i < m.eventsPerFetch; i++ { + report.Event(mb.Event{ + MetricSetFields: mapstr.M{ + "counter": m.counter, + }, + }) + m.counter++ + } + + return nil +} diff --git a/x-pack/metricbeat/module/benchmark/info/info_test.go b/x-pack/metricbeat/module/benchmark/info/info_test.go new file mode 100644 index 000000000000..1df775e76b01 --- /dev/null +++ b/x-pack/metricbeat/module/benchmark/info/info_test.go @@ -0,0 +1,54 @@ +// 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 info + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + mbtest "github.com/elastic/beats/v7/metricbeat/mb/testing" +) + +func TestFetch(t *testing.T) { + tests := map[string]struct { + count uint + }{ + "one count": {count: uint(1)}, + "five count": {count: uint(5)}, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + config := map[string]interface{}{ + "module": "benchmark", + "period": "1s", + "metricsets": []string{"info"}, + "count": tc.count, + } + t.Cleanup(func() { + if t.Failed() { + t.Logf("Contents of config:\n%v", config) + } + }) + + f := mbtest.NewFetcher(t, config) + events, errs := f.FetchEvents() + assert.Emptyf(t, errs, "errs should be empty, err: %v", errs) + assert.Equalf(t, int(tc.count), len(events), "events should have %d events not %d, events: %v", int(tc.count), len(events), events) + + for i, event := range events { + msf := event.MetricSetFields + + ok, err := msf.HasKey("counter") + assert.Truef(t, ok, "MetricSetFields must contain \"counter\", msf: %v", msf) + assert.NoErrorf(t, err, "MetricSetFields must contain \"counter\", msf: %v", msf) + + v, err := msf.GetValue("counter") + assert.NoErrorf(t, err, "MetricSetFields must contain \"counter\", msf: %v", msf) + assert.Equalf(t, uint(i+1), v, "counter should be %d, was %v", i+1, v) + } + }) + } +} diff --git a/x-pack/metricbeat/module/cloudfoundry/v1.go b/x-pack/metricbeat/module/cloudfoundry/v1.go index f03f6a98ebb8..86610e0d6cbf 100644 --- a/x-pack/metricbeat/module/cloudfoundry/v1.go +++ b/x-pack/metricbeat/module/cloudfoundry/v1.go @@ -7,7 +7,8 @@ package cloudfoundry import ( - "github.com/elastic/beats/v7/libbeat/common/atomic" + "sync/atomic" + "github.com/elastic/beats/v7/metricbeat/mb" cfcommon "github.com/elastic/beats/v7/x-pack/libbeat/common/cloudfoundry" "github.com/elastic/elastic-agent-libs/logp" @@ -29,7 +30,6 @@ func newModuleV1(base mb.BaseModule, hub CloudfoundryHub, log *logp.Logger) (*Mo m := ModuleV1{ BaseModule: base, log: log, - running: atomic.MakeBool(false), } consumer, err := hub.DopplerConsumer(cfcommon.DopplerCallbacks{ Metric: m.callback, @@ -83,7 +83,7 @@ func (m *ModuleV1) callback(event cfcommon.Event) { // run ensures that the module is running with the passed subscription func (m *ModuleV1) run(s subscription) { - if !m.running.CAS(false, true) { + if !m.running.CompareAndSwap(false, true) { // Module is already running, queue subscription for current dispatcher. m.subscriptions <- s return diff --git a/x-pack/metricbeat/module/gcp/_meta/config.yml b/x-pack/metricbeat/module/gcp/_meta/config.yml index ad0c7da852fa..55001654db98 100644 --- a/x-pack/metricbeat/module/gcp/_meta/config.yml +++ b/x-pack/metricbeat/module/gcp/_meta/config.yml @@ -34,6 +34,7 @@ credentials_file_path: "your JSON credentials file path" exclude_labels: false period: 1m + location_label: "resource.labels.zone" metrics: - aligner: ALIGN_NONE service: compute diff --git a/x-pack/metricbeat/module/gcp/distribution.go b/x-pack/metricbeat/module/gcp/distribution.go index aae21e1d58e5..f77b3afc7112 100644 --- a/x-pack/metricbeat/module/gcp/distribution.go +++ b/x-pack/metricbeat/module/gcp/distribution.go @@ -53,7 +53,7 @@ func calcLinearUpperBound(bucket *distribution.Distribution_BucketOptions_Linear return bucket.Offset + (bucket.Width * float64(i)) } -func createHistogram(values []float64, counts []uint64) mapstr.M { +func createHistogram(values []float64, counts []int64) mapstr.M { return mapstr.M{ "values": values, "counts": counts, @@ -62,11 +62,11 @@ func createHistogram(values []float64, counts []uint64) mapstr.M { func DistributionHistogramToES(d *distribution.Distribution) mapstr.M { if !containsHistogram(d) { - return createHistogram([]float64{}, []uint64{}) + return createHistogram([]float64{}, []int64{}) } values := make([]float64, 0, len(d.BucketCounts)) - counts := make([]uint64, 0, len(d.BucketCounts)) + counts := make([]int64, 0, len(d.BucketCounts)) switch { case d.BucketOptions.GetExplicitBuckets() != nil: @@ -79,19 +79,17 @@ func DistributionHistogramToES(d *distribution.Distribution) mapstr.M { bucket := d.BucketOptions.GetExponentialBuckets() for i := range d.BucketCounts { - values = append(values, calcExponentialUpperBound(bucket, i+1)) + values = append(values, calcExponentialUpperBound(bucket, i)) } case d.BucketOptions.GetLinearBuckets() != nil: bucket := d.BucketOptions.GetLinearBuckets() for i := range d.BucketCounts { - values = append(values, calcLinearUpperBound(bucket, i+1)) + values = append(values, calcLinearUpperBound(bucket, i)) } } - for i := range d.BucketCounts { - counts = append(counts, uint64(d.BucketCounts[i])) - } + counts = append(counts, d.BucketCounts...) return createHistogram(values, counts) } diff --git a/x-pack/metricbeat/module/gcp/distribution_test.go b/x-pack/metricbeat/module/gcp/distribution_test.go index e2f582653beb..3838a9e9dd3a 100644 --- a/x-pack/metricbeat/module/gcp/distribution_test.go +++ b/x-pack/metricbeat/module/gcp/distribution_test.go @@ -40,7 +40,7 @@ func TestDistributionHistogramToES(t *testing.T) { }, }, expected: mapstr.M{ - "counts": []uint64{0, 0, 0, 6, 1, 1}, + "counts": []int64{0, 0, 0, 6, 1, 1}, "values": []float64{0, 1, 2, 5, 10, 20}, }, }, @@ -63,8 +63,8 @@ func TestDistributionHistogramToES(t *testing.T) { }, }, expected: mapstr.M{ - "counts": []uint64{0, 0, 3, 1}, - "values": []float64{6, 12, 24, 48}, + "counts": []int64{0, 0, 3, 1}, + "values": []float64{3, 6, 12, 24}, }, }, }, @@ -86,8 +86,8 @@ func TestDistributionHistogramToES(t *testing.T) { }, }, expected: mapstr.M{ - "counts": []uint64{0, 1, 2, 0}, - "values": []float64{20, 35, 50, 65}, + "counts": []int64{0, 1, 2, 0}, + "values": []float64{5, 20, 35, 50}, }, }, }, @@ -107,7 +107,7 @@ func TestDistributionHistogramToES(t *testing.T) { }, }, expected: mapstr.M{ - "counts": []uint64{}, + "counts": []int64{}, "values": []float64{}, }, }, diff --git a/x-pack/metricbeat/module/gcp/metrics/_meta/docs.asciidoc b/x-pack/metricbeat/module/gcp/metrics/_meta/docs.asciidoc index 642df10f4962..40dc27e80e8f 100644 --- a/x-pack/metricbeat/module/gcp/metrics/_meta/docs.asciidoc +++ b/x-pack/metricbeat/module/gcp/metrics/_meta/docs.asciidoc @@ -45,6 +45,8 @@ services under "Google Cloud metrics", but does not work for other services (`kubernetes` aka GKE for example). This option allow to override the default and specify an arbitrary metric prefix. +* *location_label*: Use this option to specify the resource label that identifies the location (such as zone or region) for a Google Cloud service when filtering metrics. For example, labels like `resource.label.location` or `resource.label.zone` are used by Google Cloud to represent the region or zone of a resource. This is an optional configuration for the user. + [float] === Example Configuration * `metrics` metricset is enabled to collect metrics from all zones under @@ -134,3 +136,28 @@ metric prefix, as for GKE metrics the required prefix is `kubernetes.io/` metric_types: - "container/cpu/core_usage_time" ---- + +* `metrics` metricset is enabled to collect metrics from region +`us-east4` in `elastic-observability` project. The metric, number of replicas of the prediction model is +collected from a new GCP service `aiplatform`. Since its a new service which is not supported by +default in this metricset, the user provides the servicelabel (resource.label.location), for which +user wants to filter the incoming data + ++ +[source,yaml] +---- +- module: gcp + metricsets: + - metrics + project_id: "elastic-observability" + credentials_json: "your JSON credentials" + exclude_labels: false + period: 1m + location_label: "resource.label.location" # This is an optional configuration + regions: + - us-east4 + metrics: + - service: aiplatform + metric_types: + - "prediction/online/replicas" +---- \ No newline at end of file diff --git a/x-pack/metricbeat/module/gcp/metrics/metrics_requester.go b/x-pack/metricbeat/module/gcp/metrics/metrics_requester.go index ad0632e6c852..915ff63190f0 100644 --- a/x-pack/metricbeat/module/gcp/metrics/metrics_requester.go +++ b/x-pack/metricbeat/module/gcp/metrics/metrics_requester.go @@ -251,7 +251,7 @@ func (r *metricsRequester) getFilterForMetric(serviceName, m string) string { // NOTE: some GCP services are global, not regional or zonal. To these services we don't need // to apply any additional filters. if locationsConfigsAvailable && !isAGlobalService(serviceName) { - serviceLabel := getServiceLabelFor(serviceName) + serviceLabel := r.getServiceLabel(serviceName) f = r.buildLocationFilter(serviceLabel, f) } @@ -261,6 +261,16 @@ func (r *metricsRequester) getFilterForMetric(serviceName, m string) string { return f } +// getServiceLabel determines the service label to be used for the given service name. If a custom +// location label is configured, it will be used. Otherwise, the default service label for the +// given service name will be returned. +func (r *metricsRequester) getServiceLabel(serviceName string) string { + if r.config.LocationLabel != "" { + return r.config.LocationLabel + } + return getServiceLabelFor(serviceName) +} + // Returns a GCP TimeInterval based on the ingestDelay and samplePeriod from ListMetricDescriptor func getTimeIntervalAligner(ingestDelay time.Duration, samplePeriod time.Duration, collectionPeriod *durationpb.Duration, inputAligner string) (*monitoringpb.TimeInterval, string) { var startTime, endTime, currentTime time.Time diff --git a/x-pack/metricbeat/module/gcp/metrics/metrics_requester_test.go b/x-pack/metricbeat/module/gcp/metrics/metrics_requester_test.go index 9fb044e39e5f..20f8a5d9e366 100644 --- a/x-pack/metricbeat/module/gcp/metrics/metrics_requester_test.go +++ b/x-pack/metricbeat/module/gcp/metrics/metrics_requester_test.go @@ -128,6 +128,13 @@ func TestGetFilterForMetric(t *testing.T) { metricsRequester{config: config{Region: "foobar", Regions: []string{"foo", "bar"}}, logger: logger}, "metric.type=\"dummy\" AND resource.labels.zone = starts_with(\"foobar\")", }, + { + "aiplatform service with configured region and zone", + "aiplatform", + "", + metricsRequester{config: config{Region: "foo", Zone: "bar", LocationLabel: "resource.label.location"}, logger: logger}, + "metric.type=\"dummy\" AND resource.label.location = starts_with(\"foo\")", + }, } for _, c := range cases { diff --git a/x-pack/metricbeat/module/gcp/metrics/metricset.go b/x-pack/metricbeat/module/gcp/metrics/metricset.go index f5b15d68fb3e..660f1936f893 100644 --- a/x-pack/metricbeat/module/gcp/metrics/metricset.go +++ b/x-pack/metricbeat/module/gcp/metrics/metricset.go @@ -103,6 +103,7 @@ type config struct { Zone string `config:"zone"` Region string `config:"region"` Regions []string `config:"regions"` + LocationLabel string `config:"location_label"` ProjectID string `config:"project_id" validate:"required"` ExcludeLabels bool `config:"exclude_labels"` CredentialsFilePath string `config:"credentials_file_path"` diff --git a/x-pack/metricbeat/module/gcp/pubsub/_meta/data_topic.json b/x-pack/metricbeat/module/gcp/pubsub/_meta/data_topic.json index 1453f9f379c7..cb6585606dfd 100644 --- a/x-pack/metricbeat/module/gcp/pubsub/_meta/data_topic.json +++ b/x-pack/metricbeat/module/gcp/pubsub/_meta/data_topic.json @@ -12,25 +12,112 @@ "module": "gcp" }, "gcp": { - "labels": { - "resource": { - "topic_id": "test-ks" - } - }, "pubsub": { "topic": { "message_sizes": { - "bucket_options": { - "Options": { - "ExponentialBuckets": { - "num_finite_buckets": 16, - "growth_factor": 4, - "scale": 1 - } + "bytes": { + "histogram": { + "values": [ + 1, + 1.2, + 1.44, + 1.728, + 2.0736, + 2.48832, + 2.9859839999999997, + 3.5831807999999996, + 4.299816959999999, + 5.159780351999999, + 6.191736422399999, + 7.430083706879999, + 8.916100448255998, + 10.699320537907198, + 12.839184645488636, + 15.407021574586365, + 18.488425889503635, + 22.18611106740436, + 26.623333280885234, + 31.94799993706228, + 38.33759992447474, + 46.00511990936968, + 55.20614389124361, + 66.24737266949234, + 79.4968472033908, + 95.39621664406897, + 114.47545997288276, + 137.3705519674593, + 164.84466236095116, + 197.8135948331414, + 237.37631379976966, + 284.8515765597236, + 341.82189187166824, + 410.18627024600187, + 492.22352429520225, + 590.6682291542427, + 708.8018749850912, + 850.5622499821095, + 1020.6746999785313, + 1224.8096399742376, + 1469.771567969085, + 1763.725881562902, + 2116.4710578754825, + 2539.7652694505787 + ], + "counts": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 10, + 3, + 2 + ] } } } } + }, + "labels": { + "resource": { + "topic_id": "test-topic" + } } }, "metricset": { diff --git a/x-pack/metricbeat/module/mssql/connection.go b/x-pack/metricbeat/module/mssql/connection.go index ac328491ddb2..cc8b0683e5ac 100644 --- a/x-pack/metricbeat/module/mssql/connection.go +++ b/x-pack/metricbeat/module/mssql/connection.go @@ -9,7 +9,7 @@ import ( "fmt" // Register driver. - _ "github.com/denisenkom/go-mssqldb" + _ "github.com/microsoft/go-mssqldb" ) // NewConnection returns a connection already established with MSSQL diff --git a/x-pack/metricbeat/module/mssql/performance/data_integration_test.go b/x-pack/metricbeat/module/mssql/performance/data_integration_test.go index 0d3d1d8fc781..0e351805d80f 100644 --- a/x-pack/metricbeat/module/mssql/performance/data_integration_test.go +++ b/x-pack/metricbeat/module/mssql/performance/data_integration_test.go @@ -5,11 +5,9 @@ package performance import ( - "errors" - "net/url" "testing" - _ "github.com/denisenkom/go-mssqldb" + _ "github.com/microsoft/go-mssqldb" "github.com/stretchr/testify/assert" mbtest "github.com/elastic/beats/v7/metricbeat/mb/testing" @@ -24,30 +22,3 @@ func TestData(t *testing.T) { err := mbtest.WriteEventsReporterV2(f, t, "") assert.NoError(t, err) } - -func getHostURI() (string, map[string]interface{}, error) { - config := mtest.GetConfig("performance") - - host, ok := config["hosts"].([]string) - if !ok { - return "", nil, errors.New("error getting host name information") - } - - username, ok := config["username"].(string) - if !ok { - return "", nil, errors.New("error getting username information") - } - - password, ok := config["password"].(string) - if !ok { - return "", nil, errors.New("error getting password information") - } - - u := &url.URL{ - Scheme: "sqlserver", - User: url.UserPassword(username, password), - Host: host[0], - } - - return u.String(), config, nil -} diff --git a/x-pack/metricbeat/module/openai/_meta/config.yml b/x-pack/metricbeat/module/openai/_meta/config.yml new file mode 100644 index 000000000000..a34fd7b183de --- /dev/null +++ b/x-pack/metricbeat/module/openai/_meta/config.yml @@ -0,0 +1,34 @@ +- module: openai + metricsets: ["usage"] + enabled: false + period: 1h + + # # Project API Keys - Multiple API keys can be specified for different projects + # api_keys: + # - key: "api_key1" + # - key: "api_key2" + + # # API Configuration + # ## Base URL for the OpenAI usage API endpoint + # api_url: "https://api.openai.com/v1/usage" + # ## Custom headers to be included in API requests + # headers: + # - "k1: v1" + # - "k2: v2" + ## Rate Limiting Configuration + # rate_limit: + # limit: 12 # seconds between requests + # burst: 1 # max concurrent requests + # ## Request Timeout Duration + # timeout: 30s + + # # Data Collection Configuration + # collection: + # ## Number of days to look back when collecting usage data + # lookback_days: 30 + # ## Whether to collect usage data in realtime. Defaults to false as how + # # OpenAI usage data is collected will end up adding duplicate data to ES + # # and also making it harder to do analytics. Best approach is to avoid + # # realtime collection and collect only upto last day (in UTC). So, there's + # # at most 24h delay. + # realtime: false diff --git a/x-pack/metricbeat/module/openai/_meta/docs.asciidoc b/x-pack/metricbeat/module/openai/_meta/docs.asciidoc new file mode 100644 index 000000000000..744909c7a1ab --- /dev/null +++ b/x-pack/metricbeat/module/openai/_meta/docs.asciidoc @@ -0,0 +1,2 @@ +This is the openai module. + diff --git a/x-pack/metricbeat/module/openai/_meta/fields.yml b/x-pack/metricbeat/module/openai/_meta/fields.yml new file mode 100644 index 000000000000..d514eb010f15 --- /dev/null +++ b/x-pack/metricbeat/module/openai/_meta/fields.yml @@ -0,0 +1,10 @@ +- key: openai + title: "openai" + release: beta + description: > + openai module + fields: + - name: openai + type: group + description: > + fields: diff --git a/x-pack/metricbeat/module/openai/doc.go b/x-pack/metricbeat/module/openai/doc.go new file mode 100644 index 000000000000..5f2f07fb0bca --- /dev/null +++ b/x-pack/metricbeat/module/openai/doc.go @@ -0,0 +1,6 @@ +// 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 openai is a Metricbeat module that contains MetricSets. +package openai diff --git a/x-pack/metricbeat/module/openai/fields.go b/x-pack/metricbeat/module/openai/fields.go new file mode 100644 index 000000000000..de875dbdaab1 --- /dev/null +++ b/x-pack/metricbeat/module/openai/fields.go @@ -0,0 +1,23 @@ +// 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. + +// Code generated by beats/dev-tools/cmd/asset/asset.go - DO NOT EDIT. + +package openai + +import ( + "github.com/elastic/beats/v7/libbeat/asset" +) + +func init() { + if err := asset.SetFields("metricbeat", "openai", asset.ModuleFieldsPri, AssetOpenai); err != nil { + panic(err) + } +} + +// AssetOpenai returns asset data. +// This is the base64 encoded zlib format compressed contents of module/openai. +func AssetOpenai() string { + return "eJzsWMtu4zgQvPsrGtnL7sHYuw8BjOwDAbKbIMlgjgIttmWOKVJDtuI4Xz+gJNp6UHZsyRMEGB5FsqpZrK6YmcIatzPQGSomJgAkSOIMrsoPVxMAgxKZxRkskNgEgKONjchIaDWD6wkAVLsh1TyXOAFYCpTczoq5KSiWYo3BDdpmOIPE6DyrvgRQmzh1rNyyBHdfQ3ButAv3I0hVjvsM1fwW5g+3JQekSEbEFpjiYImRsCRiW9vTLtGN3+BGp6lWsGAWqxXACIzWBBJfUDaW7xQyCVPijbnCIsEba/wZ17jdaNOea5zovgYDgqMisRRojlO6T6OQdoA8HctEtMbtgMO5m1nj9ti5PNGQI3mqo6cxyFlMePaZHqv9nvEgmUM9l+h5myHo5UGezOhvGNOAK3ooEY5dkScackWeqoHRbcVMolv/582KUdXXnDUiYV9WZ6IvXTrFXLcmAf5FhYbJGqXPk9bSUIjUizL4PUdLNiJNTHaW+RKlVklgslHl/3m6QONc4EEhZbx9A43YNkVX97KG76lDfO+BIGDhPZ9VLLMrHTDgyYxPFVSfE+u0sVaErxSRXqMaQ+dnhwBqp3ZFACUB5LaTF/tiksI3hPxy5ewoqoL6hWHxCnl0eX0KnpZMvVVhykQ//zv98cWi6UFqNV4odU+m8+lbYfbl1V/zu7vp3yBSlxnVNbmuCSXHPrSkDIfoGalVFdD5DXRiZqk8jYpDdG/xvLwqwfbO/Zi07GUtyouseBtslCfxhs0e7dHxozI6t2hGyOei/96RzanmKEfg+8/hhAhbHfh1JWyGBmyGGK+mpKdFJB1qwE25ZawW9BUM7cGLK9cmdE1vMdaKj9X1FZr7uRijPfRX82Pa/sK90LLmM76SM+RTYc2DlqRO0WfbscX6KV0Zr5hxrywzljH3gL+8WXhzzrlwG5gsnzqOw8Lvhm3AkjYswT+CRl1SNOaj6x+hcEq5EioZ8uTSRiRCHbgrvXBPz8B0ORGdJPEj28CyVXhY593/A6wVlpiiKNYcI6EITWaQxvsjNPcMcKM5wu2eYVD3/3xhd1KBkwpqUr1DZ+MOiS9MRpWJx5L30QP77vhkqppO/YWYPwIAAP//Z/rS7Q==" +} diff --git a/x-pack/metricbeat/module/openai/usage/_meta/data.json b/x-pack/metricbeat/module/openai/usage/_meta/data.json new file mode 100644 index 000000000000..da78c73e036f --- /dev/null +++ b/x-pack/metricbeat/module/openai/usage/_meta/data.json @@ -0,0 +1,37 @@ +{ + "@timestamp": "2017-10-12T08:05:34.853Z", + "event": { + "dataset": "openai.usage", + "duration": 115000, + "module": "openai" + }, + "metricset": { + "name": "usage", + "period": 10000 + }, + "openai": { + "usage": { + "api_key_id": null, + "api_key_name": null, + "api_key_redacted": null, + "api_key_type": null, + "data": { + "cached_context_tokens_total": 0, + "context_tokens_total": 118, + "email": null, + "generated_tokens_total": 35, + "operation": "completion-realtime", + "request_type": "", + "requests_total": 1, + "snapshot_id": "gpt-4o-realtime-preview-2024-10-01" + }, + "organization_id": "org-dummy", + "organization_name": "Personal", + "project_id": null, + "project_name": null + } + }, + "service": { + "type": "openai" + } +} \ No newline at end of file diff --git a/x-pack/metricbeat/module/openai/usage/_meta/docs.asciidoc b/x-pack/metricbeat/module/openai/usage/_meta/docs.asciidoc new file mode 100644 index 000000000000..dc88baf82a09 --- /dev/null +++ b/x-pack/metricbeat/module/openai/usage/_meta/docs.asciidoc @@ -0,0 +1 @@ +This is the usage metricset of the module openai. diff --git a/x-pack/metricbeat/module/openai/usage/_meta/fields.yml b/x-pack/metricbeat/module/openai/usage/_meta/fields.yml new file mode 100644 index 000000000000..c25fe30c17bb --- /dev/null +++ b/x-pack/metricbeat/module/openai/usage/_meta/fields.yml @@ -0,0 +1,156 @@ +- name: usage + type: group + release: beta + description: > + OpenAI API usage metrics and statistics + fields: + # Common base fields at root level + - name: organization_id + type: keyword + description: Organization identifier + - name: organization_name + type: keyword + description: Organization name + - name: api_key_id + type: keyword + description: API key identifier + - name: api_key_name + type: keyword + description: API key name + - name: api_key_redacted + type: keyword + description: Redacted API key + - name: api_key_type + type: keyword + description: Type of API key + - name: project_id + type: keyword + description: Project identifier + - name: project_name + type: keyword + description: Project name + + # Completion/Chat usage data + - name: data + type: group + description: > + General usage data metrics + fields: + - name: requests_total + type: long + description: Number of requests made + - name: operation + type: keyword + description: Operation type + - name: snapshot_id + type: keyword + description: Snapshot identifier + - name: context_tokens_total + type: long + description: Total number of context tokens used + - name: generated_tokens_total + type: long + description: Total number of generated tokens + - name: cached_context_tokens_total + type: long + description: Total number of cached context tokens + - name: email + type: keyword + description: User email + - name: request_type + type: keyword + description: Type of request + + # DALL-E image generation metrics + - name: dalle + type: group + description: > + DALL-E API usage metrics + fields: + - name: num_images + type: long + description: Number of images generated + - name: requests_total + type: long + description: Number of requests + - name: image_size + type: keyword + description: Size of generated images + - name: operation + type: keyword + description: Operation type + - name: user_id + type: keyword + description: User identifier + - name: model_id + type: keyword + description: Model identifier + + # Whisper speech-to-text metrics + - name: whisper + type: group + description: > + Whisper API usage metrics + fields: + - name: model_id + type: keyword + description: Model identifier + - name: num_seconds + type: long + description: Number of seconds processed + - name: requests_total + type: long + description: Number of requests + - name: user_id + type: keyword + description: User identifier + + # Text-to-Speech metrics + - name: tts + type: group + description: > + Text-to-Speech API usage metrics + fields: + - name: model_id + type: keyword + description: Model identifier + - name: num_characters + type: long + description: Number of characters processed + - name: requests_total + type: long + description: Number of requests + - name: user_id + type: keyword + description: User identifier + + # Additional data types (raw storage) + - name: ft_data + type: group + description: > + Fine-tuning data metrics + fields: + - name: original + type: object + object_type: keyword + description: Raw fine-tuning data + + - name: assistant_code_interpreter + type: group + description: > + Assistant Code Interpreter usage metrics + fields: + - name: original + type: object + object_type: keyword + description: Raw assistant code interpreter data + + - name: retrieval_storage + type: group + description: > + Retrieval storage usage metrics + fields: + - name: original + type: object + object_type: keyword + description: Raw retrieval storage data diff --git a/x-pack/metricbeat/module/openai/usage/client.go b/x-pack/metricbeat/module/openai/usage/client.go new file mode 100644 index 000000000000..3995386c30e7 --- /dev/null +++ b/x-pack/metricbeat/module/openai/usage/client.go @@ -0,0 +1,71 @@ +// 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 usage + +import ( + "fmt" + "net/http" + "time" + + "golang.org/x/time/rate" + + "github.com/elastic/elastic-agent-libs/logp" +) + +// RLHTTPClient wraps the standard http.Client with a rate limiter to control API request frequency. +type RLHTTPClient struct { + client *http.Client + logger *logp.Logger + Ratelimiter *rate.Limiter +} + +// Do executes an HTTP request while respecting rate limits. +// It waits for rate limit token before proceeding with the request. +// Returns the HTTP response and any error encountered. +func (c *RLHTTPClient) Do(req *http.Request) (*http.Response, error) { + start := time.Now() + + c.logger.Debug("Waiting for rate limit token") + + err := c.Ratelimiter.Wait(req.Context()) + if err != nil { + return nil, fmt.Errorf("failed to acquire rate limit token: %w", err) + } + + c.logger.Debug("Rate limit token acquired") + + waitDuration := time.Since(start) + + if waitDuration > time.Minute { + c.logger.Infof("Rate limit wait exceeded threshold: %v", waitDuration) + } + + resp, err := c.client.Do(req) + if err != nil { + return nil, fmt.Errorf("failed to execute request: %w", err) + } + + return resp, nil +} + +// newClient creates a new rate-limited HTTP client with specified rate limiter and timeout. +func newClient(logger *logp.Logger, rl *rate.Limiter, timeout time.Duration) *RLHTTPClient { + transport := &http.Transport{ + MaxIdleConns: 100, + MaxIdleConnsPerHost: 100, + IdleConnTimeout: 90 * time.Second, + } + + client := &http.Client{ + Timeout: timeout, + Transport: transport, + } + + return &RLHTTPClient{ + client: client, + logger: logger, + Ratelimiter: rl, + } +} diff --git a/x-pack/metricbeat/module/openai/usage/config.go b/x-pack/metricbeat/module/openai/usage/config.go new file mode 100644 index 000000000000..f930a0137476 --- /dev/null +++ b/x-pack/metricbeat/module/openai/usage/config.go @@ -0,0 +1,94 @@ +// 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 usage + +import ( + "errors" + "fmt" + "net/url" + "time" +) + +type Config struct { + APIKeys []apiKeyConfig `config:"api_keys" validate:"required"` + APIURL string `config:"api_url" validate:"required"` + Headers []string `config:"headers"` + RateLimit *rateLimitConfig `config:"rate_limit"` + Timeout time.Duration `config:"timeout" validate:"required"` + Collection collectionConfig `config:"collection"` +} + +type rateLimitConfig struct { + Limit *int `config:"limit" validate:"required"` + Burst *int `config:"burst" validate:"required"` +} + +type apiKeyConfig struct { + Key string `config:"key" validate:"required"` +} + +type collectionConfig struct { + LookbackDays int `config:"lookback_days"` + Realtime bool `config:"realtime"` +} + +func defaultConfig() Config { + return Config{ + APIURL: "https://api.openai.com/v1/usage", + Timeout: 30 * time.Second, + RateLimit: &rateLimitConfig{ + Limit: ptr(12), + Burst: ptr(1), + }, + Collection: collectionConfig{ + LookbackDays: 0, // 0 days + Realtime: false, // avoid realtime collection by default + }, + } +} + +func (c *Config) Validate() error { + var errs []error + + if len(c.APIKeys) == 0 { + errs = append(errs, errors.New("at least one API key must be configured")) + } + if c.APIURL == "" { + errs = append(errs, errors.New("api_url cannot be empty")) + } else { + _, err := url.ParseRequestURI(c.APIURL) + if err != nil { + errs = append(errs, fmt.Errorf("invalid api_url format: %w", err)) + } + } + if c.RateLimit == nil { + errs = append(errs, errors.New("rate_limit must be configured")) + } else { + if c.RateLimit.Limit == nil { + errs = append(errs, errors.New("rate_limit.limit must be configured")) + } + if c.RateLimit.Burst == nil { + errs = append(errs, errors.New("rate_limit.burst must be configured")) + } + } + if c.Timeout <= 0 { + errs = append(errs, errors.New("timeout must be greater than 0")) + } + if c.Collection.LookbackDays < 0 { + errs = append(errs, errors.New("lookback_days must be >= 0")) + } + + for i, apiKey := range c.APIKeys { + if apiKey.Key == "" { + errs = append(errs, fmt.Errorf("API key at position %d cannot be empty", i)) + } + } + + if len(errs) > 0 { + return fmt.Errorf("validation failed: %w", errors.Join(errs...)) + } + + return nil +} diff --git a/x-pack/functionbeat/provider/local/include/feature.go b/x-pack/metricbeat/module/openai/usage/errors.go similarity index 53% rename from x-pack/functionbeat/provider/local/include/feature.go rename to x-pack/metricbeat/module/openai/usage/errors.go index d5eed566826a..9b8b793767c0 100644 --- a/x-pack/functionbeat/provider/local/include/feature.go +++ b/x-pack/metricbeat/module/openai/usage/errors.go @@ -2,13 +2,9 @@ // or more contributor license agreements. Licensed under the Elastic License; // you may not use this file except in compliance with the Elastic License. -package include +package usage -import ( - "github.com/elastic/beats/v7/libbeat/feature" - "github.com/elastic/beats/v7/x-pack/functionbeat/provider/local/local" -) +import "errors" -func init() { - feature.MustRegister(local.Features...) -} +// ErrNoState indicates no previous state exists for the given API key +var ErrNoState = errors.New("no previous state found") diff --git a/x-pack/metricbeat/module/openai/usage/helper.go b/x-pack/metricbeat/module/openai/usage/helper.go new file mode 100644 index 000000000000..992c025df8cc --- /dev/null +++ b/x-pack/metricbeat/module/openai/usage/helper.go @@ -0,0 +1,30 @@ +// 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 usage + +import "strings" + +// dateFormatForStateStore is used to parse and format dates in the YYYY-MM-DD format +const dateFormatForStateStore = "2006-01-02" + +func ptr[T any](value T) *T { + return &value +} + +func processHeaders(headers []string) map[string]string { + headersMap := make(map[string]string, len(headers)) + for _, header := range headers { + parts := strings.SplitN(header, ":", 2) + if len(parts) != 2 { + continue + } + k, v := strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]) + if k == "" || v == "" { + continue + } + headersMap[k] = v + } + return headersMap +} diff --git a/x-pack/metricbeat/module/openai/usage/persistcache.go b/x-pack/metricbeat/module/openai/usage/persistcache.go new file mode 100644 index 000000000000..51a8d6fb0f89 --- /dev/null +++ b/x-pack/metricbeat/module/openai/usage/persistcache.go @@ -0,0 +1,187 @@ +// 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 usage + +import ( + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + "os" + "path" + "strings" + "sync" + "time" +) + +// stateManager handles the storage and retrieval of state data with key hashing and caching capabilities +type stateManager struct { + mu sync.RWMutex + store *stateStore + keyPrefix string + hashCache sync.Map +} + +// stateStore handles persistence of key-value pairs using the filesystem +type stateStore struct { + Dir string // Base directory for storing state files + mu sync.RWMutex +} + +// newStateManager creates a new state manager instance with the given storage path +func newStateManager(storePath string) (*stateManager, error) { + if strings.TrimSpace(storePath) == "" { + return nil, errors.New("empty path provided") + } + + store, err := newStateStore(storePath) + if err != nil { + return nil, fmt.Errorf("create state store: %w", err) + } + + return &stateManager{ + mu: sync.RWMutex{}, + store: store, + keyPrefix: "state_", + hashCache: sync.Map{}, + }, nil +} + +// newStateStore creates a new state store instance at the specified path +func newStateStore(path string) (*stateStore, error) { + if err := os.MkdirAll(path, 0o755); err != nil { + return nil, fmt.Errorf("creating state directory: %w", err) + } + return &stateStore{ + Dir: path, + }, nil +} + +// getStatePath builds the full file path for a given state key +func (s *stateStore) getStatePath(name string) string { + return path.Join(s.Dir, name) +} + +// Put stores a value in a file named by the key +func (s *stateStore) Put(key, value string) error { + s.mu.Lock() + defer s.mu.Unlock() + + filePath := s.getStatePath(key) + + // In case the file already exists, file is truncated. + f, err := os.Create(filePath) + if err != nil { + return fmt.Errorf("creating state file: %w", err) + } + defer f.Close() + + _, err = f.WriteString(value) + if err != nil { + return fmt.Errorf("writing value to state file: %w", err) + } + + if err = f.Sync(); err != nil { + return fmt.Errorf("syncing state file: %w", err) + } + + return nil +} + +// Get retrieves the value stored in the file named by the key +func (s *stateStore) Get(key string) (string, error) { + s.mu.RLock() + defer s.mu.RUnlock() + + filePath := s.getStatePath(key) + data, err := os.ReadFile(filePath) + if err != nil { + return "", fmt.Errorf("reading state file: %w", err) + } + return string(data), nil +} + +// Has checks if a state exists for the given key +func (s *stateStore) Has(key string) bool { + s.mu.RLock() + defer s.mu.RUnlock() + + filePath := s.getStatePath(key) + _, err := os.Stat(filePath) + return err == nil +} + +// Remove deletes the state file for the given key +func (s *stateStore) Remove(key string) error { + s.mu.Lock() + defer s.mu.Unlock() + + filePath := s.getStatePath(key) + if err := os.Remove(filePath); err != nil && !os.IsNotExist(err) { + return fmt.Errorf("removing state file: %w", err) + } + return nil +} + +// Clear removes all state files by deleting and recreating the state directory +func (s *stateStore) Clear() error { + s.mu.Lock() + defer s.mu.Unlock() + + if err := os.RemoveAll(s.Dir); err != nil { + return fmt.Errorf("clearing state directory: %w", err) + } + return os.MkdirAll(s.Dir, 0o755) +} + +// GetLastProcessedDate retrieves and parses the last processed date for a given API key +func (s *stateManager) GetLastProcessedDate(apiKey string) (time.Time, error) { + s.mu.RLock() + defer s.mu.RUnlock() + + stateKey := s.GetStateKey(apiKey) + + if !s.store.Has(stateKey) { + return time.Time{}, ErrNoState + } + + dateStr, err := s.store.Get(stateKey) + if err != nil { + return time.Time{}, fmt.Errorf("get state: %w", err) + } + + return time.Parse(dateFormatForStateStore, dateStr) +} + +// SaveState saves the last processed date for a given API key +func (s *stateManager) SaveState(apiKey, dateStr string) error { + s.mu.Lock() + defer s.mu.Unlock() + + stateKey := s.GetStateKey(apiKey) + return s.store.Put(stateKey, dateStr) +} + +// hashKey generates and caches a SHA-256 hash of the provided API key +func (s *stateManager) hashKey(apiKey string) string { + // Check cache first to avoid recomputing hashes + if hashedKey, ok := s.hashCache.Load(apiKey); ok { + return hashedKey.(string) + } + + // Generate SHA-256 hash and hex encode for safe filename usage + hasher := sha256.New() + _, _ = hasher.Write([]byte(apiKey)) + hashedKey := hex.EncodeToString(hasher.Sum(nil)) + + // Cache the computed hash for future lookups + s.hashCache.Store(apiKey, hashedKey) + return hashedKey +} + +// GetStateKey generates a unique state key for a given API key +func (s *stateManager) GetStateKey(apiKey string) string { + return s.keyPrefix + s.hashKey(apiKey) +} diff --git a/x-pack/metricbeat/module/openai/usage/schema.go b/x-pack/metricbeat/module/openai/usage/schema.go new file mode 100644 index 000000000000..64f22393e590 --- /dev/null +++ b/x-pack/metricbeat/module/openai/usage/schema.go @@ -0,0 +1,69 @@ +// 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 usage + +type BaseData struct { + OrganizationID string `json:"organization_id"` + OrganizationName string `json:"organization_name"` + ApiKeyID *string `json:"api_key_id"` + ApiKeyName *string `json:"api_key_name"` + ApiKeyRedacted *string `json:"api_key_redacted"` + ApiKeyType *string `json:"api_key_type"` + ProjectID *string `json:"project_id"` + ProjectName *string `json:"project_name"` +} + +type UsageResponse struct { + Object string `json:"object"` + Data []UsageData `json:"data"` + FtData []interface{} `json:"ft_data"` + DalleApiData []DalleData `json:"dalle_api_data"` + WhisperApiData []WhisperData `json:"whisper_api_data"` + TtsApiData []TtsData `json:"tts_api_data"` + AssistantCodeInterpreterData []interface{} `json:"assistant_code_interpreter_data"` + RetrievalStorageData []interface{} `json:"retrieval_storage_data"` +} + +type UsageData struct { + BaseData + AggregationTimestamp int64 `json:"aggregation_timestamp"` + NRequests int `json:"n_requests"` + Operation string `json:"operation"` + SnapshotID string `json:"snapshot_id"` + NContextTokensTotal int `json:"n_context_tokens_total"` + NGeneratedTokensTotal int `json:"n_generated_tokens_total"` + Email *string `json:"email"` + RequestType string `json:"request_type"` + NCachedContextTokensTotal int `json:"n_cached_context_tokens_total"` +} + +type DalleData struct { + BaseData + Timestamp int64 `json:"timestamp"` + NumImages int `json:"num_images"` + NumRequests int `json:"num_requests"` + ImageSize string `json:"image_size"` + Operation string `json:"operation"` + ModelID string `json:"model_id"` + UserID string `json:"user_id"` +} + +type WhisperData struct { + BaseData + Timestamp int64 `json:"timestamp"` + ModelID string `json:"model_id"` + NumSeconds int `json:"num_seconds"` + NumRequests int `json:"num_requests"` + UserID string `json:"user_id"` +} + +type TtsData struct { + BaseData + Timestamp int64 `json:"timestamp"` + ModelID string `json:"model_id"` + NumCharacters int `json:"num_characters"` + NumRequests int `json:"num_requests"` + UserID string `json:"user_id"` +} diff --git a/x-pack/metricbeat/module/openai/usage/usage.go b/x-pack/metricbeat/module/openai/usage/usage.go new file mode 100644 index 000000000000..86dbe76ce815 --- /dev/null +++ b/x-pack/metricbeat/module/openai/usage/usage.go @@ -0,0 +1,387 @@ +// 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 usage + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "net" + "net/http" + "path" + "time" + + "golang.org/x/sync/errgroup" + "golang.org/x/time/rate" + + "github.com/elastic/beats/v7/libbeat/common/cfgwarn" + "github.com/elastic/beats/v7/metricbeat/mb" + "github.com/elastic/elastic-agent-libs/logp" + "github.com/elastic/elastic-agent-libs/mapstr" + "github.com/elastic/elastic-agent-libs/paths" +) + +// init registers the MetricSet with the central registry as soon as the program +// starts. The New function will be called later to instantiate an instance of +// the MetricSet for each host is defined in the module's configuration. After the +// MetricSet has been created then Fetch will begin to be called periodically. +func init() { + mb.Registry.MustAddMetricSet("openai", "usage", New) +} + +// MetricSet holds any configuration or state information. It must implement +// the mb.MetricSet interface. And this is best achieved by embedding +// mb.BaseMetricSet because it implements all of the required mb.MetricSet +// interface methods except for Fetch. +type MetricSet struct { + mb.BaseMetricSet + httpClient *RLHTTPClient + logger *logp.Logger + config Config + report mb.ReporterV2 + stateManager *stateManager + headers map[string]string +} + +// New creates a new instance of the MetricSet. New is responsible for unpacking +// any MetricSet specific configuration options if there are any. +func New(base mb.BaseMetricSet) (mb.MetricSet, error) { + cfgwarn.Beta("The openai usage metricset is beta.") + + config := defaultConfig() + if err := base.Module().UnpackConfig(&config); err != nil { + return nil, err + } + + if err := config.Validate(); err != nil { + return nil, err + } + + sm, err := newStateManager(paths.Resolve(paths.Data, path.Join("state", base.Module().Name(), base.Name()))) + if err != nil { + return nil, fmt.Errorf("create state manager: %w", err) + } + + logger := logp.NewLogger("openai.usage") + + httpClient := newClient( + logger, + rate.NewLimiter( + rate.Every(time.Duration(*config.RateLimit.Limit)*time.Second), + *config.RateLimit.Burst, + ), + config.Timeout, + ) + + return &MetricSet{ + BaseMetricSet: base, + httpClient: httpClient, + logger: logger, + config: config, + stateManager: sm, + headers: processHeaders(config.Headers), + }, nil +} + +// Fetch collects OpenAI API usage data for the configured time range. +// +// The collection process: +// 1. Determines the time range based on realtime/non-realtime configuration +// 2. Calculates start date using configured lookback days +// 3. Fetches usage data for each day in the range +// 4. Reports collected metrics through the mb.ReporterV2 +func (m *MetricSet) Fetch(report mb.ReporterV2) error { + endDate := time.Now().UTC().Truncate(time.Hour * 24) // truncate to day as we only collect daily data + + if !m.config.Collection.Realtime { + // If we're not collecting realtime data, then just pull until + // yesterday (in UTC). + endDate = endDate.AddDate(0, 0, -1) + } + + startDate := endDate.AddDate(0, 0, -m.config.Collection.LookbackDays) + + m.report = report + return m.fetchDateRange(startDate, endDate, m.httpClient) +} + +// fetchDateRange retrieves OpenAI API usage data for each configured API key within a date range. +// +// For each API key: +// 1. Retrieves last processed date from state store +// 2. Adjusts collection range to avoid duplicates +// 3. Collects daily usage data +// 4. Updates state store with latest processed date +// 5. Handles errors per day without failing entire range +func (m *MetricSet) fetchDateRange(startDate, endDate time.Time, httpClient *RLHTTPClient) error { + g, ctx := errgroup.WithContext(context.TODO()) + + for i := range m.config.APIKeys { + apiKey := m.config.APIKeys[i] + apiKeyIdx := i + 1 + g.Go(func() error { + lastProcessedDate, err := m.stateManager.GetLastProcessedDate(apiKey.Key) + if err == nil { + currentStartDate := lastProcessedDate.AddDate(0, 0, 1) + if currentStartDate.After(endDate) { + m.logger.Infof("Skipping API key #%d as current start date (%s) is after end date (%s)", apiKeyIdx, currentStartDate, endDate) + return nil + } + startDate = currentStartDate + } + + m.logger.Debugf("Fetching data for API key #%d from %s to %s", apiKeyIdx, startDate, endDate) + + for d := startDate; !d.After(endDate); d = d.AddDate(0, 0, 1) { + select { + case <-ctx.Done(): + return ctx.Err() + default: + dateStr := d.Format(dateFormatForStateStore) + if err := m.fetchSingleDay(apiKeyIdx, dateStr, apiKey.Key, httpClient); err != nil { + // If there's an error, log it and continue to the next day. + // In this case, we are not saving the state. + m.logger.Errorf("Error fetching data (api key #%d) for date %s: %v", apiKeyIdx, dateStr, err) + continue + } + if err := m.stateManager.SaveState(apiKey.Key, dateStr); err != nil { + m.logger.Errorf("Error storing state for API key: %v at index %d", err, apiKeyIdx) + } + } + } + return nil + }) + } + + if err := g.Wait(); err != nil { + m.logger.Errorf("Error fetching data: %v", err) + } + + return nil +} + +// fetchSingleDay retrieves usage data for a specific date and API key. +func (m *MetricSet) fetchSingleDay(apiKeyIdx int, dateStr, apiKey string, httpClient *RLHTTPClient) error { + req, err := m.createRequest(dateStr, apiKey) + if err != nil { + return fmt.Errorf("error creating request: %w", err) + } + + resp, err := httpClient.Do(req) + if err != nil { + var netErr net.Error + if errors.As(err, &netErr) && netErr.Timeout() { + return fmt.Errorf("request timed out with configured timeout: %v and error: %w", m.config.Timeout, err) + } + return fmt.Errorf("error making request: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("error response from API: status=%s", resp.Status) + } + + return m.processResponse(apiKeyIdx, resp, dateStr) +} + +// createRequest builds an HTTP request for the OpenAI usage API. +func (m *MetricSet) createRequest(dateStr, apiKey string) (*http.Request, error) { + req, err := http.NewRequestWithContext(context.TODO(), http.MethodGet, m.config.APIURL, nil) + if err != nil { + return nil, fmt.Errorf("error creating request: %w", err) + } + + q := req.URL.Query() + q.Add("date", dateStr) + req.URL.RawQuery = q.Encode() + + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", apiKey)) + for key, value := range m.headers { + req.Header.Add(key, value) + } + + return req, nil +} + +// processResponse handles the API response and processes the usage data. +func (m *MetricSet) processResponse(apiKeyIdx int, resp *http.Response, dateStr string) error { + var usageResponse UsageResponse + if err := json.NewDecoder(resp.Body).Decode(&usageResponse); err != nil { + return fmt.Errorf("error decoding response: %w", err) + } + + m.logger.Infof("Fetching usage metrics (api key #%d) for date: %s", apiKeyIdx, dateStr) + + m.processUsageData(usageResponse.Data) + m.processDalleData(usageResponse.DalleApiData) + m.processWhisperData(usageResponse.WhisperApiData) + m.processTTSData(usageResponse.TtsApiData) + + // Process additional data. + // + // NOTE(shmsr): During testing, could not get the usage data for the following + // and found no documentation, example responses, etc. That's why let's store them + // as it is so that we can use processors later on to process them as needed. + m.processFTData(usageResponse.FtData) + m.processAssistantCodeInterpreterData(usageResponse.AssistantCodeInterpreterData) + m.processRetrievalStorageData(usageResponse.RetrievalStorageData) + + return nil +} + +func getBaseFields(data BaseData) mapstr.M { + return mapstr.M{ + "organization_id": data.OrganizationID, + "organization_name": data.OrganizationName, + "api_key_id": data.ApiKeyID, + "api_key_name": data.ApiKeyName, + "api_key_redacted": data.ApiKeyRedacted, + "api_key_type": data.ApiKeyType, + "project_id": data.ProjectID, + "project_name": data.ProjectName, + } +} + +func (m *MetricSet) processUsageData(data []UsageData) { + events := make([]mb.Event, 0, len(data)) + for _, usage := range data { + event := mb.Event{ + Timestamp: time.Unix(usage.AggregationTimestamp, 0).UTC(), // epoch time to time.Time (UTC) + MetricSetFields: mapstr.M{ + "data": mapstr.M{ + "requests_total": usage.NRequests, + "operation": usage.Operation, + "snapshot_id": usage.SnapshotID, + "context_tokens_total": usage.NContextTokensTotal, + "generated_tokens_total": usage.NGeneratedTokensTotal, + "email": usage.Email, + "request_type": usage.RequestType, + "cached_context_tokens_total": usage.NCachedContextTokensTotal, + }, + }, + } + event.MetricSetFields.DeepUpdate(getBaseFields(usage.BaseData)) + events = append(events, event) + } + m.processEvents(events) +} + +func (m *MetricSet) processDalleData(data []DalleData) { + events := make([]mb.Event, 0, len(data)) + for _, dalle := range data { + event := mb.Event{ + Timestamp: time.Unix(dalle.Timestamp, 0).UTC(), // epoch time to time.Time (UTC) + MetricSetFields: mapstr.M{ + "dalle": mapstr.M{ + "num_images": dalle.NumImages, + "requests_total": dalle.NumRequests, + "image_size": dalle.ImageSize, + "operation": dalle.Operation, + "user_id": dalle.UserID, + "model_id": dalle.ModelID, + }, + }, + } + event.MetricSetFields.DeepUpdate(getBaseFields(dalle.BaseData)) + events = append(events, event) + } + m.processEvents(events) +} + +func (m *MetricSet) processWhisperData(data []WhisperData) { + events := make([]mb.Event, 0, len(data)) + for _, whisper := range data { + event := mb.Event{ + Timestamp: time.Unix(whisper.Timestamp, 0).UTC(), // epoch time to time.Time (UTC) + MetricSetFields: mapstr.M{ + "whisper": mapstr.M{ + "model_id": whisper.ModelID, + "num_seconds": whisper.NumSeconds, + "requests_total": whisper.NumRequests, + "user_id": whisper.UserID, + }, + }, + } + event.MetricSetFields.DeepUpdate(getBaseFields(whisper.BaseData)) + events = append(events, event) + } + m.processEvents(events) +} + +func (m *MetricSet) processTTSData(data []TtsData) { + events := make([]mb.Event, 0, len(data)) + for _, tts := range data { + event := mb.Event{ + Timestamp: time.Unix(tts.Timestamp, 0).UTC(), // epoch time to time.Time (UTC) + MetricSetFields: mapstr.M{ + "tts": mapstr.M{ + "model_id": tts.ModelID, + "num_characters": tts.NumCharacters, + "requests_total": tts.NumRequests, + "user_id": tts.UserID, + }, + }, + } + event.MetricSetFields.DeepUpdate(getBaseFields(tts.BaseData)) + events = append(events, event) + } + + m.processEvents(events) +} + +func (m *MetricSet) processFTData(data []interface{}) { + events := make([]mb.Event, 0, len(data)) + for _, ft := range data { + event := mb.Event{ + MetricSetFields: mapstr.M{ + "ft_data": mapstr.M{ + "original": ft, + }, + }, + } + events = append(events, event) + } + m.processEvents(events) +} + +func (m *MetricSet) processAssistantCodeInterpreterData(data []interface{}) { + events := make([]mb.Event, 0, len(data)) + for _, aci := range data { + event := mb.Event{ + MetricSetFields: mapstr.M{ + "assistant_code_interpreter": mapstr.M{ + "original": aci, + }, + }, + } + events = append(events, event) + } + m.processEvents(events) +} + +func (m *MetricSet) processRetrievalStorageData(data []interface{}) { + events := make([]mb.Event, 0, len(data)) + for _, rs := range data { + event := mb.Event{ + MetricSetFields: mapstr.M{ + "retrieval_storage": mapstr.M{ + "original": rs, + }, + }, + } + events = append(events, event) + } + m.processEvents(events) +} + +func (m *MetricSet) processEvents(events []mb.Event) { + if len(events) == 0 { + return + } + for i := range events { + m.report.Event(events[i]) + } +} diff --git a/x-pack/metricbeat/module/openai/usage/usage_integration_test.go b/x-pack/metricbeat/module/openai/usage/usage_integration_test.go new file mode 100644 index 000000000000..8cb842419955 --- /dev/null +++ b/x-pack/metricbeat/module/openai/usage/usage_integration_test.go @@ -0,0 +1,482 @@ +// 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. + +//go:build integration + +package usage + +import ( + "fmt" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/elastic/beats/v7/metricbeat/mb" + mbtest "github.com/elastic/beats/v7/metricbeat/mb/testing" + "github.com/elastic/elastic-agent-libs/mapstr" +) + +func TestFetch(t *testing.T) { + apiKey := time.Now().String() // to generate a unique API key everytime to ignore the stateStore + usagePath := "/usage" + server := initServer(usagePath, apiKey) + defer server.Close() + + tests := []struct { + name string + expected mb.Event + }{ + { + name: "tc: #1", + expected: mb.Event{ + RootFields: nil, + ModuleFields: nil, + MetricSetFields: mapstr.M{ + "api_key_id": (*string)(nil), + "api_key_name": (*string)(nil), + "api_key_redacted": (*string)(nil), + "api_key_type": (*string)(nil), + "data": mapstr.M{ + "email": (*string)(nil), + "cached_context_tokens_total": 0, + "context_tokens_total": 118, + "generated_tokens_total": 35, + "requests_total": 1, + "operation": "completion-realtime", + "request_type": "", + "snapshot_id": "gpt-4o-realtime-preview-2024-10-01", + }, + "organization_id": "org-dummy", + "organization_name": "Personal", + "project_id": (*string)(nil), + "project_name": (*string)(nil), + }, + Index: "", + ID: "", + Namespace: "", + Timestamp: time.Date(2024, time.November, 4, 5, 1, 0, 0, time.UTC), + Error: error(nil), + Host: "", + Service: "", + Took: 0, + Period: 0, + DisableTimeSeries: false, + }, + }, + { + name: "tc: #2", + expected: mb.Event{ + RootFields: nil, + ModuleFields: nil, + MetricSetFields: mapstr.M{ + "api_key_id": (*string)(nil), + "api_key_name": (*string)(nil), + "api_key_redacted": (*string)(nil), + "api_key_type": (*string)(nil), + "data": mapstr.M{ + "email": (*string)(nil), + "cached_context_tokens_total": 0, + "context_tokens_total": 31, + "generated_tokens_total": 12, + "requests_total": 1, + "operation": "completion", + "request_type": "", + "snapshot_id": "gpt-4o-2024-08-06", + }, + "organization_id": "org-dummy", + "organization_name": "Personal", + "project_id": (*string)(nil), + "project_name": (*string)(nil), + }, + Index: "", + ID: "", + Namespace: "", + Timestamp: time.Date(2024, time.November, 4, 5, 1, 0, 0, time.UTC), + Error: error(nil), + Host: "", + Service: "", + Took: 0, + Period: 0, + DisableTimeSeries: false, + }, + }, + { + name: "tc: #3", + expected: mb.Event{ + RootFields: nil, + ModuleFields: nil, + MetricSetFields: mapstr.M{ + "api_key_id": (*string)(nil), + "api_key_name": (*string)(nil), + "api_key_redacted": (*string)(nil), + "api_key_type": (*string)(nil), + "data": mapstr.M{ + "email": (*string)(nil), + "cached_context_tokens_total": 0, + "context_tokens_total": 13, + "generated_tokens_total": 9, + "requests_total": 1, + "operation": "completion", + "request_type": "", + "snapshot_id": "ft:gpt-3.5-turbo-0125:personal:yay-renew:APjjyG8E:ckpt-step-84", + }, + "organization_id": "org-dummy", + "organization_name": "Personal", + "project_id": (*string)(nil), + "project_name": (*string)(nil), + }, + Index: "", + ID: "", + Namespace: "", + Timestamp: time.Date(2024, time.November, 4, 5, 19, 0, 0, time.UTC), + Error: error(nil), + Host: "", + Service: "", + Took: 0, + Period: 0, + DisableTimeSeries: false, + }, + }, + { + name: "tc: #4", + expected: mb.Event{ + RootFields: nil, + ModuleFields: nil, + MetricSetFields: mapstr.M{ + "api_key_id": ptr("key_sha_id_random"), + "api_key_name": ptr("project_key"), + "api_key_redacted": ptr("sk-...zkA"), + "api_key_type": ptr("organization"), + "dalle": mapstr.M{ + "image_size": "1024x1024", + "model_id": "dall-e-3", + "num_images": 1, + "requests_total": 1, + "operation": "generations", + "user_id": "hello-test@elastic.co", + }, + "organization_id": "org-dummy", + "organization_name": "Personal", + "project_id": ptr("Default Project"), + "project_name": ptr("Default Project"), + }, + Index: "", + ID: "", + Namespace: "", + Timestamp: time.Date(2024, time.November, 4, 5, 1, 0, 0, time.UTC), + Error: error(nil), + Host: "", + Service: "", + Took: 0, + Period: 0, + DisableTimeSeries: false, + }, + }, + { + name: "tc: #5", + expected: mb.Event{ + RootFields: nil, + ModuleFields: nil, + MetricSetFields: mapstr.M{ + "api_key_id": (*string)(nil), + "api_key_name": (*string)(nil), + "api_key_redacted": (*string)(nil), + "api_key_type": (*string)(nil), + "whisper": mapstr.M{ + "model_id": "whisper-1", + "requests_total": 1, + "num_seconds": 2, + "user_id": "", + }, + "organization_id": "org-dummy", + "organization_name": "Personal", + "project_id": (*string)(nil), + "project_name": (*string)(nil), + }, + Index: "", + ID: "", + Namespace: "", + Timestamp: time.Date(2024, time.November, 4, 5, 1, 0, 0, time.UTC), + Error: error(nil), + Host: "", + Service: "", + Took: 0, + Period: 0, + DisableTimeSeries: false, + }, + }, + { + name: "tc: #6", + expected: mb.Event{ + RootFields: nil, + ModuleFields: nil, + MetricSetFields: mapstr.M{ + "api_key_id": ptr("key_fake_id"), + "api_key_name": ptr("project_key"), + "api_key_redacted": ptr("sk-...zkA"), + "api_key_type": ptr("organization"), + "tts": mapstr.M{ + "model_id": "tts-1", + "num_characters": 90, + "requests_total": 2, + "user_id": "hello-test@elastic.co", + }, + "organization_id": "org-fake", + "organization_name": "Personal", + "project_id": ptr("Default Project"), + "project_name": ptr("Default Project"), + }, + Index: "", + ID: "", + Namespace: "", + Timestamp: time.Date(2024, time.September, 4, 0, 0, 0, 0, time.UTC), + Error: error(nil), + Host: "", + Service: "", + Took: 0, + Period: 0, + DisableTimeSeries: false, + }, + }, + { + name: "tc: #7", + expected: mb.Event{ + RootFields: nil, + ModuleFields: nil, + MetricSetFields: mapstr.M{ + "api_key_id": ptr("key_fake_id"), + "api_key_name": ptr("fake_key"), + "api_key_redacted": ptr("sk-...FIA"), + "api_key_type": ptr("project"), + "tts": mapstr.M{ + "model_id": "tts-1", + "num_characters": 45, + "requests_total": 1, + "user_id": "hello-test@elastic.co", + }, + "organization_id": "org-fake", + "organization_name": "Personal", + "project_id": ptr("proj_fake_id"), + "project_name": ptr("fake_proj"), + }, + Index: "", + ID: "", + Namespace: "", + Timestamp: time.Date(2024, time.September, 5, 0, 0, 0, 0, time.UTC), + Error: error(nil), + Host: "", + Service: "", + Took: 0, + Period: 0, + DisableTimeSeries: false, + }, + }, + } + + f := mbtest.NewReportingMetricSetV2Error(t, getConfig(server.URL+"/usage", apiKey)) + events, errs := mbtest.ReportingFetchV2Error(f) + + require.Empty(t, errs, "Expected no errors") + require.NotEmpty(t, events, "Expected events to be returned") + require.Equal(t, len(tests), len(events)) + + for i, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.expected, events[i]) + }) + } +} + +func TestData(t *testing.T) { + apiKey := time.Now().String() // to generate a unique API key everytime + usagePath := "/usage" + server := initServer(usagePath, apiKey) + defer server.Close() + + f := mbtest.NewReportingMetricSetV2Error(t, getConfig(server.URL+"/usage", apiKey)) + + err := mbtest.WriteEventsReporterV2Error(f, t, "") + require.NoError(t, err, "Writing events should not return an error") +} + +func getConfig(url, apiKey string) map[string]interface{} { + return map[string]interface{}{ + "module": "openai", + "metricsets": []string{"usage"}, + "enabled": true, + "period": "24h", + "api_url": url, + "api_keys": []map[string]interface{}{ + {"key": apiKey}, + }, + "rate_limit": map[string]interface{}{ + "limit": 60, + "burst": 5, + }, + "collection": map[string]interface{}{ + "lookback_days": 0, + "realtime": false, + }, + } +} + +func initServer(endpoint, api_key string) *httptest.Server { + data := []byte(`{ + "object": "list", + "data": [ + { + "organization_id": "org-dummy", + "organization_name": "Personal", + "aggregation_timestamp": 1730696460, + "n_requests": 1, + "operation": "completion-realtime", + "snapshot_id": "gpt-4o-realtime-preview-2024-10-01", + "n_context_tokens_total": 118, + "n_generated_tokens_total": 35, + "email": null, + "api_key_id": null, + "api_key_name": null, + "api_key_redacted": null, + "api_key_type": null, + "project_id": null, + "project_name": null, + "request_type": "", + "n_cached_context_tokens_total": 0 + }, + { + "organization_id": "org-dummy", + "organization_name": "Personal", + "aggregation_timestamp": 1730696460, + "n_requests": 1, + "operation": "completion", + "snapshot_id": "gpt-4o-2024-08-06", + "n_context_tokens_total": 31, + "n_generated_tokens_total": 12, + "email": null, + "api_key_id": null, + "api_key_name": null, + "api_key_redacted": null, + "api_key_type": null, + "project_id": null, + "project_name": null, + "request_type": "", + "n_cached_context_tokens_total": 0 + }, + { + "organization_id": "org-dummy", + "organization_name": "Personal", + "aggregation_timestamp": 1730697540, + "n_requests": 1, + "operation": "completion", + "snapshot_id": "ft:gpt-3.5-turbo-0125:personal:yay-renew:APjjyG8E:ckpt-step-84", + "n_context_tokens_total": 13, + "n_generated_tokens_total": 9, + "email": null, + "api_key_id": null, + "api_key_name": null, + "api_key_redacted": null, + "api_key_type": null, + "project_id": null, + "project_name": null, + "request_type": "", + "n_cached_context_tokens_total": 0 + } + ], + "ft_data": [], + "dalle_api_data": [ + { + "timestamp": 1730696460, + "num_images": 1, + "num_requests": 1, + "image_size": "1024x1024", + "operation": "generations", + "user_id": "hello-test@elastic.co", + "organization_id": "org-dummy", + "api_key_id": "key_sha_id_random", + "api_key_name": "project_key", + "api_key_redacted": "sk-...zkA", + "api_key_type": "organization", + "organization_name": "Personal", + "model_id": "dall-e-3", + "project_id": "Default Project", + "project_name": "Default Project" + } + ], + "whisper_api_data": [ + { + "timestamp": 1730696460, + "model_id": "whisper-1", + "num_seconds": 2, + "num_requests": 1, + "user_id": null, + "organization_id": "org-dummy", + "api_key_id": null, + "api_key_name": null, + "api_key_redacted": null, + "api_key_type": null, + "organization_name": "Personal", + "project_id": null, + "project_name": null + } + ], + "tts_api_data": [ + { + "timestamp": 1725408000, + "model_id": "tts-1", + "num_characters": 90, + "num_requests": 2, + "user_id": "hello-test@elastic.co", + "organization_id": "org-fake", + "api_key_id": "key_fake_id", + "api_key_name": "project_key", + "api_key_redacted": "sk-...zkA", + "api_key_type": "organization", + "organization_name": "Personal", + "project_id": "Default Project", + "project_name": "Default Project" + }, + { + "timestamp": 1725494400, + "model_id": "tts-1", + "num_characters": 45, + "num_requests": 1, + "user_id": "hello-test@elastic.co", + "organization_id": "org-fake", + "api_key_id": "key_fake_id", + "api_key_name": "fake_key", + "api_key_redacted": "sk-...FIA", + "api_key_type": "project", + "organization_name": "Personal", + "project_id": "proj_fake_id", + "project_name": "fake_proj" + } + ], + "assistant_code_interpreter_data": [], + "retrieval_storage_data": [] +}`) + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Validate Bearer token + authHeader := r.Header.Get("Authorization") + expectedToken := fmt.Sprintf("Bearer %s", api_key) + + if authHeader != expectedToken { + w.WriteHeader(http.StatusUnauthorized) + return + } + + // If it doesn't match the expected endpoint, return 404 + if r.URL.Path != endpoint { + w.WriteHeader(http.StatusNotFound) + return + } + + w.WriteHeader(http.StatusOK) + _, _ = w.Write(data) + })) + return server +} diff --git a/x-pack/metricbeat/module/sql/query/query.go b/x-pack/metricbeat/module/sql/query/query.go index 5ae873c06ff3..b5b50e2d88f4 100644 --- a/x-pack/metricbeat/module/sql/query/query.go +++ b/x-pack/metricbeat/module/sql/query/query.go @@ -345,19 +345,28 @@ func inferTypeFromMetrics(ms mapstr.M) mapstr.M { for k, v := range ms { switch v.(type) { - case float64: + case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64: numericMetrics[k] = v case string: stringMetrics[k] = v case bool: boolMetrics[k] = v case nil: - // Ignore because a nil has no data type and thus cannot be indexed + // Ignore nil values as they cannot be indexed + + // TODO: Handle []interface{} properly; for now it is going to "string" field. + // Keeping the behaviour as it is for now. + // + // case []interface{}: + default: stringMetrics[k] = v } } + // TODO: Ideally the field keys should have in sync with ES types like s/bool/boolean, etc. + // But changing the field keys will be a breaking change. So, we are leaving it as it is. + if len(numericMetrics) > 0 { ret["numeric"] = numericMetrics } diff --git a/x-pack/metricbeat/modules.d/benchmark.yml.disabled b/x-pack/metricbeat/modules.d/benchmark.yml.disabled new file mode 100644 index 000000000000..29901546c423 --- /dev/null +++ b/x-pack/metricbeat/modules.d/benchmark.yml.disabled @@ -0,0 +1,9 @@ +# Module: benchmark +# Docs: https://www.elastic.co/guide/en/beats/metricbeat/main/metricbeat-module-benchmark.html + +- module: benchmark + metricsets: + - info + enabled: false + period: 10s + diff --git a/x-pack/metricbeat/modules.d/gcp.yml.disabled b/x-pack/metricbeat/modules.d/gcp.yml.disabled index c8cddd198ce3..6bb0c9bad2a8 100644 --- a/x-pack/metricbeat/modules.d/gcp.yml.disabled +++ b/x-pack/metricbeat/modules.d/gcp.yml.disabled @@ -37,6 +37,7 @@ credentials_file_path: "your JSON credentials file path" exclude_labels: false period: 1m + location_label: "resource.labels.zone" metrics: - aligner: ALIGN_NONE service: compute diff --git a/x-pack/metricbeat/modules.d/openai.yml.disabled b/x-pack/metricbeat/modules.d/openai.yml.disabled new file mode 100644 index 000000000000..6a881ae86419 --- /dev/null +++ b/x-pack/metricbeat/modules.d/openai.yml.disabled @@ -0,0 +1,37 @@ +# Module: openai +# Docs: https://www.elastic.co/guide/en/beats/metricbeat/main/metricbeat-module-openai.html + +- module: openai + metricsets: ["usage"] + enabled: false + period: 1h + + # # Project API Keys - Multiple API keys can be specified for different projects + # api_keys: + # - key: "api_key1" + # - key: "api_key2" + + # # API Configuration + # ## Base URL for the OpenAI usage API endpoint + # api_url: "https://api.openai.com/v1/usage" + # ## Custom headers to be included in API requests + # headers: + # - "k1: v1" + # - "k2: v2" + ## Rate Limiting Configuration + # rate_limit: + # limit: 12 # seconds between requests + # burst: 1 # max concurrent requests + # ## Request Timeout Duration + # timeout: 30s + + # # Data Collection Configuration + # collection: + # ## Number of days to look back when collecting usage data + # lookback_days: 30 + # ## Whether to collect usage data in realtime. Defaults to false as how + # # OpenAI usage data is collected will end up adding duplicate data to ES + # # and also making it harder to do analytics. Best approach is to avoid + # # realtime collection and collect only upto last day (in UTC). So, there's + # # at most 24h delay. + # realtime: false diff --git a/x-pack/metricbeat/tests/integration/setup_integration_test.go b/x-pack/metricbeat/tests/integration/setup_integration_test.go new file mode 100644 index 000000000000..f461f46ba621 --- /dev/null +++ b/x-pack/metricbeat/tests/integration/setup_integration_test.go @@ -0,0 +1,107 @@ +// 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. + +//go:build integration + +package integration + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/elastic/beats/v7/libbeat/tests/integration" + "github.com/elastic/beats/v7/libbeat/version" +) + +func TestIndexTotalFieldsLimitNotReached(t *testing.T) { + cfg := ` +metricbeat: +logging: + level: debug +metricbeat.config.modules: + path: ${path.config}/modules.d/*.yml + reload.enabled: false +` + metricbeat := integration.NewBeat(t, "metricbeat", "../../metricbeat.test") + metricbeat.WriteConfigFile(cfg) + esURL := integration.GetESURL(t, "http") + kURL, _ := integration.GetKibana(t) + + ver, _, _ := strings.Cut(version.GetDefaultVersion(), "-") + index := "metricbeat-" + ver + + dataStreamURL, err := integration.FormatDatastreamURL(t, esURL, index) + require.NoError(t, err) + templateURL, err := integration.FormatIndexTemplateURL(t, esURL, index) + require.NoError(t, err) + policyURL, err := integration.FormatPolicyURL(t, esURL, index) + cleanUpES := func() { + _, _, err := integration.HttpDo(t, http.MethodDelete, dataStreamURL) + require.NoErrorf(t, err, "cleanup failed: could not remove datastream %s", index) + _, _, err = integration.HttpDo(t, http.MethodDelete, templateURL) + require.NoErrorf(t, err, "cleanup failed: could not remove index template %s", index) + _, _, err = integration.HttpDo(t, http.MethodDelete, policyURL) + require.NoErrorf(t, err, "cleanup failed: could not remove ilm policy %s", index) + } + // ensure no datastream/index template/ilm policy is set before running the test + cleanUpES() + t.Cleanup(cleanUpES) + + metricbeat.Start("setup", + "--index-management", + "-E", "setup.kibana.protocol=http", + "-E", "setup.kibana.host="+kURL.Hostname(), + "-E", "setup.kibana.port="+kURL.Port(), + "-E", "output.elasticsearch.protocol=http", + "-E", "output.elasticsearch.hosts=['"+esURL.String()+"']") + procState, err := metricbeat.Process.Wait() + require.NoError(t, err, "metricbeat setup failed") + require.Equalf(t, 0, procState.ExitCode(), + "metricbeat setup failed: incorrect exit code: %d", procState.ExitCode()) + + // generate an event with dynamically mapped fields + fields := map[string]string{} + totalFields := 500 + for i := range totalFields { + fields[fmt.Sprintf("a-label-%d", i)] = fmt.Sprintf("some-value-%d", i) + } + event, err := json.Marshal(map[string]any{ + "@timestamp": time.Now().Format(time.RFC3339), + // 'kubernetes.labels.*' is a dynamically mapped field + "kubernetes.labels": fields, + }) + require.NoError(t, err, "could not marshal event to send to ES") + + endpoint := fmt.Sprintf("%s/%s/_doc", esURL.String(), index) + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + r, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, bytes.NewBuffer(event)) + require.NoError(t, err, "could not create request to send event to ES") + r.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(r) + require.NoError(t, err, "could not send request to send event to ES") + defer resp.Body.Close() + + failuremsg := fmt.Sprintf("failed to ingest events with %d new fields. If this test fails it likely means the current `index.mapping.total_fields.limit` for metricbeat index (%s) is close to be reached. Check the logs to see why the event was not ingested", totalFields, index) + if !assert.Equal(t, http.StatusCreated, resp.StatusCode, failuremsg) { + t.Logf("event sent: %s", string(event)) + + respBody, err := io.ReadAll(resp.Body) + require.NoError(t, err, "could not read response body") + t.Logf("ES ingest event reponse: %s", string(respBody)) + } +} diff --git a/x-pack/osquerybeat/beater/osquerybeat.go b/x-pack/osquerybeat/beater/osquerybeat.go index 7ed65de2dc69..6b659ed7dcef 100644 --- a/x-pack/osquerybeat/beater/osquerybeat.go +++ b/x-pack/osquerybeat/beater/osquerybeat.go @@ -12,7 +12,7 @@ import ( "time" "github.com/gofrs/uuid/v5" - lru "github.com/hashicorp/golang-lru" + lru "github.com/hashicorp/golang-lru/v2" "github.com/osquery/osquery-go" kconfig "github.com/osquery/osquery-go/plugin/config" klogger "github.com/osquery/osquery-go/plugin/logger" @@ -254,7 +254,7 @@ func (bt *osquerybeat) runOsquery(ctx context.Context, b *beat.Beat, osq *osqd.O socketPath := osq.SocketPath() // Create a cache for queries types resolution - cache, err := lru.New(adhocOsqueriesTypesCacheSize) + cache, err := lru.New[string, map[string]string](adhocOsqueriesTypesCacheSize) if err != nil { bt.log.Errorf("Failed to create osquery query results types cache: %v", err) return err diff --git a/x-pack/osquerybeat/internal/osqdcli/cache.go b/x-pack/osquerybeat/internal/osqdcli/cache.go index de69943da6c5..aaaf10ef8a61 100644 --- a/x-pack/osquerybeat/internal/osqdcli/cache.go +++ b/x-pack/osquerybeat/internal/osqdcli/cache.go @@ -4,15 +4,15 @@ package osqdcli -type Cache interface { - Add(key, value interface{}) (evicted bool) - Get(key interface{}) (value interface{}, ok bool) +type Cache[K comparable, V any] interface { + Add(K, V) (evicted bool) + Get(K) (value V, ok bool) Resize(size int) (evicted int) } -func WithCache(cache Cache, minSize int) Option { +func WithCache(cache Cache[string, map[string]string], minSize int) Option { return func(c *Client) { - nsc := &nullSafeCache{cache: cache} + nsc := &nullSafeCache[string, map[string]string]{cache: cache} if minSize > 0 { nsc.minSize = minSize } @@ -20,28 +20,28 @@ func WithCache(cache Cache, minSize int) Option { } } -type nullSafeCache struct { - cache Cache +type nullSafeCache[K comparable, V any] struct { + cache Cache[K, V] minSize int } -func (c *nullSafeCache) Add(key, value interface{}) (evicted bool) { +func (c *nullSafeCache[K, V]) Add(key K, value V) (evicted bool) { if c.cache == nil { - return + return false } return c.cache.Add(key, value) } -func (c *nullSafeCache) Get(key interface{}) (value interface{}, ok bool) { +func (c *nullSafeCache[K, V]) Get(key K) (value V, ok bool) { if c.cache == nil { - return + return value, ok } return c.cache.Get(key) } -func (c *nullSafeCache) Resize(size int) (evicted int) { +func (c *nullSafeCache[K, V]) Resize(size int) (evicted int) { if c.cache == nil { - return + return 0 } return c.cache.Resize(c.minSize + size) } diff --git a/x-pack/osquerybeat/internal/osqdcli/client.go b/x-pack/osquerybeat/internal/osqdcli/client.go index ca9ce7905807..a0eb9f1e700b 100644 --- a/x-pack/osquerybeat/internal/osqdcli/client.go +++ b/x-pack/osquerybeat/internal/osqdcli/client.go @@ -68,7 +68,7 @@ type Client struct { cli *osquery.ExtensionManagerClient mx sync.Mutex - cache Cache + cache Cache[string, map[string]string] cliLimiter *semaphore.Weighted } @@ -106,7 +106,7 @@ func New(socketPath string, opts ...Option) *Client { timeout: defaultTimeout, maxTimeout: defaultMaxTimeout, connectRetries: defaultConnectRetries, - cache: &nullSafeCache{}, + cache: &nullSafeCache[string, map[string]string]{}, cliLimiter: semaphore.NewWeighted(limit), } @@ -258,15 +258,9 @@ func (c *Client) resolveResult(ctx context.Context, sql string, hits []map[strin } func (c *Client) queryColumnTypes(ctx context.Context, sql string) (map[string]string, error) { - var colTypes map[string]string - - if v, ok := c.cache.Get(sql); ok { - colTypes, ok = v.(map[string]string) - if ok { - c.log.Debugf("using cached column types for query: %s", sql) - } else { - c.log.Error("failed get the column types from cache, incompatible type") - } + colTypes, ok := c.cache.Get(sql) + if ok { + c.log.Debugf("using cached column types for query: %s", sql) } if colTypes == nil {