diff --git a/NOTICE.txt b/NOTICE.txt index 1144db8a2605..042a14e6da16 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -20682,6 +20682,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 @@ -24450,13 +24480,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 @@ -24468,7 +24498,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. @@ -24487,13 +24517,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- Dependency : golang.org/x/mod -Version: v0.19.0 +Version: v0.21.0 Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/golang.org/x/mod@v0.19.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 @@ -24505,7 +24535,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. @@ -24524,13 +24554,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 @@ -24542,7 +24572,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. @@ -24635,13 +24665,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 @@ -24653,7 +24683,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. @@ -24672,13 +24702,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 @@ -24690,7 +24720,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. @@ -24746,13 +24776,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- Dependency : golang.org/x/tools -Version: v0.23.0 +Version: v0.25.0 Licence type (autodetected): BSD-3-Clause -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/golang.org/x/tools@v0.23.0/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 @@ -24764,7 +24794,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. @@ -36349,6 +36379,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 @@ -40346,6 +40407,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 @@ -41433,6 +41525,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 @@ -43274,6 +43403,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 @@ -54724,6 +54885,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-20240205201215-2c58cdc269a3 @@ -54763,13 +54954,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 @@ -54781,7 +54972,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. @@ -55364,6 +55555,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 5081c345039d..c04efbe67632 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.62.0 @@ -138,15 +140,15 @@ 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/mod v0.19.0 - golang.org/x/net v0.27.0 + golang.org/x/crypto v0.27.0 + golang.org/x/mod v0.21.0 + golang.org/x/net v0.29.0 golang.org/x/oauth2 v0.22.0 golang.org/x/sync v0.8.0 - golang.org/x/sys v0.22.0 - golang.org/x/text v0.16.0 + golang.org/x/sys v0.25.0 + golang.org/x/text v0.18.0 golang.org/x/time v0.6.0 - golang.org/x/tools v0.23.0 + golang.org/x/tools v0.25.0 google.golang.org/api v0.191.0 google.golang.org/genproto v0.0.0-20240730163845-b1a4ccb954bf // indirect google.golang.org/grpc v1.64.1 @@ -209,6 +211,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 @@ -260,6 +263,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.16 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 // indirect + github.com/benbjohnson/clock v1.3.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bluekeyes/go-gitdiff v0.7.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect @@ -290,6 +294,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 @@ -300,6 +305,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.8 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect @@ -370,8 +376,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-20240205201215-2c58cdc269a3 // 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/genproto/googleapis/rpc v0.0.0-20240730163845-b1a4ccb954bf // indirect gopkg.in/yaml.v3 v3.0.1 // indirect @@ -408,5 +415,6 @@ 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 ) diff --git a/go.sum b/go.sum index 838744dab133..09be9abe508d 100644 --- a/go.sum +++ b/go.sum @@ -387,6 +387,8 @@ github.com/awslabs/goformation/v7 v7.14.9/go.mod h1:7obldQ8NQ/AkMsgL5K3l4lRMDFB6 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= @@ -806,6 +808,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= @@ -958,6 +962,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= @@ -1044,6 +1050,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= @@ -1629,6 +1637,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= @@ -1770,6 +1780,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= @@ -1816,11 +1828,12 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= 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= @@ -1879,8 +1892,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 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/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= -golang.org/x/mod v0.19.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= @@ -1958,9 +1971,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= @@ -2110,11 +2124,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= @@ -2123,11 +2138,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= @@ -2144,8 +2160,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= @@ -2153,6 +2169,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.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -2243,8 +2260,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.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= -golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= +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/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2417,6 +2434,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 7748bf87d44f..4a81b7660061 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 48b8b97ca601..274e58282764 100644 --- a/x-pack/metricbeat/metricbeat.reference.yml +++ b/x-pack/metricbeat/metricbeat.reference.yml @@ -1101,6 +1101,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"] @@ -1309,9 +1317,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: @@ -1320,20 +1330,14 @@ metricbeat.modules: #username: "user" #password: "secret" + # Count number of metrics present in Elasticsearch document (default: false) + #metrics_count: false + # This can be used for service account based authorization: #bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token #ssl.certificate_authorities: # - /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt - # Count number of metrics present in Elasticsearch document (default: false) - #metrics_count: false - - # 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 @@ -1341,24 +1345,12 @@ metricbeat.modules: # host: "localhost" # port: "9201" - # Secure settings for the server using TLS/SSL: - #ssl.certificate: "/etc/pki/server/cert.pem" - #ssl.key: "/etc/pki/server/cert.key" - # Count number of metrics present in Elasticsearch document (default: false) #metrics_count: false - # 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: [] + # Secure settings for the server using TLS/SSL: + #ssl.certificate: "/etc/pki/server/cert.pem" + #ssl.key: "/etc/pki/server/cert.key" # Metrics that will be collected using a PromQL #- module: prometheus @@ -1386,11 +1378,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: @@ -1399,14 +1389,20 @@ metricbeat.modules: #username: "user" #password: "secret" - # Count number of metrics present in Elasticsearch document (default: false) - #metrics_count: false - # This can be used for service account based authorization: #bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token #ssl.certificate_authorities: # - /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt + # Count number of metrics present in Elasticsearch document (default: false) + #metrics_count: false + + # 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 @@ -1414,13 +1410,25 @@ metricbeat.modules: # host: "localhost" # port: "9201" - # Count number of metrics present in Elasticsearch document (default: false) - #metrics_count: false - # Secure settings for the server using TLS/SSL: #ssl.certificate: "/etc/pki/server/cert.pem" #ssl.key: "/etc/pki/server/cert.key" + # Count number of metrics present in Elasticsearch document (default: false) + #metrics_count: false + + # 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..c2d5c9db635f --- /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/main/metricbeat-module-meraki.html + +- module: meraki + metricsets: ["device_health"] + enabled: true + period: 300s + apiKey: "Meraki dashboard API key" + organizations: ["Meraki organization ID"]