From 31e3a2c4030d403e4a31c31ceb6473d7f74b6872 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2024 20:40:24 +0100 Subject: [PATCH] [8.15](backport #40836) [metricbeat] meraki module with device_health metricset (#40862) * [metricbeat] meraki module with device_health metricset (#40836) * inital meraki module and metricsets * initial refactor for single meraki metricset device_health * added tunnel support aka VPN support by Device * adding interfaces aka switch ports and switch port status * processing review comments * refactored for comments * fixing default metricset * Removing unused variables and adding text to required variables * add go module deps * fixing for loop and starting on fields yml * remove %d from loop condition * fixing review comments and loss latency * update dashboard-api lib to version with MIT licensed ratelimiter * remove unused fields in metricset struct * remove device details for now * Major refactor to improve overall readability and device status/metric associations. This commit removes a couple of data points from the original code, namely: - network appliance port settings - these settings are not defined per-device, but per-network, and as such don't fit into the current naming taxonomy. - site-to-site VPN settings - similarly to the above, these are not per-device attibutes. In addition there is a limitation included on including only a single metric bucket (as returned from the API) per metricbeat collection loop. There needs to be some better logging/config validation on this, which will come later; for now, just run with a maximum 5 minute collection interval. This commit includes the field mappings too, but it currently causes events to get dropped due to the index field limit getting hit (max 10k fields). You can get around this by setting 'setup.template.settings.index.mapping.total_fields.limit' to a higher value. We maybe can't include all these mappings in the metricbeat module, but for now they are here to allow testing with standalone metricbeat. * Add maximum collection interval check to avoid missing uplink loss and latency metrics. Remove 'percent' units, because the data does not fit the 0-1 elastic interpretation of percent. * revert accidental changes to reference config * add example in data.json * review comments: license headers, missing/incorrect mapping * result of 'go mod tidy' ... trying to unblock the CI builds * fix linter issues * update NOTICE.txt * add release tag to fields.yml, update docs * review feedback: keyword -> dat * commit results of 'make update' in x-pack metricbeat for CI * remove mappings to avoid hitting field limits in global metricbeat index template * add one field back to please the docs CI * more linter errors guarding against shared loop var pointers * fix error introduced in previous commit * add exception for golangci-lint G601 which is no longer required in go1.22+ * remove the guards against taking addresses of loop vars * i can't get the golanglint-ci config to get picked up, so i'm reverting that change and putting back the annoying index loop code * Update go.mod to match toolchain version to .go-version Co-authored-by: Craig MacKenzie --------- Co-authored-by: Dan Hiebert Co-authored-by: Craig MacKenzie (cherry picked from commit ae71c676d8edff4747fc7d8c2d22cdd0d7cedce6) # Conflicts: # NOTICE.txt # go.mod # go.sum # x-pack/metricbeat/metricbeat.reference.yml * fix go.mod merge conflict * fix merge errors in NOTICE.txt * fix merge errors in metricbeat.reference.yml * add result of running 'mage update' --------- Co-authored-by: Tom Myers <106530686+tommyers-elastic@users.noreply.github.com> --- NOTICE.txt | 289 ++++++++++++++++-- go.mod | 26 +- go.sum | 49 ++- metricbeat/docs/fields.asciidoc | 12 + metricbeat/docs/modules/meraki.asciidoc | 47 +++ .../modules/meraki/device_health.asciidoc | 29 ++ metricbeat/docs/modules_list.asciidoc | 3 + x-pack/metricbeat/include/list.go | 2 + x-pack/metricbeat/metricbeat.reference.yml | 52 ++-- .../metricbeat/module/meraki/_meta/config.yml | 6 + .../module/meraki/_meta/docs.asciidoc | 2 + .../metricbeat/module/meraki/_meta/fields.yml | 7 + .../meraki/device_health/_meta/data.json | 83 +++++ .../meraki/device_health/_meta/docs.asciidoc | 1 + .../meraki/device_health/_meta/fields.yml | 7 + .../meraki/device_health/device_health.go | 184 +++++++++++ .../device_health/device_health_test.go | 67 ++++ .../module/meraki/device_health/devices.go | 234 ++++++++++++++ .../meraki/device_health/switchports.go | 157 ++++++++++ .../module/meraki/device_health/uplinks.go | 177 +++++++++++ x-pack/metricbeat/module/meraki/doc.go | 6 + x-pack/metricbeat/module/meraki/fields.go | 23 ++ .../metricbeat/modules.d/meraki.yml.disabled | 9 + 23 files changed, 1395 insertions(+), 77 deletions(-) create mode 100644 metricbeat/docs/modules/meraki.asciidoc create mode 100644 metricbeat/docs/modules/meraki/device_health.asciidoc create mode 100644 x-pack/metricbeat/module/meraki/_meta/config.yml create mode 100644 x-pack/metricbeat/module/meraki/_meta/docs.asciidoc create mode 100644 x-pack/metricbeat/module/meraki/_meta/fields.yml create mode 100644 x-pack/metricbeat/module/meraki/device_health/_meta/data.json create mode 100644 x-pack/metricbeat/module/meraki/device_health/_meta/docs.asciidoc create mode 100644 x-pack/metricbeat/module/meraki/device_health/_meta/fields.yml create mode 100644 x-pack/metricbeat/module/meraki/device_health/device_health.go create mode 100644 x-pack/metricbeat/module/meraki/device_health/device_health_test.go create mode 100644 x-pack/metricbeat/module/meraki/device_health/devices.go create mode 100644 x-pack/metricbeat/module/meraki/device_health/switchports.go create mode 100644 x-pack/metricbeat/module/meraki/device_health/uplinks.go create mode 100644 x-pack/metricbeat/module/meraki/doc.go create mode 100644 x-pack/metricbeat/module/meraki/fields.go create mode 100644 x-pack/metricbeat/modules.d/meraki.yml.disabled diff --git a/NOTICE.txt b/NOTICE.txt index 357c5d9a4401..2a0eaebacfdc 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -20752,6 +20752,36 @@ 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 +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/tommyers-elastic/dashboard-api-go/v3@v3.0.0-20240913150833-a945473a8f25/LICENSE: + +MIT License + +Copyright (c) 2019-2020 Cisco Systems + +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/miekg/dns Version: v1.1.42 @@ -24520,13 +24550,13 @@ THE SOFTWARE. -------------------------------------------------------------------------------- Dependency : golang.org/x/crypto -Version: v0.25.0 +Version: v0.27.0 Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/golang.org/x/crypto@v0.25.0/LICENSE: +Contents of probable licence file $GOMODCACHE/golang.org/x/crypto@v0.27.0/LICENSE: -Copyright (c) 2009 The Go Authors. All rights reserved. +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 @@ -24538,7 +24568,7 @@ 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 + * 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. @@ -24594,13 +24624,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- Dependency : golang.org/x/mod -Version: v0.18.0 +Version: v0.21.0 Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/golang.org/x/mod@v0.18.0/LICENSE: +Contents of probable licence file $GOMODCACHE/golang.org/x/mod@v0.21.0/LICENSE: -Copyright (c) 2009 The Go Authors. All rights reserved. +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 @@ -24612,7 +24642,7 @@ 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 + * 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. @@ -24631,13 +24661,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- Dependency : golang.org/x/net -Version: v0.27.0 +Version: v0.29.0 Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/golang.org/x/net@v0.27.0/LICENSE: +Contents of probable licence file $GOMODCACHE/golang.org/x/net@v0.29.0/LICENSE: -Copyright (c) 2009 The Go Authors. All rights reserved. +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 @@ -24649,7 +24679,7 @@ 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 + * 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. @@ -24705,13 +24735,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- Dependency : golang.org/x/sync -Version: v0.7.0 +Version: v0.8.0 Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/golang.org/x/sync@v0.7.0/LICENSE: +Contents of probable licence file $GOMODCACHE/golang.org/x/sync@v0.8.0/LICENSE: -Copyright (c) 2009 The Go Authors. All rights reserved. +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 @@ -24723,7 +24753,7 @@ 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 + * 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. @@ -24742,13 +24772,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- Dependency : golang.org/x/sys -Version: v0.22.0 +Version: v0.25.0 Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/golang.org/x/sys@v0.22.0/LICENSE: +Contents of probable licence file $GOMODCACHE/golang.org/x/sys@v0.25.0/LICENSE: -Copyright (c) 2009 The Go Authors. All rights reserved. +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 @@ -24760,7 +24790,7 @@ 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 + * 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. @@ -24779,13 +24809,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- Dependency : golang.org/x/text -Version: v0.16.0 +Version: v0.18.0 Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/golang.org/x/text@v0.16.0/LICENSE: +Contents of probable licence file $GOMODCACHE/golang.org/x/text@v0.18.0/LICENSE: -Copyright (c) 2009 The Go Authors. All rights reserved. +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 @@ -24797,7 +24827,7 @@ 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 + * 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. @@ -24853,13 +24883,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- Dependency : golang.org/x/tools -Version: v0.21.1-0.20240508182429-e35e4ccd0d2d +Version: v0.25.0 Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/golang.org/x/tools@v0.21.1-0.20240508182429-e35e4ccd0d2d/LICENSE: +Contents of probable licence file $GOMODCACHE/golang.org/x/tools@v0.25.0/LICENSE: -Copyright (c) 2009 The Go Authors. All rights reserved. +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 @@ -24871,7 +24901,7 @@ 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 + * 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. @@ -34299,6 +34329,37 @@ Contents of probable licence file $GOMODCACHE/github.com/aws/aws-sdk-go-v2/servi limitations under the License. +-------------------------------------------------------------------------------- +Dependency : github.com/benbjohnson/clock +Version: v1.3.0 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/benbjohnson/clock@v1.3.0/LICENSE: + +The MIT License (MIT) + +Copyright (c) 2014 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 : github.com/beorn7/perks Version: v1.0.1 @@ -38315,6 +38376,37 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +-------------------------------------------------------------------------------- +Dependency : github.com/go-resty/resty/v2 +Version: v2.11.0 +Licence type (autodetected): MIT +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/github.com/go-resty/resty/v2@v2.11.0/LICENSE: + +The MIT License (MIT) + +Copyright (c) 2015-2023 Jeevanandam M., https://myjeeva.com + +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/go-sourcemap/sourcemap Version: v2.1.2+incompatible @@ -39402,6 +39494,43 @@ Contents of probable licence file $GOMODCACHE/github.com/google/gnostic-models@v +-------------------------------------------------------------------------------- +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 @@ -41206,6 +41335,38 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 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.0 @@ -52958,6 +53119,36 @@ 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-20231127185646-65229373498e @@ -52997,13 +53188,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- Dependency : golang.org/x/term -Version: v0.22.0 +Version: v0.24.0 Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/golang.org/x/term@v0.22.0/LICENSE: +Contents of probable licence file $GOMODCACHE/golang.org/x/term@v0.24.0/LICENSE: -Copyright (c) 2009 The Go Authors. All rights reserved. +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 @@ -53015,7 +53206,7 @@ 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 + * 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. @@ -53810,6 +54001,40 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 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 diff --git a/go.mod b/go.mod index d0bbb55bd7bb..235388ea14eb 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/elastic/beats/v7 -go 1.22 +go 1.22.0 + +toolchain go1.22.6 require ( cloud.google.com/go/bigquery v1.59.1 @@ -144,16 +146,16 @@ require ( go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 - golang.org/x/crypto v0.25.0 + golang.org/x/crypto v0.27.0 golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 - golang.org/x/mod v0.18.0 - golang.org/x/net v0.27.0 + golang.org/x/mod v0.21.0 + golang.org/x/net v0.29.0 golang.org/x/oauth2 v0.18.0 - golang.org/x/sync v0.7.0 - golang.org/x/sys v0.22.0 - golang.org/x/text v0.16.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/time v0.5.0 - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d + golang.org/x/tools v0.25.0 google.golang.org/api v0.169.0 google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect google.golang.org/grpc v1.64.0 @@ -214,6 +216,7 @@ require ( github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 github.com/icholy/digest v0.1.22 + github.com/meraki/dashboard-api-go/v3 v3.0.9 github.com/otiai10/copy v1.12.0 github.com/pierrec/lz4/v4 v4.1.18 github.com/pkg/xattr v0.4.9 @@ -263,6 +266,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.5 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 // indirect + github.com/benbjohnson/clock v1.3.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cilium/ebpf v0.13.2 // indirect @@ -292,6 +296,7 @@ require ( github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-resty/resty/v2 v2.11.0 // indirect github.com/go-stack/stack v1.8.0 // indirect github.com/gobuffalo/here v0.6.7 // indirect github.com/goccy/go-json v0.10.2 // indirect @@ -302,6 +307,7 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-querystring v1.1.0 // indirect github.com/google/licenseclassifier v0.0.0-20221004142553-c1ed8fcf4bab // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect @@ -372,8 +378,9 @@ require ( go.opentelemetry.io/otel/metric v1.28.0 // indirect go.opentelemetry.io/otel/trace v1.28.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect + go.uber.org/ratelimit v0.3.1 // indirect golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect - golang.org/x/term v0.22.0 // indirect + golang.org/x/term v0.24.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 // indirect @@ -414,6 +421,7 @@ replace ( github.com/golang/glog => github.com/elastic/glog v1.0.1-0.20210831205241-7d8b5c89dfc4 github.com/google/gopacket => github.com/elastic/gopacket v1.1.20-0.20211202005954-d412fca7f83a 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 github.com/tonistiigi/fifo => github.com/containerd/fifo v0.0.0-20190816180239-bda0ff6ed73c k8s.io/kubernetes v1.13.0 => k8s.io/kubernetes v1.24.15 diff --git a/go.sum b/go.sum index d8d308a7d449..c0a26b49e833 100644 --- a/go.sum +++ b/go.sum @@ -383,6 +383,8 @@ github.com/awslabs/goformation/v4 v4.1.0/go.mod h1:MBDN7u1lMNDoehbFuO4uPvgwPeolT 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= github.com/benbjohnson/immutable v0.2.1/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI= github.com/benbjohnson/tmpl v1.0.0/go.mod h1:igT620JFIi44B6awvU9IsDhR77IXWtFigTLil/RPdps= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -804,6 +806,8 @@ github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhO github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8= +github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8= +github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= github.com/go-sourcemap/sourcemap v2.1.2+incompatible h1:0b/xya7BKGhXuqFESKM4oIiRo9WOt2ebz7KxfreD6ug= github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -956,6 +960,8 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= @@ -1042,6 +1048,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737 github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/h2non/filetype v1.1.1 h1:xvOwnXKAckvtLWsN398qS9QhlxlnVXBjXBydK2/UFB4= github.com/h2non/filetype v1.1.1/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/api v1.4.0/go.mod h1:xc8u05kyMa3Wjr9eEAsIAo3dg8+LywT5E/Cl7cNS5nU= github.com/hashicorp/consul/api v1.8.1/go.mod h1:sDjTOq0yUyv5G4h+BqSea7Fn6BU+XbolEz1952UB+mk= @@ -1639,6 +1647,8 @@ github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYa github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o= github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tommyers-elastic/dashboard-api-go/v3 v3.0.0-20240913150833-a945473a8f25 h1:o24r+NDexzdlwgqI0Dglq2I/cdONYRACikcUmYmovtQ= +github.com/tommyers-elastic/dashboard-api-go/v3 v3.0.0-20240913150833-a945473a8f25/go.mod h1:COGDRzuD05ZS/zp0lDCTDFhx6kAuuNdhDjY0y2ifi5o= github.com/tsg/go-daemon v0.0.0-20200207173439-e704b93fd89b h1:X/8hkb4rQq3+QuOxpJK7gWmAXmZucF0EI1s1BfBLq6U= github.com/tsg/go-daemon v0.0.0-20200207173439-e704b93fd89b/go.mod h1:jAqhj/JBVC1PwcLTWd6rjQyGyItxxrhpiBl8LSuAGmw= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= @@ -1783,6 +1793,8 @@ go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9i 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= +go.uber.org/ratelimit v0.3.1/go.mod h1:6euWsTB6U/Nb3X++xEUXA8ciPJvr19Q/0h1+oDcJhRk= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= @@ -1828,11 +1840,12 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= 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.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +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/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1891,8 +1904,9 @@ 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.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1971,9 +1985,10 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +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/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.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2007,8 +2022,9 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -2122,11 +2138,12 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.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/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -2135,11 +2152,12 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= 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.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= -golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +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/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2156,8 +2174,8 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 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.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2165,6 +2183,7 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -2255,8 +2274,8 @@ golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= 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.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= +golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= golang.org/x/tools/go/vcs v0.1.0-deprecated h1:cOIJqWBl99H1dH5LWizPa+0ImeeJq3t3cJjaeOWUAL4= golang.org/x/tools/go/vcs v0.1.0-deprecated/go.mod h1:zUrvATBAvEI9535oC0yWYsLsHIV4Z7g63sNPVMtuBy8= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2433,6 +2452,8 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY= +gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0= 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= diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index 6630a7ecee95..e0aeab6e4d3c 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -60,6 +60,7 @@ grouped in the following categories: * <> * <> * <> +* <> * <> * <> * <> @@ -50453,6 +50454,17 @@ type: long -- +[[exported-fields-meraki]] + + + +*`meraki.device.serial`*:: ++ +-- +type: keyword + +-- + [[exported-fields-mongodb]] == MongoDB fields diff --git a/metricbeat/docs/modules/meraki.asciidoc b/metricbeat/docs/modules/meraki.asciidoc new file mode 100644 index 000000000000..9e74dc5da2d3 --- /dev/null +++ b/metricbeat/docs/modules/meraki.asciidoc @@ -0,0 +1,47 @@ +//// +This file is generated! See scripts/mage/docs_collector.go +//// + +:modulename: meraki +:edit_url: https://github.com/elastic/beats/edit/main/x-pack/metricbeat/module/meraki/_meta/docs.asciidoc + + +[[metricbeat-module-meraki]] +[role="xpack"] +== Cisco Meraki module + +beta[] + +This is the meraki module. + + + +:edit_url: + +[float] +=== Example configuration + +The Cisco Meraki module supports the standard configuration options that are described +in <>. Here is an example configuration: + +[source,yaml] +---- +metricbeat.modules: +- module: meraki + metricsets: ["device_health"] + enabled: true + period: 300s + apiKey: "Meraki dashboard API key" + organizations: ["Meraki organization ID"] +---- + +[float] +=== Metricsets + +The following metricsets are available: + +* <> + +include::meraki/device_health.asciidoc[] + +:edit_url!: diff --git a/metricbeat/docs/modules/meraki/device_health.asciidoc b/metricbeat/docs/modules/meraki/device_health.asciidoc new file mode 100644 index 000000000000..25328811c115 --- /dev/null +++ b/metricbeat/docs/modules/meraki/device_health.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/meraki/device_health/_meta/docs.asciidoc + + +[[metricbeat-metricset-meraki-device_health]] +[role="xpack"] +=== Cisco Meraki device_health metricset + +beta[] + +include::../../../../x-pack/metricbeat/module/meraki/device_health/_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/meraki/device_health/_meta/data.json[] +---- +:edit_url!: \ No newline at end of file diff --git a/metricbeat/docs/modules_list.asciidoc b/metricbeat/docs/modules_list.asciidoc index c7a53f5b9093..b49cd1427213 100644 --- a/metricbeat/docs/modules_list.asciidoc +++ b/metricbeat/docs/modules_list.asciidoc @@ -213,6 +213,8 @@ This file is generated! See scripts/mage/docs_collector.go |<> |<> |image:./images/icon-no.png[No prebuilt dashboards] | .1+| .1+| |<> +|<> beta[] |image:./images/icon-no.png[No prebuilt dashboards] | +.1+| .1+| |<> beta[] |<> |image:./images/icon-yes.png[Prebuilt dashboards are available] | .5+| .5+| |<> |<> @@ -367,6 +369,7 @@ include::modules/kvm.asciidoc[] include::modules/linux.asciidoc[] include::modules/logstash.asciidoc[] include::modules/memcached.asciidoc[] +include::modules/meraki.asciidoc[] include::modules/mongodb.asciidoc[] include::modules/mssql.asciidoc[] include::modules/munin.asciidoc[] diff --git a/x-pack/metricbeat/include/list.go b/x-pack/metricbeat/include/list.go index 492e4e7d4d01..b13740cfe449 100644 --- a/x-pack/metricbeat/include/list.go +++ b/x-pack/metricbeat/include/list.go @@ -48,6 +48,8 @@ import ( _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/istio/mesh" _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/istio/mixer" _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/istio/pilot" + _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/meraki" + _ "github.com/elastic/beats/v7/x-pack/metricbeat/module/meraki/device_health" _ "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" diff --git a/x-pack/metricbeat/metricbeat.reference.yml b/x-pack/metricbeat/metricbeat.reference.yml index 1b5bec3fdd43..e8ec973a75c3 100644 --- a/x-pack/metricbeat/metricbeat.reference.yml +++ b/x-pack/metricbeat/metricbeat.reference.yml @@ -1103,6 +1103,14 @@ metricbeat.modules: hosts: ["localhost:11211"] enabled: true +#----------------------------- Cisco Meraki Module ----------------------------- +- module: meraki + metricsets: ["device_health"] + enabled: true + period: 300s + apiKey: "Meraki dashboard API key" + organizations: ["Meraki organization ID"] + #------------------------------- MongoDB Module ------------------------------- - module: mongodb metricsets: ["dbstats", "status", "collstats", "metrics", "replstatus"] @@ -1311,9 +1319,11 @@ metricbeat.modules: # Password to use when connecting to PostgreSQL. Empty by default. #password: pass -#----------------------- Prometheus Typed Metrics Module ----------------------- +#------------------------------ Prometheus Module ------------------------------ +# Metrics collected from a Prometheus endpoint - module: prometheus period: 10s + metricsets: ["collector"] hosts: ["localhost:9090"] metrics_path: /metrics #metrics_filters: @@ -1327,12 +1337,6 @@ metricbeat.modules: #ssl.certificate_authorities: # - /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt - # Use Elasticsearch histogram type to store histograms (beta, default: false) - # This will change the default layout and put metric type in the field name - #use_types: true - - # Store counter rates instead of original cumulative counters (experimental, default: false) - #rate_counters: true # Metrics sent by a Prometheus server using remote_write option #- module: prometheus @@ -1344,18 +1348,6 @@ metricbeat.modules: #ssl.certificate: "/etc/pki/server/cert.pem" #ssl.key: "/etc/pki/server/cert.key" - # Use Elasticsearch histogram type to store histograms (beta, default: false) - # This will change the default layout and put metric type in the field name - #use_types: true - - # Store counter rates instead of original cumulative counters (experimental, default: false) - #rate_counters: true - - # Define patterns for counter and histogram types so as to identify metrics' types according to these patterns - #types_patterns: - # counter_patterns: [] - # histogram_patterns: [] - # Metrics that will be collected using a PromQL #- module: prometheus # metricsets: ["query"] @@ -1382,11 +1374,9 @@ metricbeat.modules: # params: # query: "some_value" -#------------------------------ Prometheus Module ------------------------------ -# Metrics collected from a Prometheus endpoint +#----------------------- Prometheus Typed Metrics Module ----------------------- - module: prometheus period: 10s - metricsets: ["collector"] hosts: ["localhost:9090"] metrics_path: /metrics #metrics_filters: @@ -1400,6 +1390,12 @@ metricbeat.modules: #ssl.certificate_authorities: # - /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt + # Use Elasticsearch histogram type to store histograms (beta, default: false) + # This will change the default layout and put metric type in the field name + #use_types: true + + # Store counter rates instead of original cumulative counters (experimental, default: false) + #rate_counters: true # Metrics sent by a Prometheus server using remote_write option #- module: prometheus @@ -1411,6 +1407,18 @@ metricbeat.modules: #ssl.certificate: "/etc/pki/server/cert.pem" #ssl.key: "/etc/pki/server/cert.key" + # Use Elasticsearch histogram type to store histograms (beta, default: false) + # This will change the default layout and put metric type in the field name + #use_types: true + + # Store counter rates instead of original cumulative counters (experimental, default: false) + #rate_counters: true + + # Define patterns for counter and histogram types so as to identify metrics' types according to these patterns + #types_patterns: + # counter_patterns: [] + # histogram_patterns: [] + # Metrics that will be collected using a PromQL #- module: prometheus # metricsets: ["query"] diff --git a/x-pack/metricbeat/module/meraki/_meta/config.yml b/x-pack/metricbeat/module/meraki/_meta/config.yml new file mode 100644 index 000000000000..54da937c0cbd --- /dev/null +++ b/x-pack/metricbeat/module/meraki/_meta/config.yml @@ -0,0 +1,6 @@ +- module: meraki + metricsets: ["device_health"] + enabled: true + period: 300s + apiKey: "Meraki dashboard API key" + organizations: ["Meraki organization ID"] diff --git a/x-pack/metricbeat/module/meraki/_meta/docs.asciidoc b/x-pack/metricbeat/module/meraki/_meta/docs.asciidoc new file mode 100644 index 000000000000..f2cc90ab62ff --- /dev/null +++ b/x-pack/metricbeat/module/meraki/_meta/docs.asciidoc @@ -0,0 +1,2 @@ +This is the meraki module. + diff --git a/x-pack/metricbeat/module/meraki/_meta/fields.yml b/x-pack/metricbeat/module/meraki/_meta/fields.yml new file mode 100644 index 000000000000..c1942d91a328 --- /dev/null +++ b/x-pack/metricbeat/module/meraki/_meta/fields.yml @@ -0,0 +1,7 @@ +- key: meraki + title: Cisco Meraki + release: beta + fields: + - name: meraki + type: group + fields: diff --git a/x-pack/metricbeat/module/meraki/device_health/_meta/data.json b/x-pack/metricbeat/module/meraki/device_health/_meta/data.json new file mode 100644 index 000000000000..4e658fe413a7 --- /dev/null +++ b/x-pack/metricbeat/module/meraki/device_health/_meta/data.json @@ -0,0 +1,83 @@ +{ + "@timestamp": "2024-09-15T22:33:30.079Z", + "service": { + "type": "meraki" + }, + "ecs": { + "version": "8.0.0" + }, + "host": { + "name": "Toms-MBP.broadband" + }, + "agent": { + "id": "77b8b5ed-245e-4ddc-a98c-195ffa174328", + "name": "Toms-MBP.broadband", + "type": "metricbeat", + "version": "9.0.0", + "ephemeral_id": "cb124423-75db-4ef5-87d3-6b37434d3a17" + }, + "event": { + "duration": 9445416042, + "dataset": "meraki.device_health", + "module": "meraki" + }, + "metricset": { + "name": "device_health", + "period": 300000 + }, + "meraki": { + "organization_id": "125432", + "device": { + "location": [ + -122.098531723022, + 37.4180951010362 + ], + "product_type": "switch", + "lan_ip": "192.168.128.54", + "mac": "00:18:0a:7d:9b:13", + "network_id": "N_577586652210304682", + "serial": "Q2HP-3M4W-3VJ8", + "name": "8 Port Switch", + "firmware": "switch-16-1", + "model": "MS220-8P" + }, + "switch": { + "port": { + "poe_enabled": true, + "rstp_enabled": true, + "allowed_vlans": "all", + "status": { + "enabled": true, + "usage": { + "sent": 0, + "recv": 0, + "total": 0 + }, + "status": "Disconnected", + "secure_port": { + "authentication_status": "Disabled", + "active": false, + "enabled": false + }, + "is_uplink": false, + "client_count": 0, + "errors": [ + "Port disconnected" + ], + "throughput": { + "recv": 0, + "sent": 0, + "total": 0 + } + }, + "stp_guard": "disabled", + "type": "trunk", + "enabled": true, + "access_policy_type": "Open", + "vlan": 1, + "id": "10", + "link_negotiation": "Auto negotiate" + } + } + } +} \ No newline at end of file diff --git a/x-pack/metricbeat/module/meraki/device_health/_meta/docs.asciidoc b/x-pack/metricbeat/module/meraki/device_health/_meta/docs.asciidoc new file mode 100644 index 000000000000..f09d386197a7 --- /dev/null +++ b/x-pack/metricbeat/module/meraki/device_health/_meta/docs.asciidoc @@ -0,0 +1 @@ +This is the device_health metricset of the module meraki. diff --git a/x-pack/metricbeat/module/meraki/device_health/_meta/fields.yml b/x-pack/metricbeat/module/meraki/device_health/_meta/fields.yml new file mode 100644 index 000000000000..df4175478d3d --- /dev/null +++ b/x-pack/metricbeat/module/meraki/device_health/_meta/fields.yml @@ -0,0 +1,7 @@ +- name: device + type: group + release: beta + fields: + - name: serial + type: keyword + dimension: true diff --git a/x-pack/metricbeat/module/meraki/device_health/device_health.go b/x-pack/metricbeat/module/meraki/device_health/device_health.go new file mode 100644 index 000000000000..25d41bf43f5e --- /dev/null +++ b/x-pack/metricbeat/module/meraki/device_health/device_health.go @@ -0,0 +1,184 @@ +// 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 device_health + +import ( + "fmt" + "reflect" + "time" + + "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" + + meraki "github.com/meraki/dashboard-api-go/v3/sdk" +) + +func init() { + mb.Registry.MustAddMetricSet("meraki", "device_health", New) +} + +type config struct { + BaseURL string `config:"apiBaseURL"` + ApiKey string `config:"apiKey"` + DebugMode string `config:"apiDebugMode"` + Organizations []string `config:"organizations"` + Period time.Duration `config:"period"` + // todo: device filtering? +} + +func defaultConfig() *config { + return &config{ + BaseURL: "https://api.meraki.com", + DebugMode: "false", + Period: time.Second * 300, + } +} + +type MetricSet struct { + mb.BaseMetricSet + logger *logp.Logger + client *meraki.Client + organizations []string +} + +func New(base mb.BaseMetricSet) (mb.MetricSet, error) { + cfgwarn.Beta("The meraki device_health metricset is beta.") + + logger := logp.NewLogger(base.FullyQualifiedName()) + + config := defaultConfig() + if err := base.Module().UnpackConfig(config); err != nil { + return nil, err + } + + // the reason for this is due to restrictions imposed by some dashboard API endpoints. + // for example, "/api/v1/organizations/{organizationId}/devices/uplinksLossAndLatency" + // has a maximum 'timespan' of 5 minutes. + if config.Period.Seconds() > 300 { + return nil, fmt.Errorf("the maximum allowed collection period is 5 minutes (300s)") + } + + logger.Debugf("loaded config: %v", config) + client, err := meraki.NewClientWithOptions(config.BaseURL, config.ApiKey, config.DebugMode, "Metricbeat Elastic") + if err != nil { + logger.Error("creating Meraki dashboard API client failed: %w", err) + return nil, err + } + + return &MetricSet{ + BaseMetricSet: base, + logger: logger, + client: client, + organizations: config.Organizations, + }, nil +} + +func (m *MetricSet) Fetch(reporter mb.ReporterV2) error { + for _, org := range m.organizations { + // some metrics require a 'timespan' parameter; we match this to our + // collection interval to only collect new metric values + collectionPeriod := m.BaseMetricSet.Module().Config().Period + + // First we get the list of all devices for this org (and their metadata). + // Devices are uniquely identified by their serial number, which are used to + // associate the metrics we collect later with the devices returned here. + devices, err := getDevices(m.client, org) + if err != nil { + return fmt.Errorf("getDevices failed; %w", err) + } + + // Now we continue to populate the device data structure with health + // attributes/statuses/metrics etc in the following functions... + err = getDeviceStatuses(m.client, org, devices) + if err != nil { + return fmt.Errorf("getDeviceStatuses failed; %w", err) + } + + err = getDevicePerformanceScores(m.client, devices) + if err != nil { + return fmt.Errorf("getDevicePerformanceScores failed; %w", err) + } + + err = getDeviceChannelUtilization(m.client, devices, collectionPeriod) + if err != nil { + return fmt.Errorf("getDeviceChannelUtilization failed; %w", err) + } + + err = getDeviceLicenses(m.client, org, devices) + if err != nil { + return fmt.Errorf("getDeviceLicenses failed; %w", err) + } + + err = getDeviceUplinks(m.client, org, devices, collectionPeriod) + if err != nil { + return fmt.Errorf("getDeviceUplinks failed; %w", err) + } + + err = getDeviceSwitchports(m.client, org, devices, collectionPeriod) + if err != nil { + return fmt.Errorf("getDeviceSwitchports failed; %w", err) + } + + // Once we have collected _all_ the data and associated it with the correct device + // we can report the various device health metrics. These functions are split up + // in this way primarily to allow better separation of the code, but also because + // each function here corresponds to a distinct set of reported metric events + // i.e. there is one event per device, one event per uplink (but multiple uplinks per device), + // one event per switchport (but multiple switchports per device), etc. + reportDeviceMetrics(reporter, org, devices) + reportUplinkMetrics(reporter, org, devices) + reportSwitchportMetrics(reporter, org, devices) + } + + return nil +} + +func reportMetricsForOrganization(reporter mb.ReporterV2, organizationID string, metrics ...[]mapstr.M) { + for _, metricSlice := range metrics { + for _, metric := range metricSlice { + event := mb.Event{ModuleFields: mapstr.M{"organization_id": organizationID}} + if ts, ok := metric["@timestamp"]; ok { + t, err := time.Parse(time.RFC3339, ts.(string)) + if err == nil { + // if the timestamp parsing fails, we just fall back to the event time + // (and leave the additional timestamp in the event for posterity) + event.Timestamp = t + delete(metric, "@timestamp") + } + } + + for k, v := range metric { + if !isEmpty(v) { + event.ModuleFields.Put(k, v) + } + } + + reporter.Event(event) + } + } +} + +func isEmpty(value interface{}) bool { + // we make use of the fact that all the dashboard API responses utilize + // pointers for non-string types to filter out empty values from metric events. + + if value == nil { + return true + } + + t := reflect.TypeOf(value) + + if t.Kind() == reflect.Ptr { + return reflect.ValueOf(value).IsNil() + } + + if t.Kind() == reflect.Slice || t.Kind() == reflect.String { + return reflect.ValueOf(value).Len() == 0 + } + + return false +} diff --git a/x-pack/metricbeat/module/meraki/device_health/device_health_test.go b/x-pack/metricbeat/module/meraki/device_health/device_health_test.go new file mode 100644 index 000000000000..668007690346 --- /dev/null +++ b/x-pack/metricbeat/module/meraki/device_health/device_health_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 device_health + +import ( + "testing" +) + +func TestIsEmpty(t *testing.T) { + tests := []struct { + name string + input interface{} + expected bool + }{ + { + name: "Nil pointer", + input: (*int)(nil), + expected: true, + }, + { + name: "Empty string", + input: "", + expected: true, + }, + { + name: "Non-empty string", + input: "test", + expected: false, + }, + { + name: "Empty slice", + input: []string{}, + expected: true, + }, + { + name: "Regular value", + input: float64(1.2), + expected: false, + }, + { + name: "Pointer to int", + input: func() *int { i := 42; return &i }(), + expected: false, + }, + { + name: "Pointer to bool", + input: func() *bool { b := false; return &b }(), + expected: false, + }, + { + name: "Boolean false", + input: false, + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := isEmpty(tt.input) + if result != tt.expected { + t.Errorf("isEmpty(%v) = %v; want %v", tt.input, result, tt.expected) + } + }) + } +} diff --git a/x-pack/metricbeat/module/meraki/device_health/devices.go b/x-pack/metricbeat/module/meraki/device_health/devices.go new file mode 100644 index 000000000000..2f2591d6783e --- /dev/null +++ b/x-pack/metricbeat/module/meraki/device_health/devices.go @@ -0,0 +1,234 @@ +// 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 device_health + +import ( + "fmt" + "strings" + "time" + + "github.com/elastic/beats/v7/metricbeat/mb" + "github.com/elastic/elastic-agent-libs/mapstr" + + meraki "github.com/meraki/dashboard-api-go/v3/sdk" +) + +// Serial is the unique identifier for all devices +type Serial string + +// Device contains attributes, statuses and metrics for Meraki devices +type Device struct { + details *meraki.ResponseItemOrganizationsGetOrganizationDevices + status *meraki.ResponseItemOrganizationsGetOrganizationDevicesStatuses + haStatus *meraki.ResponseItemApplianceGetOrganizationApplianceUplinkStatusesHighAvailability + performanceScore *meraki.ResponseApplianceGetDeviceAppliancePerformance + wifi0 *meraki.ResponseItemNetworksGetNetworkNetworkHealthChannelUtilizationWifi0 + wifi1 *meraki.ResponseItemNetworksGetNetworkNetworkHealthChannelUtilizationWifi1 + license *meraki.ResponseItemOrganizationsGetOrganizationLicenses + + uplinks []*uplink + switchports []*switchport +} + +func getDevices(client *meraki.Client, organizationID string) (map[Serial]*Device, error) { + val, res, err := client.Organizations.GetOrganizationDevices(organizationID, &meraki.GetOrganizationDevicesQueryParams{}) + + if err != nil { + return nil, fmt.Errorf("GetOrganizationDevices failed; [%d] %s. %w", res.StatusCode(), res.Body(), err) + } + + devices := make(map[Serial]*Device) + for i := range *val { + device := (*val)[i] + devices[Serial(device.Serial)] = &Device{ + details: &device, + } + } + + return devices, nil +} + +func getDeviceStatuses(client *meraki.Client, organizationID string, devices map[Serial]*Device) error { + val, res, err := client.Organizations.GetOrganizationDevicesStatuses(organizationID, &meraki.GetOrganizationDevicesStatusesQueryParams{}) + + if err != nil { + return fmt.Errorf("GetOrganizationDevicesStatuses failed; [%d] %s. %w", res.StatusCode(), res.Body(), err) + } + + for i := range *val { + status := (*val)[i] + if device, ok := devices[Serial(status.Serial)]; ok { + device.status = &status + } + } + + return nil +} + +func getDevicePerformanceScores(client *meraki.Client, devices map[Serial]*Device) error { + for _, device := range devices { + // attempting to get a performance score for a non-MX device returns a 400 + if strings.Index(device.details.Model, "MX") != 0 { + continue + } + + val, res, err := client.Appliance.GetDeviceAppliancePerformance(device.details.Serial) + if err != nil { + return fmt.Errorf("GetDeviceAppliancePerformance failed; [%d] %s. %w", res.StatusCode(), res.Body(), err) + } + + // 204 indicates there is no data for the device, it's likely 'offline' or 'dormant' + if res.StatusCode() != 204 { + device.performanceScore = val + } + } + + return nil +} + +func getDeviceChannelUtilization(client *meraki.Client, devices map[Serial]*Device, period time.Duration) error { + // There are two ways to get this information from the API. + // An alternative to this would be to use `/organizations/{organizationId}/wireless/devices/channelUtilization/byDevice`, + // avoids the need to extract the filtered network IDs below. + // However, the SDK's implementation of that operation doesn't have proper type handling, so we perfer this one. + // (The naming is also a bit different in the returned data, e.g. wifi0/wifi1 vs band 2.4/5; 80211/non80211 vs wifi/nonwifi) + + networkIDs := make(map[string]bool) + for _, device := range devices { + if device.details.ProductType != "wireless" { + continue + } + + if _, ok := networkIDs[device.details.NetworkID]; !ok { + networkIDs[device.details.NetworkID] = true + } + } + + for networkID := range networkIDs { + val, res, err := client.Networks.GetNetworkNetworkHealthChannelUtilization( + networkID, + &meraki.GetNetworkNetworkHealthChannelUtilizationQueryParams{ + Timespan: period.Seconds(), + }, + ) + + if err != nil { + if strings.Contains(string(res.Body()), "MR 27.0") { + // "This endpoint is only available for networks on MR 27.0 or above." + continue + } + + return fmt.Errorf("GetNetworkNetworkHealthChannelUtilization failed; [%d] %s. %w", res.StatusCode(), res.Body(), err) + } + + for _, utilization := range *val { + if device, ok := devices[Serial(utilization.Serial)]; ok { + if utilization.Wifi0 != nil && len(*utilization.Wifi0) != 0 { + // only take the first bucket - collection intervals which result in multiple buckets are not supported + device.wifi0.Utilization80211 = (*utilization.Wifi0)[0].Utilization80211 + device.wifi0.UtilizationNon80211 = (*utilization.Wifi0)[0].UtilizationNon80211 + device.wifi0.UtilizationTotal = (*utilization.Wifi0)[0].UtilizationTotal + } + if utilization.Wifi1 != nil && len(*utilization.Wifi1) != 0 { + device.wifi1.Utilization80211 = (*utilization.Wifi1)[0].Utilization80211 + device.wifi1.UtilizationNon80211 = (*utilization.Wifi1)[0].UtilizationNon80211 + device.wifi1.UtilizationTotal = (*utilization.Wifi1)[0].UtilizationTotal + } + } + } + } + + return nil +} + +func getDeviceLicenses(client *meraki.Client, organizationID string, devices map[Serial]*Device) error { + val, res, err := client.Organizations.GetOrganizationLicenses(organizationID, &meraki.GetOrganizationLicensesQueryParams{}) + if err != nil { + return fmt.Errorf("GetOrganizationLicenses failed; [%d] %s. %w", res.StatusCode(), res.Body(), err) + } + + for i := range *val { + license := (*val)[i] + if device, ok := devices[Serial(license.DeviceSerial)]; ok { + device.license = &license + } + } + + return nil +} + +func deviceDetailsToMapstr(details *meraki.ResponseItemOrganizationsGetOrganizationDevices) mapstr.M { + return mapstr.M{ + "device.serial": details.Serial, + "device.address": details.Address, + "device.firmware": details.Firmware, + "device.imei": details.Imei, + "device.lan_ip": details.LanIP, + "device.location": []*float64{details.Lng, details.Lat}, // (lon, lat) order is important for geo_ip mapping type! + "device.mac": details.Mac, + "device.model": details.Model, + "device.name": details.Name, + "device.network_id": details.NetworkID, + "device.notes": details.Notes, + "device.product_type": details.ProductType, + "device.tags": details.Tags, + } +} + +func reportDeviceMetrics(reporter mb.ReporterV2, organizationID string, devices map[Serial]*Device) { + metrics := []mapstr.M{} + for _, device := range devices { + metric := deviceDetailsToMapstr(device.details) + + if device.haStatus != nil { + metric["device.high_availability.enabled"] = device.haStatus.Enabled + metric["device.high_availability.role"] = device.haStatus.Role + } + + if device.status != nil { + metric["device.status.gateway"] = device.status.Gateway + metric["device.status.ip_type"] = device.status.IPType + metric["device.status.last_reported_at"] = device.status.LastReportedAt + metric["device.status.primary_dns"] = device.status.PrimaryDNS + metric["device.status.public_ip"] = device.status.PublicIP + metric["device.status.secondary_dns"] = device.status.SecondaryDNS + metric["device.status.value"] = device.status.Status + } + + if device.performanceScore != nil { + metric["device.performance_score"] = device.performanceScore.PerfScore + } + + if device.wifi0 != nil { + metric["device.channel_utilization.wifi0.utilization_80211"] = device.wifi0.Utilization80211 + metric["device.channel_utilization.wifi0.utilization_non_80211"] = device.wifi0.UtilizationNon80211 + metric["device.channel_utilization.wifi0.utilization_total"] = device.wifi0.UtilizationTotal + } + + if device.wifi1 != nil { + metric["device.channel_utilization.wifi1.utilization_80211"] = device.wifi1.Utilization80211 + metric["device.channel_utilization.wifi1.utilization_non_80211"] = device.wifi1.UtilizationNon80211 + metric["device.channel_utilization.wifi1.utilization_total"] = device.wifi1.UtilizationTotal + } + + if device.license != nil { + metric["device.license.activation_date"] = device.license.ActivationDate + metric["device.license.claim_date"] = device.license.ClaimDate + metric["device.license.duration_in_days"] = device.license.DurationInDays + metric["device.license.expiration_date"] = device.license.ExpirationDate + metric["device.license.head_license_id"] = device.license.HeadLicenseID + metric["device.license.id"] = device.license.ID + metric["device.license.license_type"] = device.license.LicenseType + metric["device.license.order_number"] = device.license.OrderNumber + metric["device.license.seat_count"] = device.license.SeatCount + metric["device.license.state"] = device.license.State + metric["device.license.total_duration_in_days"] = device.license.TotalDurationInDays + } + + metrics = append(metrics, metric) + } + + reportMetricsForOrganization(reporter, organizationID, metrics) +} diff --git a/x-pack/metricbeat/module/meraki/device_health/switchports.go b/x-pack/metricbeat/module/meraki/device_health/switchports.go new file mode 100644 index 000000000000..b61e052f708d --- /dev/null +++ b/x-pack/metricbeat/module/meraki/device_health/switchports.go @@ -0,0 +1,157 @@ +// 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 device_health + +import ( + "fmt" + "time" + + meraki "github.com/meraki/dashboard-api-go/v3/sdk" + + "github.com/elastic/beats/v7/metricbeat/mb" + "github.com/elastic/elastic-agent-libs/mapstr" +) + +type switchport struct { + port *meraki.ResponseItemSwitchGetOrganizationSwitchPortsBySwitchPorts + portStatus *meraki.ResponseItemSwitchGetDeviceSwitchPortsStatuses +} + +func getDeviceSwitchports(client *meraki.Client, organizationID string, devices map[Serial]*Device, period time.Duration) error { + switches, res, err := client.Switch.GetOrganizationSwitchPortsBySwitch(organizationID, &meraki.GetOrganizationSwitchPortsBySwitchQueryParams{}) + if err != nil { + return fmt.Errorf("GetOrganizationSwitchPortsBySwitch failed; [%d] %s. %w", res.StatusCode(), res.Body(), err) + } + + for _, device := range *switches { + if device.Ports == nil { + continue + } + + var switchports []*switchport + for i := range *device.Ports { + switchports = append(switchports, &switchport{port: &(*device.Ports)[i]}) + } + + statuses, res, err := client.Switch.GetDeviceSwitchPortsStatuses(device.Serial, &meraki.GetDeviceSwitchPortsStatusesQueryParams{ + Timespan: period.Seconds(), + }) + if err != nil { + return fmt.Errorf("GetDeviceSwitchPortsStatuses failed; [%d] %s. %w", res.StatusCode(), res.Body(), err) + } + + // match status to the port attributes found earlier using the shared port ID + for i := range *statuses { + status := (*statuses)[i] + for _, switchport := range switchports { + if switchport.port.PortID == status.PortID { + switchport.portStatus = &status + break + } + } + } + + devices[Serial(device.Serial)].switchports = switchports + } + + return nil +} + +func reportSwitchportMetrics(reporter mb.ReporterV2, organizationID string, devices map[Serial]*Device) { + metrics := []mapstr.M{} + for _, device := range devices { + for _, switchport := range device.switchports { + metric := deviceDetailsToMapstr(device.details) + + if switchport.port != nil { + metric["switch.port.id"] = switchport.port.PortID + metric["switch.port.access_policy_type"] = switchport.port.AccessPolicyType + metric["switch.port.allowed_vlans"] = switchport.port.AllowedVLANs + metric["switch.port.enabled"] = switchport.port.Enabled + metric["switch.port.link_negotiation"] = switchport.port.LinkNegotiation + metric["switch.port.name"] = switchport.port.Name + metric["switch.port.poe_enabled"] = switchport.port.PoeEnabled + metric["switch.port.rstp_enabled"] = switchport.port.RstpEnabled + metric["switch.port.sticky_mac_allow_list"] = switchport.port.StickyMacAllowList + metric["switch.port.sticky_mac_allow_list_limit"] = switchport.port.StickyMacAllowListLimit + metric["switch.port.stp_guard"] = switchport.port.StpGuard + metric["switch.port.tags"] = switchport.port.Tags + metric["switch.port.type"] = switchport.port.Type + metric["switch.port.vlan"] = switchport.port.VLAN + metric["switch.port.voice_vlan"] = switchport.port.VoiceVLAN + } + + if switchport.portStatus != nil { + metric["switch.port.status.client_count"] = switchport.portStatus.ClientCount + metric["switch.port.status.duplex"] = switchport.portStatus.Duplex + metric["switch.port.status.enabled"] = switchport.portStatus.Enabled + metric["switch.port.status.errors"] = switchport.portStatus.Errors + metric["switch.port.status.is_uplink"] = switchport.portStatus.IsUplink + metric["switch.port.status.power_usage_in_wh"] = switchport.portStatus.PowerUsageInWh + metric["switch.port.status.speed"] = switchport.portStatus.Speed + metric["switch.port.status.status"] = switchport.portStatus.Status + metric["switch.port.status.warnings"] = switchport.portStatus.Warnings + + if switchport.portStatus.Cdp != nil { + metric["switch.port.status.cdp.address"] = switchport.portStatus.Cdp.Address + metric["switch.port.status.cdp.capabilities"] = switchport.portStatus.Cdp.Capabilities + metric["switch.port.status.cdp.device_id"] = switchport.portStatus.Cdp.DeviceID + metric["switch.port.status.cdp.management_address"] = switchport.portStatus.Cdp.ManagementAddress + metric["switch.port.status.cdp.native_vlan"] = switchport.portStatus.Cdp.NativeVLAN + metric["switch.port.status.cdp.platform"] = switchport.portStatus.Cdp.Platform + metric["switch.port.status.cdp.port_id"] = switchport.portStatus.Cdp.PortID + metric["switch.port.status.cdp.system_name"] = switchport.portStatus.Cdp.SystemName + metric["switch.port.status.cdp.version"] = switchport.portStatus.Cdp.Version + metric["switch.port.status.cdp.vtp_management_domain"] = switchport.portStatus.Cdp.VtpManagementDomain + } + + if switchport.portStatus.Lldp != nil { + metric["switch.port.status.lldp.chassis_id"] = switchport.portStatus.Lldp.ChassisID + metric["switch.port.status.lldp.management_address"] = switchport.portStatus.Lldp.ManagementAddress + metric["switch.port.status.lldp.management_vlan"] = switchport.portStatus.Lldp.ManagementVLAN + metric["switch.port.status.lldp.port_description"] = switchport.portStatus.Lldp.PortDescription + metric["switch.port.status.lldp.port_id"] = switchport.portStatus.Lldp.PortID + metric["switch.port.status.lldp.port_vlan"] = switchport.portStatus.Lldp.PortVLAN + metric["switch.port.status.lldp.system_capabilities"] = switchport.portStatus.Lldp.SystemCapabilities + metric["switch.port.status.lldp.system_description"] = switchport.portStatus.Lldp.SystemDescription + metric["switch.port.status.lldp.system_name"] = switchport.portStatus.Lldp.SystemName + } + + if switchport.portStatus.SecurePort != nil { + metric["switch.port.status.secure_port.active"] = switchport.portStatus.SecurePort.Active + metric["switch.port.status.secure_port.authentication_status"] = switchport.portStatus.SecurePort.AuthenticationStatus + metric["switch.port.status.secure_port.enabled"] = switchport.portStatus.SecurePort.Enabled + + if switchport.portStatus.SecurePort.ConfigOverrides != nil { + metric["switch.port.status.secure_port.config_overrides.allowed_vlans"] = switchport.portStatus.SecurePort.ConfigOverrides.AllowedVLANs + metric["switch.port.status.secure_port.config_overrides.type"] = switchport.portStatus.SecurePort.ConfigOverrides.Type + metric["switch.port.status.secure_port.config_overrides.vlan"] = switchport.portStatus.SecurePort.ConfigOverrides.VLAN + metric["switch.port.status.secure_port.config_overrides.voice_vlan"] = switchport.portStatus.SecurePort.ConfigOverrides.VoiceVLAN + } + } + + if switchport.portStatus.SpanningTree != nil { + metric["switch.port.status.stp_statuses"] = switchport.portStatus.SpanningTree.Statuses + } + + if switchport.portStatus.TrafficInKbps != nil { + metric["switch.port.status.throughput.recv"] = switchport.portStatus.TrafficInKbps.Recv + metric["switch.port.status.throughput.sent"] = switchport.portStatus.TrafficInKbps.Sent + metric["switch.port.status.throughput.total"] = switchport.portStatus.TrafficInKbps.Total + } + + if switchport.portStatus.UsageInKb != nil { + metric["switch.port.status.usage.recv"] = switchport.portStatus.UsageInKb.Recv + metric["switch.port.status.usage.sent"] = switchport.portStatus.UsageInKb.Sent + metric["switch.port.status.usage.total"] = switchport.portStatus.UsageInKb.Total + } + } + + metrics = append(metrics, metric) + } + } + + reportMetricsForOrganization(reporter, organizationID, metrics) +} diff --git a/x-pack/metricbeat/module/meraki/device_health/uplinks.go b/x-pack/metricbeat/module/meraki/device_health/uplinks.go new file mode 100644 index 000000000000..85a54c267bc6 --- /dev/null +++ b/x-pack/metricbeat/module/meraki/device_health/uplinks.go @@ -0,0 +1,177 @@ +// 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 device_health + +import ( + "fmt" + "time" + + meraki "github.com/meraki/dashboard-api-go/v3/sdk" + + "github.com/elastic/beats/v7/metricbeat/mb" + "github.com/elastic/elastic-agent-libs/mapstr" +) + +type uplink struct { + lastReportedAt string + status *meraki.ResponseItemApplianceGetOrganizationApplianceUplinkStatusesUplinks + cellularGatewayStatus *meraki.ResponseItemCellularGatewayGetOrganizationCellularGatewayUplinkStatusesUplinks + lossAndLatency *meraki.ResponseItemOrganizationsGetOrganizationDevicesUplinksLossAndLatency +} + +func getDeviceUplinks(client *meraki.Client, organizationID string, devices map[Serial]*Device, period time.Duration) error { + // there are two separate APIs for uplink statuses depending on the type of device (MG or MX/Z). + // there is a single API for getting the loss and latency metrics regardless of the type of device. + // in this function we combine loss and latency metrics with device-specific status information, + // and attach it to the relevant device in the supplied `devices` data structure. + applicanceUplinks, res, err := client.Appliance.GetOrganizationApplianceUplinkStatuses(organizationID, &meraki.GetOrganizationApplianceUplinkStatusesQueryParams{}) + if err != nil { + return fmt.Errorf("GetOrganizationApplianceUplinkStatuses failed; [%d] %s. %w", res.StatusCode(), res.Body(), err) + } + + cellularGatewayUplinks, res, err := client.CellularGateway.GetOrganizationCellularGatewayUplinkStatuses(organizationID, &meraki.GetOrganizationCellularGatewayUplinkStatusesQueryParams{}) + if err != nil { + return fmt.Errorf("GetOrganizationCellularGatewayUplinkStatuses failed; [%d] %s. %w", res.StatusCode(), res.Body(), err) + } + + lossAndLatency, res, err := client.Organizations.GetOrganizationDevicesUplinksLossAndLatency( + organizationID, + &meraki.GetOrganizationDevicesUplinksLossAndLatencyQueryParams{ + Timespan: period.Seconds(), + }, + ) + if err != nil { + return fmt.Errorf("GetOrganizationDevicesUplinksLossAndLatency failed; [%d] %s. %w", res.StatusCode(), res.Body(), err) + } + + for _, device := range *applicanceUplinks { + if device.HighAvailability != nil { + devices[Serial(device.Serial)].haStatus = device.HighAvailability + } + + if device.Uplinks != nil { + var uplinks []*uplink + for i := range *device.Uplinks { + uplinkStatus := (*device.Uplinks)[i] + uplink := &uplink{ + lastReportedAt: device.LastReportedAt, + status: &uplinkStatus, + } + + for j := range *lossAndLatency { + metrics := (*lossAndLatency)[j] + if metrics.TimeSeries != nil && metrics.Serial == device.Serial && metrics.Uplink == uplinkStatus.Interface { + uplink.lossAndLatency = &metrics + break + } + } + + uplinks = append(uplinks, uplink) + } + + devices[Serial(device.Serial)].uplinks = uplinks + } + } + + for _, device := range *cellularGatewayUplinks { + if device.Uplinks == nil { + continue + } + + var uplinks []*uplink + for i := range *device.Uplinks { + uplinkStatus := (*device.Uplinks)[i] + uplink := &uplink{ + lastReportedAt: device.LastReportedAt, + cellularGatewayStatus: &uplinkStatus, + } + + for j := range *lossAndLatency { + metrics := (*lossAndLatency)[j] + if metrics.TimeSeries != nil && metrics.Serial == device.Serial && metrics.Uplink == uplinkStatus.Interface { + uplink.lossAndLatency = &metrics + break + } + } + + uplinks = append(uplinks, uplink) + } + + devices[Serial(device.Serial)].uplinks = uplinks + } + + return nil +} + +func reportUplinkMetrics(reporter mb.ReporterV2, organizationID string, devices map[Serial]*Device) { + metrics := []mapstr.M{} + for _, device := range devices { + if len(device.uplinks) == 0 { + continue + } + + for _, uplink := range device.uplinks { + if uplink.lossAndLatency != nil { + // each loss and latency metric can have multiple values per collection. + // we report each value as it's own (smaller) metric event, containing + // the identifying device/uplink fields. + for _, dataPoint := range *uplink.lossAndLatency.TimeSeries { + // for some reason there are sometimes empty buckets + if dataPoint.LatencyMs != nil || dataPoint.LossPercent != nil { + metrics = append(metrics, mapstr.M{ + "@timestamp": dataPoint.Ts, + "uplink.latency.ms": dataPoint.LatencyMs, + "uplink.loss.pct": dataPoint.LossPercent, + + "device.serial": uplink.lossAndLatency.Serial, // _should_ be the same as `device.Serial` + "device.network_id": uplink.lossAndLatency.NetworkID, // _should_ be the same as `device.NetworkID` + "uplink.interface": uplink.lossAndLatency.Uplink, + "uplink.ip": uplink.lossAndLatency.IP, + }) + } + } + } + + statusMetric := deviceDetailsToMapstr(device.details) + statusMetric["uplink.last_reported_at"] = uplink.lastReportedAt + + if uplink.status != nil { + statusMetric["uplink.gateway"] = uplink.status.Gateway + statusMetric["uplink.interface"] = uplink.status.Interface + statusMetric["uplink.ip"] = uplink.status.IP + statusMetric["uplink.primary_dns"] = uplink.status.PrimaryDNS + statusMetric["uplink.secondary_dns"] = uplink.status.SecondaryDNS + statusMetric["uplink.public_ip"] = uplink.status.PublicIP + statusMetric["uplink.status"] = uplink.status.Status + statusMetric["uplink.ip_assigned_by"] = uplink.status.IPAssignedBy + } + + if uplink.cellularGatewayStatus != nil { + statusMetric["uplink.gateway"] = uplink.cellularGatewayStatus.Gateway + statusMetric["uplink.interface"] = uplink.cellularGatewayStatus.Interface + statusMetric["uplink.ip"] = uplink.cellularGatewayStatus.IP + statusMetric["uplink.primary_dns"] = uplink.cellularGatewayStatus.DNS1 + statusMetric["uplink.secondary_dns"] = uplink.cellularGatewayStatus.DNS2 + statusMetric["uplink.public_ip"] = uplink.cellularGatewayStatus.PublicIP + statusMetric["uplink.status"] = uplink.cellularGatewayStatus.Status + statusMetric["uplink.apn"] = uplink.cellularGatewayStatus.Apn + statusMetric["uplink.connection_type"] = uplink.cellularGatewayStatus.ConnectionType + statusMetric["uplink.iccid"] = uplink.cellularGatewayStatus.Iccid + statusMetric["uplink.model"] = uplink.cellularGatewayStatus.Model + statusMetric["uplink.provider"] = uplink.cellularGatewayStatus.Provider + statusMetric["uplink.signal_type"] = uplink.cellularGatewayStatus.SignalType + + if uplink.cellularGatewayStatus.SignalStat != nil { + statusMetric["uplink.rsrp"] = uplink.cellularGatewayStatus.SignalStat.Rsrp + statusMetric["uplink.rsrq"] = uplink.cellularGatewayStatus.SignalStat.Rsrq + } + } + + metrics = append(metrics, statusMetric) + } + } + + reportMetricsForOrganization(reporter, organizationID, metrics) +} diff --git a/x-pack/metricbeat/module/meraki/doc.go b/x-pack/metricbeat/module/meraki/doc.go new file mode 100644 index 000000000000..fe15b0d8f7fd --- /dev/null +++ b/x-pack/metricbeat/module/meraki/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 meraki is a Metricbeat module that contains MetricSets. +package meraki diff --git a/x-pack/metricbeat/module/meraki/fields.go b/x-pack/metricbeat/module/meraki/fields.go new file mode 100644 index 000000000000..fd5e8acbceb8 --- /dev/null +++ b/x-pack/metricbeat/module/meraki/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 meraki + +import ( + "github.com/elastic/beats/v7/libbeat/asset" +) + +func init() { + if err := asset.SetFields("metricbeat", "meraki", asset.ModuleFieldsPri, AssetMeraki); err != nil { + panic(err) + } +} + +// AssetMeraki returns asset data. +// This is the base64 encoded zlib format compressed contents of module/meraki. +func AssetMeraki() string { + return "eJxsjVEOwiAQRP85xVygF9hfvz0EltFsSkuzUA23N6nBIHE+3+y8nbCwClaaX9QBRUuk4KJ5Trg2aoz0mYIbi3fAXRlDFgdgwuZXdgYApe4UPCwd+wd092faKPCpM7/4z/LM+L5l1PbqTFMff6qmX1hfycLQBV25ZU2boNhB9w4AAP//oZRLkQ==" +} diff --git a/x-pack/metricbeat/modules.d/meraki.yml.disabled b/x-pack/metricbeat/modules.d/meraki.yml.disabled new file mode 100644 index 000000000000..489ed4362994 --- /dev/null +++ b/x-pack/metricbeat/modules.d/meraki.yml.disabled @@ -0,0 +1,9 @@ +# Module: meraki +# Docs: https://www.elastic.co/guide/en/beats/metricbeat/8.15/metricbeat-module-meraki.html + +- module: meraki + metricsets: ["device_health"] + enabled: true + period: 300s + apiKey: "Meraki dashboard API key" + organizations: ["Meraki organization ID"]