├── .gitignore ├── .res └── grafana.png ├── LICENSE ├── README.md ├── cmd └── root.go ├── go.mod ├── go.sum ├── internal ├── config │ └── config.go ├── dsl │ ├── config.go │ └── dsl.go ├── exporter │ └── exporter.go └── rtop │ └── rtop.go └── main.go /.gitignore: -------------------------------------------------------------------------------- 1 | ### Go 2 | # Binaries for programs and plugins 3 | *.exe 4 | *.exe~ 5 | *.dll 6 | *.so 7 | *.dylib 8 | 9 | # Test binary, built with `go test -c` 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | 15 | # Dependency directories (remove the comment below to include it) 16 | vendor/ 17 | 18 | .idea 19 | .vscode 20 | 21 | xdsl-exporter 22 | -------------------------------------------------------------------------------- /.res/grafana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dentrax/xdsl-exporter/a2fbf069ef3c8e604fdf374e6e2234dff61004e1/.res/grafana.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

xDSL Exporter

2 | 3 |
4 | 5 | A Prometheus Exporter for your xDSL Modem 6 | 7 |
8 | 9 |
10 | 11 | **ARTICLE:** [How to monitor an xDSL Modem using a Prometheus Exporter plugin and Grafana Agent on Grafana Cloud with Grafana OnCall](https://grafana.com/blog/2023/03/17/how-to-monitor-an-xdsl-modem-using-a-prometheus-exporter-plugin-and-grafana-agent-on-grafana-cloud-with-grafana-oncall/?mdm=github) 12 | 13 | ## Overview 14 | 15 | ![Overview](.res/grafana.png) 16 | 17 | ## Prerequisites 18 | 19 | * Enable SSH or Telnet on your modem 20 | * Set idle Timeout set to 0 (infinite) 21 | 22 | ## Installation 23 | 24 | ``` 25 | $ git clone git@github.com:Dentrax/xdsl-exporter.git 26 | $ cd xdsl-exporter 27 | $ go run . --target-client 28 | ``` 29 | 30 | * Please see the vendor list below for supported vendors. 31 | * Please read the Disclaimer section below before using this exporter. 32 | 33 | ## Usage 34 | 35 | ``` 36 | Usage: 37 | xdsl-exporter [flags] 38 | 39 | Flags: 40 | -h, --help help for xdsl-exporter 41 | --known-hosts-path string Path to your known_hosts file. (default "~/.ssh/known_hosts") 42 | --listen-address string Address on which to expose metrics and web interface. (default ":9090") 43 | --metrics-path string Path under which to expose metrics. (default "/metrics") 44 | --target-client string Broadcom (SSH),Broadcom (Telnet),DrayTek (Telnet),FRITZ!Box,Lantiq (SSH),Lantiq (Telnet),MediaTek (SSH),MediaTek (Telnet),Sagemcom,Speedport 45 | --target-host string Hostname or IP address of the target xDSL Modem (default "192.168.1.1") 46 | --target-password string Host password 47 | --target-port int Port of the target xDSL Modem (default 22) 48 | --target-ssh-key-path string Path to the SSH key to use for authentication 49 | --target-ssh-passphrase string Passphrase to use for the SSH key 50 | --target-user string Host user (default "admin") 51 | ``` 52 | 53 | ## Supported Vendors 54 | 55 | - Broadcom (SSH): `broadcom_ssh` 56 | - Broadcom (Telnet): `broadcom_telnet` 57 | - DrayTek (Telnet): `draytek_telnet` 58 | - FRITZ!Box: `fritzbox` 59 | - Lantiq (SSH): `lantiq_ssh` 60 | - Lantiq (Telnet): `lantiq_telnet` 61 | - MediaTek (SSH): `mediatek_ssh` 62 | - MediaTek (Telnet): `mediatek_telnet` 63 | - Sagemcom: `sagemcom` 64 | - Speedport: `speedport` 65 | 66 | ## Known Issues 67 | 68 | - If SSH connection get closed by the target, the exporter will not reconnect automatically. You need to restart the exporter. 69 | - If modem is highly loaded (e.g. full bandwidth Steam downloads), the export process might take longer than the default scrape interval of 15 seconds. This will result in a timeout and the modem will not be scraped by Prometheus. You can increase both of the scrape interval and timeout to avoid this issue. 70 | 71 | # Special Thanks 72 | 73 | | Package | Author | License | 74 | |:---------------------------------------------|:-------------------------------------------------------|:-------------------------------------------------------------------------------------| 75 | | [go-dsl](https://github.com/janh/go-dsl) | [Jan Hoffmann](https://github.com/janh) | [Mozilla Public License 2.0](https://github.com/janh/go-dsl/blob/master/LICENSE) | 76 | | [rtop](https://github.com/rapidloop/rtop) | [RapidLoop](https://github.com/rapidloop) | [MIT](https://github.com/rapidloop/rtop/blob/master/LICENSE) | 77 | 78 | - Thanks to everyone who contributed these libraries and [others](https://github.com/Dentrax/xdsl-exporter/blob/main/go.mod) that made this project possible. 79 | 80 | # Disclaimer 81 | 82 | I accept no responsibility for any damage that may occur to your device during your installation, and such damages and exclusion of warranty is not by reason of my negligence. You are under this agreement. You use at your own risk. 83 | 84 | # License 85 | 86 | *cocert* was created by [Furkan 'Dentrax' Türkal](https://twitter.com/furkanturkaI) 87 | 88 | The base project code is licensed under [Apache 2.0](https://opensource.org/licenses/Apache-2.0) unless otherwise specified. Please see the **[LICENSE](https://github.com/Dentrax/xdsl-exporter/blob/main/LICENSE)** file for more information. 89 | 90 | Best Regards 91 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2022 Furkan Türkal 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package cmd 18 | 19 | import ( 20 | "fmt" 21 | "github.com/Dentrax/xdsl-exporter/internal/rtop" 22 | "net/http" 23 | "os" 24 | "os/signal" 25 | "strings" 26 | "syscall" 27 | "time" 28 | 29 | "github.com/Dentrax/xdsl-exporter/internal/config" 30 | "github.com/Dentrax/xdsl-exporter/internal/dsl" 31 | "github.com/Dentrax/xdsl-exporter/internal/exporter" 32 | "github.com/go-kit/log/level" 33 | "github.com/prometheus/client_golang/prometheus" 34 | "github.com/prometheus/client_golang/prometheus/promhttp" 35 | "github.com/prometheus/common/promlog" 36 | "github.com/prometheus/common/version" 37 | "github.com/prometheus/exporter-toolkit/web" 38 | "github.com/spf13/cobra" 39 | 40 | "github.com/mitchellh/go-homedir" 41 | "github.com/spf13/viper" 42 | ) 43 | 44 | var ( 45 | cfg = config.Config{} 46 | cfgFile string 47 | cmd = &cobra.Command{ 48 | Use: "xdsl-exporter", 49 | Short: "A Prometheus Exporter for your rusty xDSL Modem", 50 | SilenceUsage: true, 51 | SilenceErrors: true, 52 | RunE: func(cmd *cobra.Command, args []string) error { 53 | return run() 54 | }, 55 | } 56 | ) 57 | 58 | func Execute() { 59 | if err := cmd.Execute(); err != nil { 60 | fmt.Println(err) 61 | os.Exit(1) 62 | } 63 | } 64 | 65 | func init() { 66 | cobra.OnInitialize(initConfig) 67 | 68 | cmd.PersistentFlags().StringVar(&cfg.ListenAddress, "listen-address", ":9090", "Address on which to expose metrics and web interface.") 69 | cmd.PersistentFlags().StringVar(&cfg.MetricsPath, "metrics-path", "/metrics", "Path under which to expose metrics.") 70 | cmd.PersistentFlags().StringVar(&cfg.KnownHostsPath, "known-hosts-path", "~/.ssh/known_hosts", "Path to your known_hosts file.") 71 | cmd.PersistentFlags().StringVar(&cfg.TargetHost, "target-host", "192.168.1.1", "Hostname or IP address of the target xDSL Modem") 72 | cmd.PersistentFlags().IntVar(&cfg.TargetPort, "target-port", 22, "Port of the target xDSL Modem") 73 | cmd.PersistentFlags().StringVar(&cfg.TargetUser, "target-user", "admin", "Host user") 74 | cmd.PersistentFlags().StringVar(&cfg.TargetPassword, "target-password", "", "Host password") 75 | cmd.PersistentFlags().StringVar(&cfg.TargetSSHKeyPath, "target-ssh-key-path", "", "Path to the SSH key to use for authentication") 76 | cmd.PersistentFlags().StringVar(&cfg.TargetSSHPassphrase, "target-ssh-passphrase", "", "Passphrase to use for the SSH key") 77 | cmd.PersistentFlags().StringVar(&cfg.TargetClient, "target-client", "", strings.Join(dsl.GetSupportedClients(), ",")) 78 | } 79 | 80 | func initConfig() { 81 | if cfgFile != "" { 82 | viper.SetConfigFile(cfgFile) 83 | } else { 84 | home, err := homedir.Dir() 85 | if err != nil { 86 | fmt.Println(err) 87 | os.Exit(1) 88 | } 89 | viper.AddConfigPath(home) 90 | viper.SetConfigName(".xdsl-exporter") 91 | } 92 | viper.AutomaticEnv() 93 | if err := viper.ReadInConfig(); err == nil { 94 | fmt.Println("Using config file:", viper.ConfigFileUsed()) 95 | } 96 | } 97 | 98 | func run() error { 99 | promlogConfig := &promlog.Config{ 100 | Level: &promlog.AllowedLevel{}, 101 | } 102 | promlogConfig.Level.Set("info") 103 | logger := promlog.New(promlogConfig) 104 | 105 | prometheus.MustRegister(version.NewCollector("xdsl_exporter")) 106 | 107 | if err := cfg.Check(); err != nil { 108 | return fmt.Errorf("config check: %w", err) 109 | } 110 | 111 | dslClient, err := dsl.New(cfg) 112 | if err != nil { 113 | return err 114 | } 115 | 116 | rtopClient, err := rtop.New(cfg) 117 | if err != nil { 118 | return err 119 | } 120 | 121 | exporter := exporter.New(dslClient, rtopClient, logger) 122 | prometheus.MustRegister(exporter) 123 | 124 | http.Handle(cfg.MetricsPath, promhttp.Handler()) 125 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 126 | w.Write([]byte(` 127 | 128 | xDSL Exporter Metrics 129 | 130 |

Metrics

131 | 132 | 133 | `)) 134 | }) 135 | 136 | go func() { 137 | level.Info(logger).Log("msg", "Listening on address", "address", cfg.ListenAddress) //nolint:errcheck 138 | srv := &http.Server{ 139 | Addr: cfg.ListenAddress, 140 | ReadHeaderTimeout: 60 * time.Second, 141 | } 142 | if err := web.ListenAndServe(srv, "", logger); err != nil { 143 | level.Error(logger).Log("msg", "Error running HTTP server", "err", err) //nolint:errcheck 144 | os.Exit(1) 145 | } 146 | }() 147 | done := make(chan struct{}) 148 | go func() { 149 | level.Info(logger).Log("msg", "Listening signals...") //nolint:errcheck 150 | c := make(chan os.Signal, 1) 151 | signal.Notify(c, os.Interrupt, syscall.SIGTERM) 152 | <-c 153 | exporter.CloseClient() 154 | close(done) 155 | }() 156 | 157 | <-done 158 | level.Info(logger).Log("msg", "Shutting down...") //nolint:errcheck 159 | 160 | return nil 161 | } 162 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Dentrax/xdsl-exporter 2 | 3 | go 1.19 4 | 5 | require ( 6 | 3e8.eu/go/dsl v0.0.0-20220610130843-19df3dc8d05e 7 | github.com/go-kit/log v0.2.0 8 | github.com/mitchellh/go-homedir v1.1.0 9 | github.com/prometheus/client_golang v1.13.0 10 | github.com/prometheus/common v0.37.0 11 | github.com/prometheus/exporter-toolkit v0.7.1 12 | github.com/rapidloop/rtop v0.0.0-20220606143554-4dcd50bfc7e3 13 | github.com/spf13/cobra v1.5.0 14 | github.com/spf13/viper v1.12.0 15 | ) 16 | 17 | replace github.com/rapidloop/rtop => github.com/Dentrax/rtop v0.0.0-20220903202932-65d9232dd7e9 18 | 19 | require ( 20 | github.com/beorn7/perks v1.0.1 // indirect 21 | github.com/cespare/xxhash/v2 v2.1.2 // indirect 22 | github.com/fatih/semgroup v1.2.0 // indirect 23 | github.com/fsnotify/fsnotify v1.5.4 // indirect 24 | github.com/go-logfmt/logfmt v0.5.1 // indirect 25 | github.com/golang/protobuf v1.5.2 // indirect 26 | github.com/hashicorp/hcl v1.0.0 // indirect 27 | github.com/inconshreveable/mousetrap v1.0.0 // indirect 28 | github.com/jpillora/backoff v1.0.0 // indirect 29 | github.com/magiconair/properties v1.8.6 // indirect 30 | github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect 31 | github.com/mitchellh/mapstructure v1.5.0 // indirect 32 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect 33 | github.com/pelletier/go-toml v1.9.5 // indirect 34 | github.com/pelletier/go-toml/v2 v2.0.1 // indirect 35 | github.com/pkg/errors v0.9.1 // indirect 36 | github.com/prometheus/client_model v0.2.0 // indirect 37 | github.com/prometheus/procfs v0.8.0 // indirect 38 | github.com/spf13/afero v1.8.2 // indirect 39 | github.com/spf13/cast v1.5.0 // indirect 40 | github.com/spf13/jwalterweatherman v1.1.0 // indirect 41 | github.com/spf13/pflag v1.0.5 // indirect 42 | github.com/subosito/gotenv v1.3.0 // indirect 43 | github.com/ziutek/telnet v0.0.0-20180329124119-c3b780dc415b // indirect 44 | golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect 45 | golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 // indirect 46 | golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect 47 | golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect 48 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect 49 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect 50 | golang.org/x/text v0.3.7 // indirect 51 | google.golang.org/appengine v1.6.7 // indirect 52 | google.golang.org/protobuf v1.28.1 // indirect 53 | gopkg.in/ini.v1 v1.66.4 // indirect 54 | gopkg.in/yaml.v2 v2.4.0 // indirect 55 | gopkg.in/yaml.v3 v3.0.0 // indirect 56 | ) 57 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | 3e8.eu/go/dsl v0.0.0-20220610130843-19df3dc8d05e h1:ig2ujhjou+ojhgixoWxwqQ5LfaJBspQstAwVDnNbErk= 2 | 3e8.eu/go/dsl v0.0.0-20220610130843-19df3dc8d05e/go.mod h1:chnuGPDpYjf07KzabHc9zFswSFS7NnZ8LEK+2qZWjSY= 3 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 4 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 5 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 6 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 7 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 8 | cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 9 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 10 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 11 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 12 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 13 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 14 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 15 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= 16 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 17 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 18 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 19 | cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= 20 | cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= 21 | cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= 22 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 23 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 24 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 25 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 26 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 27 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 28 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 29 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 30 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 31 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 32 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 33 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 34 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 35 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 36 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 37 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 38 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 39 | cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= 40 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 41 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 42 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 43 | github.com/Dentrax/rtop v0.0.0-20220903202932-65d9232dd7e9 h1:142mSEXBpOmb146vx7TiOBShbKqgN3dcoJozfkEBgVs= 44 | github.com/Dentrax/rtop v0.0.0-20220903202932-65d9232dd7e9/go.mod h1:J0D4BRlaWGf1puZqjnPmBKHO53t3X/r5XwdFdj6i7ls= 45 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 46 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 47 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 48 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 49 | github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= 50 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 51 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 52 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 53 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 54 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 55 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 56 | github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= 57 | github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 58 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 59 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 60 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 61 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 62 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 63 | github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 64 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 65 | github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 66 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 67 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 68 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 69 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 70 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 71 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 72 | github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= 73 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 74 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 75 | github.com/fatih/semgroup v1.2.0 h1:h/OLXwEM+3NNyAdZEpMiH1OzfplU09i2qXPVThGZvyg= 76 | github.com/fatih/semgroup v1.2.0/go.mod h1:1KAD4iIYfXjE4U13B48VM4z9QUwV5Tt8O4rS879kgm8= 77 | github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= 78 | github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= 79 | github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= 80 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 81 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 82 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 83 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 84 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 85 | github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= 86 | github.com/go-kit/log v0.2.0 h1:7i2K3eKTos3Vc0enKCfnVcgHh2olr/MyfboYq7cAcFw= 87 | github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= 88 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 89 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 90 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= 91 | github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= 92 | github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= 93 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 94 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 95 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 96 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 97 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 98 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 99 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 100 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 101 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 102 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 103 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 104 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 105 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 106 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 107 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 108 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 109 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 110 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 111 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 112 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 113 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 114 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 115 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 116 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 117 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 118 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 119 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 120 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 121 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 122 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 123 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 124 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 125 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 126 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 127 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 128 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 129 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 130 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 131 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 132 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 133 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 134 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 135 | github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= 136 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 137 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 138 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 139 | github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 140 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 141 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 142 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 143 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 144 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 145 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 146 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 147 | github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 148 | github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 149 | github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 150 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 151 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 152 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 153 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 154 | github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= 155 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 156 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 157 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 158 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 159 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 160 | github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 161 | github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= 162 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 163 | github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= 164 | github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= 165 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 166 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 167 | github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 168 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 169 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 170 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 171 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 172 | github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= 173 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 174 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 175 | github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 176 | github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 177 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 178 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 179 | github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= 180 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 181 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 182 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 183 | github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= 184 | github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= 185 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 186 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 187 | github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= 188 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 189 | github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= 190 | github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 191 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 192 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 193 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 194 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 195 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 196 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 197 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= 198 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 199 | github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= 200 | github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= 201 | github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= 202 | github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= 203 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 204 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 205 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 206 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 207 | github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= 208 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 209 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 210 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 211 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 212 | github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= 213 | github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= 214 | github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= 215 | github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= 216 | github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= 217 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 218 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 219 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 220 | github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= 221 | github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 222 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 223 | github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= 224 | github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= 225 | github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= 226 | github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= 227 | github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= 228 | github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= 229 | github.com/prometheus/exporter-toolkit v0.7.1 h1:c6RXaK8xBVercEeUQ4tRNL8UGWzDHfvj9dseo1FcK1Y= 230 | github.com/prometheus/exporter-toolkit v0.7.1/go.mod h1:ZUBIj498ePooX9t/2xtDjeQYwvRpiPP2lh5u4iblj2g= 231 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 232 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 233 | github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= 234 | github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 235 | github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 236 | github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= 237 | github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= 238 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 239 | github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= 240 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 241 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 242 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 243 | github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= 244 | github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= 245 | github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= 246 | github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= 247 | github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= 248 | github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= 249 | github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= 250 | github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= 251 | github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= 252 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 253 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 254 | github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= 255 | github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= 256 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 257 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 258 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 259 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 260 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 261 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 262 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 263 | github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= 264 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 265 | github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= 266 | github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= 267 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 268 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 269 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 270 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 271 | github.com/ziutek/telnet v0.0.0-20180329124119-c3b780dc415b h1:VfPXB/wCGGt590QhD1bOpv2J/AmC/RJNTg/Q59HKSB0= 272 | github.com/ziutek/telnet v0.0.0-20180329124119-c3b780dc415b/go.mod h1:IZpXDfkJ6tWD3PhBK5YzgQT+xJWh7OsdwiG8hA2MkO4= 273 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 274 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 275 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 276 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 277 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 278 | go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= 279 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 280 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 281 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 282 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 283 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 284 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 285 | golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 286 | golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 287 | golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 288 | golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= 289 | golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 290 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 291 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 292 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 293 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 294 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 295 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 296 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 297 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 298 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 299 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 300 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 301 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 302 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 303 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 304 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 305 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 306 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 307 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 308 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 309 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 310 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 311 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 312 | golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 313 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 314 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 315 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 316 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 317 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 318 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 319 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 320 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 321 | golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 322 | golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 323 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 324 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 325 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 326 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 327 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 328 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 329 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 330 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 331 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 332 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 333 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 334 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 335 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 336 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 337 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 338 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 339 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 340 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 341 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 342 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 343 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 344 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 345 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 346 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 347 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 348 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 349 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 350 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 351 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 352 | golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 353 | golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 354 | golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 355 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 356 | golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 357 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 358 | golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 359 | golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 h1:NWy5+hlRbC7HK+PmcXVUmW1IMyFce7to56IUvhUFm7Y= 360 | golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 361 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 362 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 363 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 364 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 365 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 366 | golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 367 | golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 368 | golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 369 | golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 370 | golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 371 | golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= 372 | golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE= 373 | golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= 374 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 375 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 376 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 377 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 378 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 379 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 380 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 381 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 382 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 383 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 384 | golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8= 385 | golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 386 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 387 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 388 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 389 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 390 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 391 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 392 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 393 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 394 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 395 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 396 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 397 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 398 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 399 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 400 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 401 | golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 402 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 403 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 404 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 405 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 406 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 407 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 408 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 409 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 410 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 411 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 412 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 413 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 414 | golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 415 | golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 416 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 417 | golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 418 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 419 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 420 | golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 421 | golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 422 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 423 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 424 | golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 425 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 426 | golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 427 | golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 428 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 429 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 430 | golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 431 | golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 432 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= 433 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 434 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 435 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= 436 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 437 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 438 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 439 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 440 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 441 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 442 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 443 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 444 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 445 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 446 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 447 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 448 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 449 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 450 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 451 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 452 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 453 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 454 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 455 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 456 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 457 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 458 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 459 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 460 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 461 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 462 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 463 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 464 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 465 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 466 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 467 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 468 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 469 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 470 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 471 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 472 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 473 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 474 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 475 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 476 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 477 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 478 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 479 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 480 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 481 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 482 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 483 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 484 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 485 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 486 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 487 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 488 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 489 | golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= 490 | golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 491 | golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 492 | golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 493 | golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 494 | golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 495 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 496 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 497 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 498 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 499 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 500 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 501 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 502 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 503 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 504 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 505 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 506 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 507 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 508 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 509 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 510 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 511 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 512 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 513 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 514 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 515 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 516 | google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= 517 | google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= 518 | google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= 519 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 520 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 521 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 522 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 523 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 524 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 525 | google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= 526 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 527 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 528 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 529 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 530 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 531 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 532 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 533 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 534 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 535 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 536 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 537 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 538 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 539 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 540 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 541 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 542 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 543 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 544 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 545 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 546 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 547 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 548 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 549 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 550 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 551 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 552 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 553 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 554 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 555 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 556 | google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 557 | google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 558 | google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 559 | google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 560 | google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 561 | google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 562 | google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 563 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 564 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 565 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 566 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 567 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 568 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 569 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 570 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 571 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 572 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 573 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 574 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 575 | google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 576 | google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 577 | google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= 578 | google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 579 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 580 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 581 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 582 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 583 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 584 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 585 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 586 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 587 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 588 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 589 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 590 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 591 | google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= 592 | google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 593 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 594 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 595 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 596 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 597 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 598 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 599 | gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= 600 | gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 601 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 602 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 603 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 604 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 605 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 606 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 607 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 608 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 609 | gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= 610 | gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 611 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 612 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 613 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 614 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 615 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 616 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 617 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 618 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 619 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 620 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 621 | -------------------------------------------------------------------------------- /internal/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "fmt" 5 | "net/url" 6 | "os" 7 | 8 | "github.com/mitchellh/go-homedir" 9 | ) 10 | 11 | type Config struct { 12 | ListenAddress string 13 | MetricsPath string 14 | KnownHostsPath string 15 | TargetHost string 16 | TargetPort int 17 | TargetUser string 18 | TargetPassword string 19 | TargetSSHKeyPath string 20 | TargetSSHPassphrase string 21 | TargetClient string 22 | } 23 | 24 | func (c Config) Check() error { 25 | if c.ListenAddress == "" { 26 | return fmt.Errorf("listen address is empty") 27 | } 28 | 29 | if c.MetricsPath == "" { 30 | return fmt.Errorf("metrics path is empty") 31 | } 32 | 33 | if c.TargetHost == "" { 34 | return fmt.Errorf("target host is empty") 35 | } 36 | 37 | _, err := url.Parse(c.TargetHost) 38 | if err != nil { 39 | return fmt.Errorf("invalid target host: %w", err) 40 | } 41 | 42 | if c.TargetUser == "" { 43 | return fmt.Errorf("target user is empty") 44 | } 45 | 46 | if c.TargetPassword == "" && c.TargetSSHKeyPath == "" { 47 | return fmt.Errorf("no password or ssh key path provided") 48 | } 49 | 50 | return nil 51 | } 52 | 53 | func (c Config) ReadSSHKey() (string, error) { 54 | value, err := os.ReadFile(c.TargetSSHKeyPath) 55 | if err != nil { 56 | return "", fmt.Errorf("read ssh key: %w", err) 57 | } 58 | return string(value), nil 59 | } 60 | 61 | func (c Config) ReadKnownHosts() (string, error) { 62 | expanded, err := homedir.Expand(c.KnownHostsPath) 63 | if err != nil { 64 | return "", fmt.Errorf("get known_hosts: %w", err) 65 | } 66 | 67 | value, err := os.ReadFile(expanded) 68 | if err != nil { 69 | return "", fmt.Errorf("read known_hosts: %w", err) 70 | } 71 | return string(value), nil 72 | } 73 | -------------------------------------------------------------------------------- /internal/dsl/config.go: -------------------------------------------------------------------------------- 1 | package dsl 2 | 3 | import ( 4 | "fmt" 5 | 6 | "3e8.eu/go/dsl" 7 | 8 | "github.com/Dentrax/xdsl-exporter/internal/config" 9 | ) 10 | 11 | func GenerateConfigFrom(cfg config.Config) (*dsl.Config, error) { 12 | client := dsl.ClientType(cfg.TargetClient) 13 | if !client.IsValid() { 14 | return nil, fmt.Errorf("invalid client type: %s: alloweds: %s", client, GetSupportedClients()) 15 | } 16 | 17 | sshKey, err := cfg.ReadSSHKey() 18 | if err != nil { 19 | return nil, err 20 | } 21 | 22 | knownHosts, err := cfg.ReadKnownHosts() 23 | if err != nil { 24 | return nil, err 25 | } 26 | 27 | return &dsl.Config{ 28 | Type: client, 29 | Host: cfg.TargetHost, 30 | User: cfg.TargetUser, 31 | AuthPassword: getAuthPassword(cfg.TargetPassword), 32 | AuthPrivateKeys: getAuthPrivateKeys(sshKey, cfg.TargetSSHPassphrase), 33 | KnownHosts: knownHosts, 34 | Options: nil, 35 | }, nil 36 | } 37 | 38 | func getAuthPassword(password string) dsl.PasswordCallback { 39 | if password == "" { 40 | return nil 41 | } 42 | return dsl.Password(password) 43 | } 44 | 45 | func getAuthPrivateKeys(sshKey, sshKeyPassphrase string) dsl.PrivateKeysCallback { 46 | getKeys := func(sshKey string) func() ([]string, error) { 47 | if sshKey == "" { 48 | return nil 49 | } 50 | return func() ([]string, error) { 51 | return []string{sshKey}, nil 52 | } 53 | } 54 | 55 | getPassphrase := func(sshKeyPassphrase string) func(fingerprint string) (string, error) { 56 | if sshKeyPassphrase == "" { 57 | return nil 58 | } 59 | return func(fingerprint string) (string, error) { 60 | return sshKeyPassphrase, nil 61 | } 62 | } 63 | 64 | return dsl.PrivateKeysCallback{ 65 | Keys: getKeys(sshKey), 66 | Passphrase: getPassphrase(sshKeyPassphrase), 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /internal/dsl/dsl.go: -------------------------------------------------------------------------------- 1 | package dsl 2 | 3 | import ( 4 | "fmt" 5 | 6 | "3e8.eu/go/dsl" 7 | 8 | "github.com/Dentrax/xdsl-exporter/internal/config" 9 | ) 10 | 11 | func GetSupportedClients() []string { 12 | clientTypes := dsl.GetClientTypes() 13 | var result []string 14 | for _, clientType := range clientTypes { 15 | result = append(result, clientType.ClientDesc().Title) 16 | } 17 | return result 18 | } 19 | 20 | func New(cfg config.Config) (dsl.Client, error) { 21 | c, err := GenerateConfigFrom(cfg) 22 | if err != nil { 23 | return nil, fmt.Errorf("generate dsl config: %w", err) 24 | } 25 | 26 | client, err := dsl.NewClient(*c) 27 | if err != nil { 28 | return nil, fmt.Errorf("new dsl client: %w", err) 29 | } 30 | 31 | return client, nil 32 | } 33 | -------------------------------------------------------------------------------- /internal/exporter/exporter.go: -------------------------------------------------------------------------------- 1 | package exporter 2 | 3 | import ( 4 | "3e8.eu/go/dsl" 5 | "github.com/go-kit/log" 6 | "github.com/go-kit/log/level" 7 | "github.com/prometheus/client_golang/prometheus" 8 | rtop "github.com/rapidloop/rtop/pkg/client" 9 | "github.com/rapidloop/rtop/pkg/types" 10 | "strconv" 11 | ) 12 | 13 | const ( 14 | Namespace = "xdsl" 15 | SubsystemDsl = "dsl" 16 | SubsystemRtop = "rtop" 17 | ) 18 | 19 | type Exporter struct { 20 | dsl dsl.Client 21 | rtop *rtop.Client 22 | logger log.Logger 23 | 24 | // via go-dsl 25 | // see: https://github.com/janh/go-dsl/blob/690a62b79cd43d01b5f10fe2ef0d1a8a2b3f00f7/models/status.go#L13-L77 26 | state *prometheus.Desc 27 | mode *prometheus.Desc 28 | uptime *prometheus.Desc 29 | farEndInventory *prometheus.Desc 30 | nearEndInventory *prometheus.Desc 31 | downstreamActualRate *prometheus.Desc 32 | upstreamActualRate *prometheus.Desc 33 | downstreamAttainableRate *prometheus.Desc 34 | upstreamAttainableRate *prometheus.Desc 35 | downstreamMinimumErrorFreeThroughput *prometheus.Desc 36 | upstreamMinimumErrorFreeThroughput *prometheus.Desc 37 | downstreamBitswapEnabled *prometheus.Desc 38 | upstreamBitswapEnabled *prometheus.Desc 39 | downstreamSeamlessRateAdaption *prometheus.Desc 40 | upstreamSeamlessRateAdaption *prometheus.Desc 41 | downstreamInterleavingDelay *prometheus.Desc 42 | upstreamInterleavingDelay *prometheus.Desc 43 | downstreamImpulseNoiseProtection *prometheus.Desc 44 | upstreamImpulseNoiseProtection *prometheus.Desc 45 | downstreamRetransmissionEnabled *prometheus.Desc 46 | upstreamRetransmissionEnabled *prometheus.Desc 47 | downstreamVectoringState *prometheus.Desc 48 | upstreamVectoringState *prometheus.Desc 49 | downstreamAttenuation *prometheus.Desc 50 | upstreamAttenuation *prometheus.Desc 51 | downstreamSNRMargin *prometheus.Desc 52 | upstreamSNRMargin *prometheus.Desc 53 | downstreamPower *prometheus.Desc 54 | upstreamPower *prometheus.Desc 55 | downstreamRTXTXCount *prometheus.Desc 56 | upstreamRTXTXCount *prometheus.Desc 57 | downstreamRTXCCount *prometheus.Desc 58 | upstreamRTXCCount *prometheus.Desc 59 | downstreamRTXUCCount *prometheus.Desc 60 | upstreamRTXUCCount *prometheus.Desc 61 | downstreamFECCount *prometheus.Desc 62 | upstreamFECCount *prometheus.Desc 63 | downstreamCRCCount *prometheus.Desc 64 | upstreamCRCCount *prometheus.Desc 65 | downstreamESCount *prometheus.Desc 66 | upstreamESCount *prometheus.Desc 67 | downstreamSESCount *prometheus.Desc 68 | upstreamSESCount *prometheus.Desc 69 | 70 | // via rtop 71 | rtopInfo *prometheus.Desc 72 | rtopLoad1 *prometheus.Desc 73 | rtopLoad5 *prometheus.Desc 74 | rtopLoad15 *prometheus.Desc 75 | rtopLoadRunning *prometheus.Desc 76 | rtopLoadTotal *prometheus.Desc 77 | rtopCPUUser *prometheus.Desc 78 | rtopCPUSystem *prometheus.Desc 79 | rtopCPUNice *prometheus.Desc 80 | rtopCPUIdle *prometheus.Desc 81 | rtopCPUIOWait *prometheus.Desc 82 | rtopCPUIRQ *prometheus.Desc 83 | rtopCPUSoftIRQ *prometheus.Desc 84 | rtopCPUSteal *prometheus.Desc 85 | rtopCPUGuest *prometheus.Desc 86 | rtopMEMTotal *prometheus.Desc 87 | rtopMEMFree *prometheus.Desc 88 | rtopMEMUsed *prometheus.Desc 89 | rtopMEMBuffers *prometheus.Desc 90 | rtopMEMCached *prometheus.Desc 91 | rtopMEMSwapFree *prometheus.Desc 92 | rtopMEMSwapTotal *prometheus.Desc 93 | rtopFSTotal *prometheus.Desc 94 | rtopFSUsed *prometheus.Desc 95 | rtopFSFree *prometheus.Desc 96 | rtopNETRx *prometheus.Desc 97 | rtopNETTx *prometheus.Desc 98 | } 99 | 100 | func New(dsl dsl.Client, rtop *rtop.Client, logger log.Logger) *Exporter { 101 | return &Exporter{ 102 | dsl: dsl, 103 | rtop: rtop, 104 | logger: logger, 105 | state: prometheus.NewDesc( 106 | prometheus.BuildFQName(Namespace, SubsystemDsl, "state"), 107 | "State of the DSL modem.", 108 | []string{"state"}, 109 | nil, 110 | ), 111 | mode: prometheus.NewDesc( 112 | prometheus.BuildFQName(Namespace, SubsystemDsl, "mode"), 113 | "Mode of the DSL modem.", 114 | []string{"mode"}, 115 | nil, 116 | ), 117 | uptime: prometheus.NewDesc( 118 | prometheus.BuildFQName(Namespace, SubsystemDsl, "uptime"), 119 | "Uptime of the DSL modem.", 120 | []string{"uptime"}, 121 | nil, 122 | ), 123 | farEndInventory: prometheus.NewDesc( 124 | prometheus.BuildFQName(Namespace, SubsystemDsl, "modem_manufacturer_far"), 125 | "Far end inventory name of the manufacturer", 126 | []string{"vendor", "version"}, 127 | nil, 128 | ), 129 | nearEndInventory: prometheus.NewDesc( 130 | prometheus.BuildFQName(Namespace, SubsystemDsl, "modem_manufacturer_near"), 131 | "Near end inventory name of the manufacturer.", 132 | []string{"vendor", "version"}, 133 | nil, 134 | ), 135 | downstreamActualRate: prometheus.NewDesc( 136 | prometheus.BuildFQName(Namespace, SubsystemDsl, "actual_rate_downstream"), 137 | "Actual rate of downstream.", 138 | []string{"unit"}, 139 | nil, 140 | ), 141 | upstreamActualRate: prometheus.NewDesc( 142 | prometheus.BuildFQName(Namespace, SubsystemDsl, "actual_rate_upstream"), 143 | "Actual rate of upstream.", 144 | []string{"unit"}, 145 | nil, 146 | ), 147 | downstreamAttainableRate: prometheus.NewDesc( 148 | prometheus.BuildFQName(Namespace, SubsystemDsl, "attainable_rate_downstream"), 149 | "Attainable rate of downstream.", 150 | []string{"unit"}, 151 | nil, 152 | ), 153 | upstreamAttainableRate: prometheus.NewDesc( 154 | prometheus.BuildFQName(Namespace, SubsystemDsl, "attainable_rate_upstream"), 155 | "Attainable rate of upstream.", 156 | []string{"unit"}, 157 | nil, 158 | ), 159 | downstreamMinimumErrorFreeThroughput: prometheus.NewDesc( 160 | prometheus.BuildFQName(Namespace, SubsystemDsl, "minimum_error_free_throughput_downstream"), 161 | "Minimum error free throughput of downstream.", 162 | []string{"unit"}, 163 | nil, 164 | ), 165 | upstreamMinimumErrorFreeThroughput: prometheus.NewDesc( 166 | prometheus.BuildFQName(Namespace, SubsystemDsl, "minimum_error_free_throughput_upstream"), 167 | "Minimum error free throughput of upstream.", 168 | []string{"unit"}, 169 | nil, 170 | ), 171 | downstreamBitswapEnabled: prometheus.NewDesc( 172 | prometheus.BuildFQName(Namespace, SubsystemDsl, "bitswap_enabled_downstream"), 173 | "Bitswap enabled of downstream.", 174 | nil, 175 | nil, 176 | ), 177 | upstreamBitswapEnabled: prometheus.NewDesc( 178 | prometheus.BuildFQName(Namespace, SubsystemDsl, "bitswap_enabled_upstream"), 179 | "Bitswap enabled of upstream.", 180 | nil, 181 | nil, 182 | ), 183 | downstreamSeamlessRateAdaption: prometheus.NewDesc( 184 | prometheus.BuildFQName(Namespace, SubsystemDsl, "seamless_rate_adaption_downstream"), 185 | "Seamless rate adaption of downstream.", 186 | nil, 187 | nil, 188 | ), 189 | upstreamSeamlessRateAdaption: prometheus.NewDesc( 190 | prometheus.BuildFQName(Namespace, SubsystemDsl, "seamless_rate_adaption_upstream"), 191 | "Seamless rate adaption of upstream.", 192 | nil, 193 | nil, 194 | ), 195 | downstreamInterleavingDelay: prometheus.NewDesc( 196 | prometheus.BuildFQName(Namespace, SubsystemDsl, "interleaving_delay_downstream"), 197 | "Interleaving delay of downstream.", 198 | []string{"unit"}, 199 | nil, 200 | ), 201 | upstreamInterleavingDelay: prometheus.NewDesc( 202 | prometheus.BuildFQName(Namespace, SubsystemDsl, "interleaving_delay_upstream"), 203 | "Interleaving delay of upstream.", 204 | []string{"unit"}, 205 | nil, 206 | ), 207 | downstreamImpulseNoiseProtection: prometheus.NewDesc( 208 | prometheus.BuildFQName(Namespace, SubsystemDsl, "impulse_noise_protection_downstream"), 209 | "Impulse noise protection of downstream.", 210 | []string{"unit"}, 211 | nil, 212 | ), 213 | upstreamImpulseNoiseProtection: prometheus.NewDesc( 214 | prometheus.BuildFQName(Namespace, SubsystemDsl, "impulse_noise_protection_upstream"), 215 | "Impulse noise protection of upstream.", 216 | []string{"unit"}, 217 | nil, 218 | ), 219 | downstreamRetransmissionEnabled: prometheus.NewDesc( 220 | prometheus.BuildFQName(Namespace, SubsystemDsl, "retransmission_enabled_downstream"), 221 | "Retransmission enabled of downstream.", 222 | nil, 223 | nil, 224 | ), 225 | upstreamRetransmissionEnabled: prometheus.NewDesc( 226 | prometheus.BuildFQName(Namespace, SubsystemDsl, "retransmission_enabled_upstream"), 227 | "Retransmission enabled of upstream.", 228 | nil, 229 | nil, 230 | ), 231 | downstreamVectoringState: prometheus.NewDesc( 232 | prometheus.BuildFQName(Namespace, SubsystemDsl, "vectoring_state_downstream"), 233 | "Vectoring state of downstream.", 234 | []string{"state"}, 235 | nil, 236 | ), 237 | upstreamVectoringState: prometheus.NewDesc( 238 | prometheus.BuildFQName(Namespace, SubsystemDsl, "vectoring_state_upstream"), 239 | "Vectoring state of upstream.", 240 | []string{"state"}, 241 | nil, 242 | ), 243 | downstreamAttenuation: prometheus.NewDesc( 244 | prometheus.BuildFQName(Namespace, SubsystemDsl, "attenuation_downstream"), 245 | "Attenuation of downstream.", 246 | []string{"unit"}, 247 | nil, 248 | ), 249 | upstreamAttenuation: prometheus.NewDesc( 250 | prometheus.BuildFQName(Namespace, SubsystemDsl, "attenuation_upstream"), 251 | "Attenuation of upstream.", 252 | []string{"unit"}, 253 | nil, 254 | ), 255 | downstreamSNRMargin: prometheus.NewDesc( 256 | prometheus.BuildFQName(Namespace, SubsystemDsl, "snr_margin_downstream"), 257 | "SNR margin of downstream.", 258 | []string{"unit"}, 259 | nil, 260 | ), 261 | upstreamSNRMargin: prometheus.NewDesc( 262 | prometheus.BuildFQName(Namespace, SubsystemDsl, "snr_margin_upstream"), 263 | "SNR margin of upstream.", 264 | []string{"unit"}, 265 | nil, 266 | ), 267 | downstreamPower: prometheus.NewDesc( 268 | prometheus.BuildFQName(Namespace, SubsystemDsl, "power_downstream"), 269 | "Power of downstream.", 270 | []string{"unit"}, 271 | nil, 272 | ), 273 | upstreamPower: prometheus.NewDesc( 274 | prometheus.BuildFQName(Namespace, SubsystemDsl, "power_upstream"), 275 | "Power of upstream.", 276 | []string{"unit"}, 277 | nil, 278 | ), 279 | downstreamRTXTXCount: prometheus.NewDesc( 280 | prometheus.BuildFQName(Namespace, SubsystemDsl, "rtxtx_count_downstream"), 281 | "RTTX TX count of downstream.", 282 | nil, 283 | nil, 284 | ), 285 | upstreamRTXTXCount: prometheus.NewDesc( 286 | prometheus.BuildFQName(Namespace, SubsystemDsl, "rtxtx_count_upstream"), 287 | "RTTX TX count of upstream.", 288 | nil, 289 | nil, 290 | ), 291 | downstreamRTXCCount: prometheus.NewDesc( 292 | prometheus.BuildFQName(Namespace, SubsystemDsl, "rtxcc_count_downstream"), 293 | "RTXCC count of downstream.", 294 | nil, 295 | nil, 296 | ), 297 | upstreamRTXCCount: prometheus.NewDesc( 298 | prometheus.BuildFQName(Namespace, SubsystemDsl, "rtxcc_count_upstream"), 299 | "RTXCC count of upstream.", 300 | nil, 301 | nil, 302 | ), 303 | downstreamRTXUCCount: prometheus.NewDesc( 304 | prometheus.BuildFQName(Namespace, SubsystemDsl, "rtxucc_count_downstream"), 305 | "RTXUCC count of downstream.", 306 | nil, 307 | nil, 308 | ), 309 | upstreamRTXUCCount: prometheus.NewDesc( 310 | prometheus.BuildFQName(Namespace, SubsystemDsl, "rtxucc_count_upstream"), 311 | "RTXUCC count of upstream.", 312 | nil, 313 | nil, 314 | ), 315 | downstreamFECCount: prometheus.NewDesc( 316 | prometheus.BuildFQName(Namespace, SubsystemDsl, "fec_count_downstream"), 317 | "FEC count of downstream.", 318 | nil, 319 | nil, 320 | ), 321 | upstreamFECCount: prometheus.NewDesc( 322 | prometheus.BuildFQName(Namespace, SubsystemDsl, "fec_count_upstream"), 323 | "FEC count of upstream.", 324 | nil, 325 | nil, 326 | ), 327 | downstreamCRCCount: prometheus.NewDesc( 328 | prometheus.BuildFQName(Namespace, SubsystemDsl, "crc_count_downstream"), 329 | "CRC count of downstream.", 330 | nil, 331 | nil, 332 | ), 333 | upstreamCRCCount: prometheus.NewDesc( 334 | prometheus.BuildFQName(Namespace, SubsystemDsl, "crc_count_upstream"), 335 | "CRC count of upstream.", 336 | nil, 337 | nil, 338 | ), 339 | downstreamESCount: prometheus.NewDesc( 340 | prometheus.BuildFQName(Namespace, SubsystemDsl, "es_count_downstream"), 341 | "ES count of downstream.", 342 | nil, 343 | nil, 344 | ), 345 | upstreamESCount: prometheus.NewDesc( 346 | prometheus.BuildFQName(Namespace, SubsystemDsl, "es_count_upstream"), 347 | "ES count of upstream.", 348 | nil, 349 | nil, 350 | ), 351 | downstreamSESCount: prometheus.NewDesc( 352 | prometheus.BuildFQName(Namespace, SubsystemDsl, "ses_count_downstream"), 353 | "SES count of downstream.", 354 | nil, 355 | nil, 356 | ), 357 | upstreamSESCount: prometheus.NewDesc( 358 | prometheus.BuildFQName(Namespace, SubsystemDsl, "ses_count_upstream"), 359 | "SES count of upstream.", 360 | nil, 361 | nil, 362 | ), 363 | // rtop 364 | rtopInfo: prometheus.NewDesc( 365 | prometheus.BuildFQName(Namespace, SubsystemRtop, "info"), 366 | "Information about the host.", 367 | []string{"hostname", "uptime"}, 368 | nil, 369 | ), 370 | rtopLoad1: prometheus.NewDesc( 371 | prometheus.BuildFQName(Namespace, SubsystemRtop, "load1"), 372 | "Load1 of the host.", 373 | nil, 374 | nil, 375 | ), 376 | rtopLoad5: prometheus.NewDesc( 377 | prometheus.BuildFQName(Namespace, SubsystemRtop, "load5"), 378 | "Load5 of the host.", 379 | nil, 380 | nil, 381 | ), 382 | rtopLoad15: prometheus.NewDesc( 383 | prometheus.BuildFQName(Namespace, SubsystemRtop, "load15"), 384 | "Load15 of the host.", 385 | nil, 386 | nil, 387 | ), 388 | rtopLoadTotal: prometheus.NewDesc( 389 | prometheus.BuildFQName(Namespace, SubsystemRtop, "load_total"), 390 | "LoadTotal of the host.", 391 | nil, 392 | nil, 393 | ), 394 | rtopLoadRunning: prometheus.NewDesc( 395 | prometheus.BuildFQName(Namespace, SubsystemRtop, "load_running"), 396 | "LoadRunning of the host.", 397 | nil, 398 | nil, 399 | ), 400 | rtopCPUUser: prometheus.NewDesc( 401 | prometheus.BuildFQName(Namespace, SubsystemRtop, "cpu_user"), 402 | "CPU user of the host.", 403 | nil, 404 | nil, 405 | ), 406 | rtopCPUSystem: prometheus.NewDesc( 407 | prometheus.BuildFQName(Namespace, SubsystemRtop, "cpu_system"), 408 | "CPU system of the host.", 409 | nil, 410 | nil, 411 | ), 412 | rtopCPUNice: prometheus.NewDesc( 413 | prometheus.BuildFQName(Namespace, SubsystemRtop, "cpu_nice"), 414 | "CPU nice of the host.", 415 | nil, 416 | nil, 417 | ), 418 | rtopCPUIdle: prometheus.NewDesc( 419 | prometheus.BuildFQName(Namespace, SubsystemRtop, "cpu_idle"), 420 | "CPU idle of the host.", 421 | nil, 422 | nil, 423 | ), 424 | rtopCPUIOWait: prometheus.NewDesc( 425 | prometheus.BuildFQName(Namespace, SubsystemRtop, "cpu_iowait"), 426 | "CPU iowait of the host.", 427 | nil, 428 | nil, 429 | ), 430 | rtopCPUIRQ: prometheus.NewDesc( 431 | prometheus.BuildFQName(Namespace, SubsystemRtop, "cpu_irq"), 432 | "CPU irq of the host.", 433 | nil, 434 | nil, 435 | ), 436 | rtopCPUSoftIRQ: prometheus.NewDesc( 437 | prometheus.BuildFQName(Namespace, SubsystemRtop, "cpu_softirq"), 438 | "CPU softirq of the host.", 439 | nil, 440 | nil, 441 | ), 442 | rtopCPUSteal: prometheus.NewDesc( 443 | prometheus.BuildFQName(Namespace, SubsystemRtop, "cpu_steal"), 444 | "CPU steal of the host.", 445 | nil, 446 | nil, 447 | ), 448 | rtopCPUGuest: prometheus.NewDesc( 449 | prometheus.BuildFQName(Namespace, SubsystemRtop, "cpu_guest"), 450 | "CPU guest of the host.", 451 | nil, 452 | nil, 453 | ), 454 | rtopMEMTotal: prometheus.NewDesc( 455 | prometheus.BuildFQName(Namespace, SubsystemRtop, "mem_total"), 456 | "Total memory of the host.", 457 | nil, 458 | nil, 459 | ), 460 | rtopMEMFree: prometheus.NewDesc( 461 | prometheus.BuildFQName(Namespace, SubsystemRtop, "mem_free"), 462 | "Free memory of the host.", 463 | nil, 464 | nil, 465 | ), 466 | rtopMEMUsed: prometheus.NewDesc( 467 | prometheus.BuildFQName(Namespace, SubsystemRtop, "mem_used"), 468 | "Used memory of the host.", 469 | nil, 470 | nil, 471 | ), 472 | rtopMEMBuffers: prometheus.NewDesc( 473 | prometheus.BuildFQName(Namespace, SubsystemRtop, "mem_buffers"), 474 | "Buffers memory of the host.", 475 | nil, 476 | nil, 477 | ), 478 | rtopMEMCached: prometheus.NewDesc( 479 | prometheus.BuildFQName(Namespace, SubsystemRtop, "mem_cached"), 480 | "Cached memory of the host.", 481 | nil, 482 | 483 | nil, 484 | ), 485 | rtopMEMSwapFree: prometheus.NewDesc( 486 | prometheus.BuildFQName(Namespace, SubsystemRtop, "mem_swap_free"), 487 | "Free swap memory of the host.", 488 | nil, 489 | nil, 490 | ), 491 | rtopMEMSwapTotal: prometheus.NewDesc( 492 | prometheus.BuildFQName(Namespace, SubsystemRtop, "mem_swap_total"), 493 | "Total swap memory of the host.", 494 | nil, 495 | nil, 496 | ), 497 | rtopFSTotal: prometheus.NewDesc( 498 | prometheus.BuildFQName(Namespace, SubsystemRtop, "fs_total"), 499 | "Total filesystems of the host.", 500 | []string{"mount"}, 501 | nil, 502 | ), 503 | rtopFSUsed: prometheus.NewDesc( 504 | prometheus.BuildFQName(Namespace, SubsystemRtop, "fs_used"), 505 | "Used filesystem of the host.", 506 | []string{"mount"}, 507 | nil, 508 | ), 509 | rtopFSFree: prometheus.NewDesc( 510 | prometheus.BuildFQName(Namespace, SubsystemRtop, "fs_free"), 511 | "Free filesystem of the host.", 512 | []string{"mount"}, 513 | nil, 514 | ), 515 | rtopNETRx: prometheus.NewDesc( 516 | prometheus.BuildFQName(Namespace, SubsystemRtop, "net_rx"), 517 | "Total received bytes of the network.", 518 | []string{"interface", "ipv4", "ipv6"}, 519 | nil, 520 | ), 521 | rtopNETTx: prometheus.NewDesc( 522 | prometheus.BuildFQName(Namespace, SubsystemRtop, "net_tx"), 523 | "Total transmitted bytes of the network.", 524 | []string{"interface", "ipv4", "ipv6"}, 525 | nil, 526 | ), 527 | } 528 | } 529 | 530 | func (e *Exporter) Describe(descs chan<- *prometheus.Desc) { 531 | // dsl 532 | descs <- e.state 533 | descs <- e.mode 534 | descs <- e.uptime 535 | descs <- e.farEndInventory 536 | descs <- e.nearEndInventory 537 | descs <- e.downstreamActualRate 538 | descs <- e.upstreamActualRate 539 | descs <- e.downstreamAttainableRate 540 | descs <- e.upstreamActualRate 541 | descs <- e.downstreamMinimumErrorFreeThroughput 542 | descs <- e.upstreamMinimumErrorFreeThroughput 543 | descs <- e.downstreamBitswapEnabled 544 | descs <- e.upstreamBitswapEnabled 545 | descs <- e.downstreamSeamlessRateAdaption 546 | descs <- e.upstreamSeamlessRateAdaption 547 | descs <- e.downstreamInterleavingDelay 548 | descs <- e.upstreamInterleavingDelay 549 | descs <- e.downstreamImpulseNoiseProtection 550 | descs <- e.upstreamImpulseNoiseProtection 551 | descs <- e.downstreamRetransmissionEnabled 552 | descs <- e.upstreamRetransmissionEnabled 553 | descs <- e.downstreamVectoringState 554 | descs <- e.upstreamVectoringState 555 | descs <- e.downstreamAttenuation 556 | descs <- e.upstreamAttenuation 557 | descs <- e.downstreamSNRMargin 558 | descs <- e.upstreamSNRMargin 559 | descs <- e.downstreamPower 560 | descs <- e.upstreamPower 561 | descs <- e.downstreamRTXTXCount 562 | descs <- e.upstreamRTXTXCount 563 | descs <- e.downstreamRTXCCount 564 | descs <- e.upstreamRTXCCount 565 | descs <- e.downstreamRTXUCCount 566 | descs <- e.upstreamRTXUCCount 567 | descs <- e.downstreamFECCount 568 | descs <- e.upstreamFECCount 569 | descs <- e.downstreamCRCCount 570 | descs <- e.upstreamCRCCount 571 | descs <- e.downstreamESCount 572 | descs <- e.upstreamESCount 573 | descs <- e.downstreamSESCount 574 | descs <- e.upstreamSESCount 575 | 576 | // rtop 577 | descs <- e.rtopInfo 578 | descs <- e.rtopLoad1 579 | descs <- e.rtopLoad5 580 | descs <- e.rtopLoad15 581 | descs <- e.rtopLoadRunning 582 | descs <- e.rtopLoadTotal 583 | descs <- e.rtopCPUUser 584 | descs <- e.rtopCPUSystem 585 | descs <- e.rtopCPUNice 586 | descs <- e.rtopCPUIdle 587 | descs <- e.rtopCPUIOWait 588 | descs <- e.rtopCPUIRQ 589 | descs <- e.rtopCPUSoftIRQ 590 | descs <- e.rtopCPUSteal 591 | descs <- e.rtopCPUGuest 592 | descs <- e.rtopMEMTotal 593 | descs <- e.rtopMEMFree 594 | descs <- e.rtopMEMUsed 595 | descs <- e.rtopMEMBuffers 596 | descs <- e.rtopMEMCached 597 | descs <- e.rtopMEMSwapFree 598 | descs <- e.rtopMEMSwapTotal 599 | descs <- e.rtopFSTotal 600 | descs <- e.rtopFSUsed 601 | descs <- e.rtopFSFree 602 | descs <- e.rtopNETRx 603 | descs <- e.rtopNETTx 604 | } 605 | 606 | func (e *Exporter) Collect(metrics chan<- prometheus.Metric) { 607 | level.Debug(e.logger).Log("msg", "collecting metrics...") 608 | 609 | if err := e.getDataFromClients(metrics); err != nil { 610 | level.Error(e.logger).Log("msg", "could not get data", "err", err.Error()) //nolint:errcheck 611 | } 612 | } 613 | 614 | func (e *Exporter) getDataFromClients(metrics chan<- prometheus.Metric) error { 615 | if err := e.getDataFromDsl(metrics); err != nil { 616 | return err 617 | } 618 | if err := e.getDataFromRtop(metrics); err != nil { 619 | return err 620 | } 621 | return nil 622 | } 623 | 624 | func (e *Exporter) getDataFromDsl(metrics chan<- prometheus.Metric) error { 625 | if err := e.dsl.UpdateData(); err != nil { 626 | return err 627 | } 628 | 629 | status := e.dsl.Status() 630 | 631 | metrics <- prometheus.MustNewConstMetric(e.state, prometheus.UntypedValue, 1, status.State.String()) 632 | metrics <- prometheus.MustNewConstMetric(e.mode, prometheus.UntypedValue, 1, status.Mode.String()) 633 | metrics <- prometheus.MustNewConstMetric(e.uptime, prometheus.UntypedValue, 1, status.Uptime.String()) 634 | metrics <- prometheus.MustNewConstMetric(e.farEndInventory, prometheus.UntypedValue, 1, status.FarEndInventory.Vendor, status.FarEndInventory.Version) 635 | metrics <- prometheus.MustNewConstMetric(e.nearEndInventory, prometheus.UntypedValue, 1, status.NearEndInventory.Vendor, status.NearEndInventory.Version) 636 | metrics <- prometheus.MustNewConstMetric(e.downstreamActualRate, prometheus.GaugeValue, float64(status.DownstreamActualRate.Int), status.DownstreamActualRate.Unit()) 637 | metrics <- prometheus.MustNewConstMetric(e.upstreamActualRate, prometheus.GaugeValue, float64(status.UpstreamActualRate.Int), status.UpstreamActualRate.Unit()) 638 | metrics <- prometheus.MustNewConstMetric(e.downstreamAttainableRate, prometheus.GaugeValue, float64(status.DownstreamAttainableRate.Int), status.DownstreamAttainableRate.Unit()) 639 | metrics <- prometheus.MustNewConstMetric(e.upstreamAttainableRate, prometheus.GaugeValue, float64(status.UpstreamAttainableRate.Int), status.UpstreamAttainableRate.Unit()) 640 | metrics <- prometheus.MustNewConstMetric(e.downstreamMinimumErrorFreeThroughput, prometheus.GaugeValue, float64(status.DownstreamMinimumErrorFreeThroughput.Int), status.DownstreamMinimumErrorFreeThroughput.Unit()) 641 | metrics <- prometheus.MustNewConstMetric(e.upstreamMinimumErrorFreeThroughput, prometheus.GaugeValue, float64(status.UpstreamMinimumErrorFreeThroughput.Int), status.UpstreamMinimumErrorFreeThroughput.Unit()) 642 | metrics <- prometheus.MustNewConstMetric(e.downstreamBitswapEnabled, prometheus.GaugeValue, boolToFloat64(status.DownstreamBitswapEnabled.Bool)) 643 | metrics <- prometheus.MustNewConstMetric(e.upstreamBitswapEnabled, prometheus.GaugeValue, boolToFloat64(status.UpstreamBitswapEnabled.Bool)) 644 | metrics <- prometheus.MustNewConstMetric(e.downstreamSeamlessRateAdaption, prometheus.GaugeValue, boolToFloat64(status.DownstreamSeamlessRateAdaption.Bool)) 645 | metrics <- prometheus.MustNewConstMetric(e.upstreamSeamlessRateAdaption, prometheus.GaugeValue, boolToFloat64(status.UpstreamSeamlessRateAdaption.Bool)) 646 | metrics <- prometheus.MustNewConstMetric(e.downstreamInterleavingDelay, prometheus.GaugeValue, status.DownstreamInterleavingDelay.Float, status.DownstreamInterleavingDelay.Unit()) 647 | metrics <- prometheus.MustNewConstMetric(e.upstreamInterleavingDelay, prometheus.GaugeValue, status.UpstreamInterleavingDelay.Float, status.UpstreamInterleavingDelay.Unit()) 648 | metrics <- prometheus.MustNewConstMetric(e.downstreamImpulseNoiseProtection, prometheus.GaugeValue, status.DownstreamImpulseNoiseProtection.Float, status.DownstreamImpulseNoiseProtection.Unit()) 649 | metrics <- prometheus.MustNewConstMetric(e.upstreamImpulseNoiseProtection, prometheus.GaugeValue, status.UpstreamImpulseNoiseProtection.Float, status.UpstreamImpulseNoiseProtection.Unit()) 650 | metrics <- prometheus.MustNewConstMetric(e.downstreamRetransmissionEnabled, prometheus.GaugeValue, boolToFloat64(status.DownstreamRetransmissionEnabled.Bool)) 651 | metrics <- prometheus.MustNewConstMetric(e.upstreamRetransmissionEnabled, prometheus.GaugeValue, boolToFloat64(status.UpstreamRetransmissionEnabled.Bool)) 652 | metrics <- prometheus.MustNewConstMetric(e.downstreamVectoringState, prometheus.GaugeValue, 1, status.DownstreamVectoringState.Value()) 653 | metrics <- prometheus.MustNewConstMetric(e.upstreamVectoringState, prometheus.GaugeValue, 1, status.UpstreamVectoringState.Value()) 654 | metrics <- prometheus.MustNewConstMetric(e.downstreamAttenuation, prometheus.GaugeValue, status.DownstreamAttenuation.Float, status.DownstreamAttenuation.Unit()) 655 | metrics <- prometheus.MustNewConstMetric(e.upstreamAttenuation, prometheus.GaugeValue, status.UpstreamAttenuation.Float, status.UpstreamAttenuation.Unit()) 656 | metrics <- prometheus.MustNewConstMetric(e.downstreamSNRMargin, prometheus.GaugeValue, status.DownstreamSNRMargin.Float, status.DownstreamSNRMargin.Unit()) 657 | metrics <- prometheus.MustNewConstMetric(e.upstreamSNRMargin, prometheus.GaugeValue, status.UpstreamSNRMargin.Float, status.UpstreamSNRMargin.Unit()) 658 | metrics <- prometheus.MustNewConstMetric(e.downstreamPower, prometheus.GaugeValue, status.DownstreamPower.Float, status.DownstreamPower.Unit()) 659 | metrics <- prometheus.MustNewConstMetric(e.upstreamPower, prometheus.GaugeValue, status.UpstreamPower.Float, status.UpstreamPower.Unit()) 660 | metrics <- prometheus.MustNewConstMetric(e.downstreamRTXTXCount, prometheus.GaugeValue, float64(status.DownstreamRTXTXCount.Int)) 661 | metrics <- prometheus.MustNewConstMetric(e.upstreamRTXTXCount, prometheus.GaugeValue, float64(status.UpstreamRTXTXCount.Int)) 662 | metrics <- prometheus.MustNewConstMetric(e.downstreamRTXCCount, prometheus.GaugeValue, float64(status.DownstreamRTXCCount.Int)) 663 | metrics <- prometheus.MustNewConstMetric(e.upstreamRTXCCount, prometheus.GaugeValue, float64(status.UpstreamRTXCCount.Int)) 664 | metrics <- prometheus.MustNewConstMetric(e.downstreamRTXUCCount, prometheus.GaugeValue, float64(status.DownstreamRTXUCCount.Int)) 665 | metrics <- prometheus.MustNewConstMetric(e.upstreamRTXUCCount, prometheus.GaugeValue, float64(status.UpstreamRTXUCCount.Int)) 666 | metrics <- prometheus.MustNewConstMetric(e.downstreamFECCount, prometheus.GaugeValue, float64(status.DownstreamFECCount.Int)) 667 | metrics <- prometheus.MustNewConstMetric(e.upstreamFECCount, prometheus.GaugeValue, float64(status.UpstreamFECCount.Int)) 668 | metrics <- prometheus.MustNewConstMetric(e.downstreamCRCCount, prometheus.GaugeValue, float64(status.DownstreamCRCCount.Int)) 669 | metrics <- prometheus.MustNewConstMetric(e.upstreamCRCCount, prometheus.GaugeValue, float64(status.UpstreamCRCCount.Int)) 670 | metrics <- prometheus.MustNewConstMetric(e.downstreamESCount, prometheus.GaugeValue, float64(status.DownstreamESCount.Int)) 671 | metrics <- prometheus.MustNewConstMetric(e.upstreamESCount, prometheus.GaugeValue, float64(status.UpstreamESCount.Int)) 672 | metrics <- prometheus.MustNewConstMetric(e.downstreamSESCount, prometheus.GaugeValue, float64(status.DownstreamSESCount.Int)) 673 | metrics <- prometheus.MustNewConstMetric(e.upstreamSESCount, prometheus.GaugeValue, float64(status.UpstreamSESCount.Int)) 674 | 675 | return nil 676 | } 677 | 678 | func (e *Exporter) getDataFromRtop(metrics chan<- prometheus.Metric) error { 679 | stats, err := e.rtop.GetStats() 680 | if err != nil { 681 | return err 682 | } 683 | 684 | metrics <- prometheus.MustNewConstMetric(e.rtopInfo, prometheus.GaugeValue, 1, stats.Hostname, stats.Uptime.String()) 685 | 686 | metrics <- prometheus.MustNewConstMetric(e.rtopLoad1, prometheus.GaugeValue, stringToFloat64(stats.Loads.Load1)) 687 | metrics <- prometheus.MustNewConstMetric(e.rtopLoad5, prometheus.GaugeValue, stringToFloat64(stats.Loads.Load5)) 688 | metrics <- prometheus.MustNewConstMetric(e.rtopLoad15, prometheus.GaugeValue, stringToFloat64(stats.Loads.Load15)) 689 | metrics <- prometheus.MustNewConstMetric(e.rtopLoadRunning, prometheus.GaugeValue, stringToFloat64(stats.Loads.RunningProcs)) 690 | metrics <- prometheus.MustNewConstMetric(e.rtopLoadTotal, prometheus.GaugeValue, stringToFloat64(stats.Loads.TotalProcs)) 691 | 692 | metrics <- prometheus.MustNewConstMetric(e.rtopCPUUser, prometheus.GaugeValue, float64(stats.CPU.User)) 693 | metrics <- prometheus.MustNewConstMetric(e.rtopCPUSystem, prometheus.GaugeValue, float64(stats.CPU.System)) 694 | metrics <- prometheus.MustNewConstMetric(e.rtopCPUNice, prometheus.GaugeValue, float64(stats.CPU.Nice)) 695 | metrics <- prometheus.MustNewConstMetric(e.rtopCPUIdle, prometheus.GaugeValue, float64(stats.CPU.Idle)) 696 | metrics <- prometheus.MustNewConstMetric(e.rtopCPUIOWait, prometheus.GaugeValue, float64(stats.CPU.IOWait)) 697 | metrics <- prometheus.MustNewConstMetric(e.rtopCPUIRQ, prometheus.GaugeValue, float64(stats.CPU.IRQ)) 698 | metrics <- prometheus.MustNewConstMetric(e.rtopCPUSoftIRQ, prometheus.GaugeValue, float64(stats.CPU.SoftIRQ)) 699 | metrics <- prometheus.MustNewConstMetric(e.rtopCPUSteal, prometheus.GaugeValue, float64(stats.CPU.Steal)) 700 | metrics <- prometheus.MustNewConstMetric(e.rtopCPUGuest, prometheus.GaugeValue, float64(stats.CPU.Guest)) 701 | 702 | metrics <- prometheus.MustNewConstMetric(e.rtopMEMTotal, prometheus.GaugeValue, float64(stats.MEM.Total)) 703 | metrics <- prometheus.MustNewConstMetric(e.rtopMEMFree, prometheus.GaugeValue, float64(stats.MEM.Free)) 704 | metrics <- prometheus.MustNewConstMetric(e.rtopMEMUsed, prometheus.GaugeValue, float64(stats.MEM.Used())) 705 | metrics <- prometheus.MustNewConstMetric(e.rtopMEMCached, prometheus.GaugeValue, float64(stats.MEM.Cached)) 706 | metrics <- prometheus.MustNewConstMetric(e.rtopMEMBuffers, prometheus.GaugeValue, float64(stats.MEM.Buffers)) 707 | metrics <- prometheus.MustNewConstMetric(e.rtopMEMSwapFree, prometheus.GaugeValue, float64(stats.MEM.SwapFree)) 708 | metrics <- prometheus.MustNewConstMetric(e.rtopMEMSwapTotal, prometheus.GaugeValue, float64(stats.MEM.SwapTotal)) 709 | 710 | e.calculateNET(stats, e.rtopNETRx, e.rtopNETTx, metrics) 711 | e.calculateFS(stats, e.rtopFSTotal, e.rtopFSUsed, e.rtopFSFree, metrics) 712 | 713 | return nil 714 | } 715 | 716 | func (e *Exporter) calculateNET(stats types.Stats, descRx *prometheus.Desc, descTx *prometheus.Desc, metrics chan<- prometheus.Metric) { 717 | for k, v := range stats.NetInterface { 718 | metrics <- prometheus.MustNewConstMetric(descRx, prometheus.GaugeValue, float64(v.Rx), k, v.IPv4, v.IPv6) 719 | metrics <- prometheus.MustNewConstMetric(descTx, prometheus.GaugeValue, float64(v.Tx), k, v.IPv4, v.IPv6) 720 | } 721 | } 722 | 723 | func (e *Exporter) calculateFS(stats types.Stats, descTotal *prometheus.Desc, descUsed *prometheus.Desc, descFree *prometheus.Desc, metrics chan<- prometheus.Metric) { 724 | for _, fs := range stats.FSInfos { 725 | metrics <- prometheus.MustNewConstMetric(descTotal, prometheus.GaugeValue, float64(fs.Total), fs.MountPoint) 726 | metrics <- prometheus.MustNewConstMetric(descUsed, prometheus.GaugeValue, float64(fs.Used), fs.MountPoint) 727 | metrics <- prometheus.MustNewConstMetric(descFree, prometheus.GaugeValue, float64(fs.Free), fs.MountPoint) 728 | } 729 | } 730 | 731 | func (e *Exporter) CloseClient() { 732 | e.dsl.Close() 733 | } 734 | 735 | func boolToFloat64(b bool) float64 { 736 | if b { 737 | return 1 738 | } 739 | return 0 740 | } 741 | 742 | func stringToFloat64(s string) float64 { 743 | f, err := strconv.ParseFloat(s, 64) 744 | if err != nil { 745 | return 0 746 | } 747 | return f 748 | } 749 | -------------------------------------------------------------------------------- /internal/rtop/rtop.go: -------------------------------------------------------------------------------- 1 | package rtop 2 | 3 | import ( 4 | "fmt" 5 | "github.com/Dentrax/xdsl-exporter/internal/config" 6 | "github.com/rapidloop/rtop/pkg/client" 7 | ) 8 | 9 | func New(cfg config.Config) (*client.Client, error) { 10 | opts := []client.Option{ 11 | client.WithUser(cfg.TargetUser), 12 | client.WithHost(cfg.TargetHost), 13 | client.WithPort(cfg.TargetPort), 14 | client.WithKeyPath(cfg.TargetSSHKeyPath), 15 | client.WithWorkers(2), 16 | } 17 | 18 | client, err := client.New(opts...) 19 | if err != nil { 20 | return nil, fmt.Errorf("new rtop client: %w", err) 21 | } 22 | 23 | return client, nil 24 | } 25 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2022 NAME HERE 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package main 17 | 18 | import ( 19 | _ "3e8.eu/go/dsl/broadcom" 20 | _ "3e8.eu/go/dsl/draytek" 21 | _ "3e8.eu/go/dsl/fritzbox" 22 | _ "3e8.eu/go/dsl/lantiq" 23 | _ "3e8.eu/go/dsl/mediatek" 24 | _ "3e8.eu/go/dsl/sagemcom" 25 | _ "3e8.eu/go/dsl/speedport" 26 | 27 | "github.com/Dentrax/xdsl-exporter/cmd" 28 | ) 29 | 30 | func main() { 31 | cmd.Execute() 32 | } 33 | --------------------------------------------------------------------------------