├── .editorconfig ├── .envrc ├── .gitignore ├── LICENSE ├── NOTICE ├── README.md ├── cli ├── Cargo.lock ├── Cargo.toml ├── package.nix └── src │ ├── cli.rs │ ├── cli │ ├── args.rs │ ├── opts.rs │ └── subs.rs │ ├── main.rs │ ├── types.rs │ ├── types │ └── error.rs │ ├── utils.rs │ └── utils │ └── nomad.rs ├── flake.lock ├── flake.nix ├── shell └── devshellModule.nix └── treefmt.toml /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | end_of_line = lf 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | charset = utf-8 9 | indent_style = space 10 | indent_size = 2 11 | 12 | # Ignore diffs/patches 13 | [*.{diff,patch}] 14 | end_of_line = unset 15 | insert_final_newline = unset 16 | trim_trailing_whitespace = unset 17 | indent_size = unset 18 | 19 | [*.md] 20 | max_line_length = off 21 | trim_trailing_whitespace = false 22 | 23 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | { 2 | # shell gc root dir 3 | mkdir -p $(direnv_layout_dir) 4 | 5 | # reload when these files change 6 | watch_file flake.nix 7 | watch_file flake.lock 8 | 9 | # load the flake devShell 10 | eval "$(nix print-dev-env --no-update-lock-file --no-write-lock-file --profile $(direnv_layout_dir)/flake-profile)" 11 | } || use nix 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | result 2 | **/target 3 | /.direnv 4 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Input Output (Hong Kong) Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bitte CLI 2 | 3 | This is a little tool that helps with deployments of Bitte clusters. 4 | 5 | Bitte is a set of NixOS configurations that are provisioned using Terraform and 6 | runs a cluster of Consul, Vault, and Nomad instances. 7 | 8 | ## Build this using nix 9 | 10 | nix build -o bitte 11 | 12 | ## Run this 13 | 14 | ./bitte --help 15 | 16 | ### Install cli tools outside of nix 17 | 18 | To install the bitte tools, you will also need the following dependencies: 19 | 20 | - [cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html) 21 | - pkg-config 22 | - openssl (linux only, darwin will use Security framework) 23 | - zlib 24 | 25 | To install: 26 | 27 | ```bash 28 | cargo install --path cli # for the bitte cli 29 | cargo install --path iogo # for the iogo utility 30 | ``` 31 | 32 | ## Setup the Bitte Environment 33 | 34 | export BITTE_FLAKE=git+ssh://git@github.com/input-output-hk/bitte 35 | export BITTE_CLUSTER=cvn-testnet 36 | export AWS_DEFAULT_REGION=eu-central-1 37 | export AWS_PROFILE=cvn-testnet 38 | 39 | # Development 40 | 41 | This program is written in [Rust](https://doc.rust-lang.org/stable/book) using 42 | the [Tokio](https://tokio.rs/tokio/tutorial) runtime for asynchronous execution. 43 | 44 | This is not a full guide by any means, but should serve as a good starting 45 | point, and baseline check for understanding much of the code. A few of the 46 | most critical concepts to understand are briefly outlined below. 47 | 48 | ## Rust 49 | 50 | Rust's compiler is a bit different than any other mainstream language since it 51 | validates and manages memory at compile time, rather than at runtime like a 52 | garbase collected language, or not at all like C/C++. 53 | 54 | Therefore, a basic understanding of Rust's 55 | [ownership](https://doc.rust-lang.org/stable/book/ch04-00-understanding-ownership.html) 56 | model will prove instrumental to working productively with the language. 57 | 58 | The Rust community does an excellent job of keeping their materials up to date 59 | and easy to follow, so be sure to use the resources linked in this section if 60 | you need help. 61 | 62 | ## Futures 63 | 64 | Another important detail to understand is that, unlike some other languages, 65 | [futures](https://rust-lang.github.io/async-book/01_getting_started/01_chapter.html) 66 | in Rust are lazy by default. That means that a future will not begin execution 67 | until `await` is called on it, e.g: 68 | 69 | ```rust 70 | // execution of `foo` does not occur here 71 | let foo = async { 3 * 40 }; 72 | 73 | // `bar` is not a future and so is evaluated immediately to 72 74 | let bar = 8 * 9; 75 | 76 | // `foo` is finally evaluated to 120 here. 77 | // The program returns to it's previous context (the function that called it) 78 | // until evaluation completes. 79 | println!("{}", bar * foo.await); 80 | ``` 81 | 82 | A brief explanation of how to eval futures eagerly is given below. 83 | 84 | ## Tokio 85 | 86 | Rust's standard library doesn't provide an asynchronous runtime on it's own, so 87 | one must opt in to an external one to make use of its async/await tokens. Tokio 88 | has become the _de facto_ async runtime of choice for many projects, since it 89 | provides both an execution environment for futures, as well as a multi-threaded, 90 | well optimized runtime. 91 | 92 | ### Eager Futures 93 | 94 | As mentioned above, futures are lazy by default and do nothing until awaited. 95 | With tokio, one can work around this when needed by [spawning](https://tokio.rs/tokio/tutorial/spawning) 96 | a new Tokio thread to run the future in while continuing work on the current 97 | thread. 98 | 99 | Becuase spawning threads can increase control flow complexity, you should probably 100 | avoid doing it by default, and wait until you make an optimization pass, finding 101 | only the futures that could really benefit from it. 102 | -------------------------------------------------------------------------------- /cli/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.17.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "aho-corasick" 22 | version = "0.7.18" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 25 | dependencies = [ 26 | "memchr", 27 | ] 28 | 29 | [[package]] 30 | name = "anyhow" 31 | version = "1.0.51" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" 34 | 35 | [[package]] 36 | name = "arrayref" 37 | version = "0.3.6" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" 40 | 41 | [[package]] 42 | name = "arrayvec" 43 | version = "0.5.2" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" 46 | 47 | [[package]] 48 | name = "async-compression" 49 | version = "0.3.8" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "5443ccbb270374a2b1055fc72da40e1f237809cd6bb0e97e66d264cd138473a6" 52 | dependencies = [ 53 | "flate2", 54 | "futures-core", 55 | "memchr", 56 | "pin-project-lite", 57 | "tokio", 58 | ] 59 | 60 | [[package]] 61 | name = "atty" 62 | version = "0.2.14" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 65 | dependencies = [ 66 | "hermit-abi", 67 | "libc", 68 | "winapi", 69 | ] 70 | 71 | [[package]] 72 | name = "autocfg" 73 | version = "1.0.1" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 76 | 77 | [[package]] 78 | name = "aws-config" 79 | version = "0.2.0" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "b14ae9e658d7c4920a1ea2873ba86afbcd285c5bf627fde9b2af295488f702bc" 82 | dependencies = [ 83 | "aws-http", 84 | "aws-hyper", 85 | "aws-sdk-sts", 86 | "aws-smithy-async", 87 | "aws-smithy-client", 88 | "aws-smithy-http", 89 | "aws-smithy-http-tower", 90 | "aws-smithy-json", 91 | "aws-smithy-types", 92 | "aws-types", 93 | "bytes", 94 | "http", 95 | "tokio", 96 | "tower", 97 | "tracing", 98 | ] 99 | 100 | [[package]] 101 | name = "aws-endpoint" 102 | version = "0.2.0" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "0d3862993d16ce409bbc9beb16744e1e906130c8071ca75e84d967f7ea590eeb" 105 | dependencies = [ 106 | "aws-smithy-http", 107 | "aws-types", 108 | "http", 109 | "regex", 110 | "tracing", 111 | ] 112 | 113 | [[package]] 114 | name = "aws-http" 115 | version = "0.2.0" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "21902b7009bb5290acab8a297d8c3287b990bdf1c57bb72f331dfaa171854416" 118 | dependencies = [ 119 | "aws-smithy-http", 120 | "aws-smithy-types", 121 | "aws-types", 122 | "http", 123 | "lazy_static", 124 | "tracing", 125 | ] 126 | 127 | [[package]] 128 | name = "aws-hyper" 129 | version = "0.2.0" 130 | source = "registry+https://github.com/rust-lang/crates.io-index" 131 | checksum = "5be61f82810771f547ed72fe9db7e087f555ce1612908ea23b58977272eb2da1" 132 | dependencies = [ 133 | "aws-endpoint", 134 | "aws-http", 135 | "aws-sig-auth", 136 | "aws-smithy-client", 137 | "aws-smithy-http", 138 | "aws-smithy-http-tower", 139 | "aws-smithy-types", 140 | "bytes", 141 | "fastrand", 142 | "http", 143 | "http-body", 144 | "hyper", 145 | "hyper-rustls", 146 | "pin-project", 147 | "tokio", 148 | "tower", 149 | "tracing", 150 | ] 151 | 152 | [[package]] 153 | name = "aws-sdk-ec2" 154 | version = "0.2.0" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "a5995bfd6c7db415402224daa202d486baff9a8fb0907806f3d84a345aade8ed" 157 | dependencies = [ 158 | "aws-endpoint", 159 | "aws-http", 160 | "aws-hyper", 161 | "aws-sig-auth", 162 | "aws-smithy-async", 163 | "aws-smithy-client", 164 | "aws-smithy-http", 165 | "aws-smithy-query", 166 | "aws-smithy-types", 167 | "aws-smithy-xml", 168 | "aws-types", 169 | "bytes", 170 | "fastrand", 171 | "http", 172 | ] 173 | 174 | [[package]] 175 | name = "aws-sdk-sts" 176 | version = "0.2.0" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "74056f7f75eabfb600311f45bdcaae17b29a6f413af1f9c43aca6c486bdeb7af" 179 | dependencies = [ 180 | "aws-endpoint", 181 | "aws-http", 182 | "aws-hyper", 183 | "aws-sig-auth", 184 | "aws-smithy-async", 185 | "aws-smithy-client", 186 | "aws-smithy-http", 187 | "aws-smithy-query", 188 | "aws-smithy-types", 189 | "aws-smithy-xml", 190 | "aws-types", 191 | "bytes", 192 | "http", 193 | ] 194 | 195 | [[package]] 196 | name = "aws-sig-auth" 197 | version = "0.2.0" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "7a16b8c9818854a3a3bba85e970f59d7f09ca0985ff10c9031bb03c95b291323" 200 | dependencies = [ 201 | "aws-sigv4", 202 | "aws-smithy-http", 203 | "aws-types", 204 | "http", 205 | "thiserror", 206 | "tracing", 207 | ] 208 | 209 | [[package]] 210 | name = "aws-sigv4" 211 | version = "0.2.0" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "f7f531763d106b1f050421d8256ce5d585e75e861d466fe8920157a004d28bf0" 214 | dependencies = [ 215 | "form_urlencoded", 216 | "hex", 217 | "http", 218 | "once_cell", 219 | "percent-encoding", 220 | "regex", 221 | "ring", 222 | "time 0.3.5", 223 | "tracing", 224 | ] 225 | 226 | [[package]] 227 | name = "aws-smithy-async" 228 | version = "0.32.0" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "969717af8b7eb7424b67fce3f3c8539b0cf72322f909a30d7ea9e8c5ed2bf929" 231 | dependencies = [ 232 | "pin-project-lite", 233 | "tokio", 234 | ] 235 | 236 | [[package]] 237 | name = "aws-smithy-client" 238 | version = "0.32.0" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "97ffd13190653d37833cf403f7b2963bdd903166933db231a13bdc48ba3fd237" 241 | dependencies = [ 242 | "aws-smithy-async", 243 | "aws-smithy-http", 244 | "aws-smithy-http-tower", 245 | "aws-smithy-types", 246 | "bytes", 247 | "fastrand", 248 | "http", 249 | "http-body", 250 | "hyper", 251 | "hyper-rustls", 252 | "lazy_static", 253 | "pin-project", 254 | "pin-project-lite", 255 | "tokio", 256 | "tower", 257 | "tracing", 258 | ] 259 | 260 | [[package]] 261 | name = "aws-smithy-http" 262 | version = "0.32.0" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "d4b5992632c561f03699f25d1deda4c73b70be7c9acc0fc3626b270d3cb9a987" 265 | dependencies = [ 266 | "aws-smithy-types", 267 | "bytes", 268 | "bytes-utils", 269 | "futures-core", 270 | "http", 271 | "http-body", 272 | "hyper", 273 | "percent-encoding", 274 | "pin-project", 275 | "tokio", 276 | "tokio-util", 277 | "tracing", 278 | ] 279 | 280 | [[package]] 281 | name = "aws-smithy-http-tower" 282 | version = "0.32.0" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "aaff953c819ed72da79b302ce7ca4464881af23eadc7e5762e9244c90ae6b708" 285 | dependencies = [ 286 | "aws-smithy-http", 287 | "bytes", 288 | "http", 289 | "http-body", 290 | "pin-project", 291 | "tower", 292 | "tracing", 293 | ] 294 | 295 | [[package]] 296 | name = "aws-smithy-json" 297 | version = "0.32.0" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "1656c19cedeaf2d9b2b42cfebf76d1cae7c7d69c454bd2ab2e0b55b7dfa4442c" 300 | dependencies = [ 301 | "aws-smithy-types", 302 | ] 303 | 304 | [[package]] 305 | name = "aws-smithy-query" 306 | version = "0.32.0" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "504c2b89119b68cec24e8ef6d9e2e2b8566a358faf096b4c78fdcf99732b0839" 309 | dependencies = [ 310 | "aws-smithy-types", 311 | "urlencoding", 312 | ] 313 | 314 | [[package]] 315 | name = "aws-smithy-types" 316 | version = "0.32.0" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "6371c45cde03dc11814f63496366367dacd19af6bfc089c27582bad0c7384fab" 319 | dependencies = [ 320 | "itoa", 321 | "num-integer", 322 | "ryu", 323 | "time 0.3.5", 324 | ] 325 | 326 | [[package]] 327 | name = "aws-smithy-xml" 328 | version = "0.32.0" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "167c7e63beace20d29d94143c5a6dd6f4d24142c97ef6c36d8bc7fbf9475c93b" 331 | dependencies = [ 332 | "thiserror", 333 | "xmlparser", 334 | ] 335 | 336 | [[package]] 337 | name = "aws-types" 338 | version = "0.2.0" 339 | source = "registry+https://github.com/rust-lang/crates.io-index" 340 | checksum = "2d3d5fa5c7fba8b0e9b743ba3da17a14c9f2e882f775d5ed198b602fb331b670" 341 | dependencies = [ 342 | "aws-smithy-async", 343 | "aws-smithy-types", 344 | "rustc_version", 345 | "tracing", 346 | "zeroize", 347 | ] 348 | 349 | [[package]] 350 | name = "backtrace" 351 | version = "0.3.63" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6" 354 | dependencies = [ 355 | "addr2line", 356 | "cc", 357 | "cfg-if", 358 | "libc", 359 | "miniz_oxide", 360 | "object", 361 | "rustc-demangle", 362 | ] 363 | 364 | [[package]] 365 | name = "base64" 366 | version = "0.13.0" 367 | source = "registry+https://github.com/rust-lang/crates.io-index" 368 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 369 | 370 | [[package]] 371 | name = "bitflags" 372 | version = "1.3.2" 373 | source = "registry+https://github.com/rust-lang/crates.io-index" 374 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 375 | 376 | [[package]] 377 | name = "bitte" 378 | version = "0.5.0-dev" 379 | dependencies = [ 380 | "anyhow", 381 | "aws-config", 382 | "aws-sdk-ec2", 383 | "clap", 384 | "clap_generate", 385 | "deploy-rs", 386 | "enum-utils", 387 | "log", 388 | "netrc-rs", 389 | "pretty_env_logger", 390 | "prettytable-rs", 391 | "regex", 392 | "reqwest", 393 | "serde", 394 | "serde_json", 395 | "thiserror", 396 | "tokio", 397 | "uuid", 398 | ] 399 | 400 | [[package]] 401 | name = "blake2b_simd" 402 | version = "0.5.11" 403 | source = "registry+https://github.com/rust-lang/crates.io-index" 404 | checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" 405 | dependencies = [ 406 | "arrayref", 407 | "arrayvec", 408 | "constant_time_eq", 409 | ] 410 | 411 | [[package]] 412 | name = "bstr" 413 | version = "0.2.17" 414 | source = "registry+https://github.com/rust-lang/crates.io-index" 415 | checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" 416 | dependencies = [ 417 | "lazy_static", 418 | "memchr", 419 | "regex-automata", 420 | "serde", 421 | ] 422 | 423 | [[package]] 424 | name = "bumpalo" 425 | version = "3.8.0" 426 | source = "registry+https://github.com/rust-lang/crates.io-index" 427 | checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" 428 | 429 | [[package]] 430 | name = "byteorder" 431 | version = "1.4.3" 432 | source = "registry+https://github.com/rust-lang/crates.io-index" 433 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 434 | 435 | [[package]] 436 | name = "bytes" 437 | version = "1.1.0" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" 440 | 441 | [[package]] 442 | name = "bytes-utils" 443 | version = "0.1.1" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "4e314712951c43123e5920a446464929adc667a5eade7f8fb3997776c9df6e54" 446 | dependencies = [ 447 | "bytes", 448 | "either", 449 | ] 450 | 451 | [[package]] 452 | name = "cbitset" 453 | version = "0.2.0" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "29b6ad25ae296159fb0da12b970b2fe179b234584d7cd294c891e2bbb284466b" 456 | dependencies = [ 457 | "num-traits", 458 | ] 459 | 460 | [[package]] 461 | name = "cc" 462 | version = "1.0.72" 463 | source = "registry+https://github.com/rust-lang/crates.io-index" 464 | checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" 465 | 466 | [[package]] 467 | name = "cfg-if" 468 | version = "1.0.0" 469 | source = "registry+https://github.com/rust-lang/crates.io-index" 470 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 471 | 472 | [[package]] 473 | name = "chrono" 474 | version = "0.4.19" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 477 | dependencies = [ 478 | "libc", 479 | "num-integer", 480 | "num-traits", 481 | "time 0.1.43", 482 | "winapi", 483 | ] 484 | 485 | [[package]] 486 | name = "clap" 487 | version = "3.0.0-rc.3" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "098d281b47bf725a0bddd829e0070ee76560faab8af123050a86c440d7f0a1fd" 490 | dependencies = [ 491 | "atty", 492 | "bitflags", 493 | "clap_derive", 494 | "indexmap", 495 | "lazy_static", 496 | "os_str_bytes", 497 | "strsim", 498 | "termcolor", 499 | "terminal_size", 500 | "textwrap", 501 | ] 502 | 503 | [[package]] 504 | name = "clap_derive" 505 | version = "3.0.0-rc.3" 506 | source = "registry+https://github.com/rust-lang/crates.io-index" 507 | checksum = "26de8102ffb96701066cea36f9a104285b67fbcc302a520640289d476c15ed8a" 508 | dependencies = [ 509 | "heck", 510 | "proc-macro-error", 511 | "proc-macro2", 512 | "quote", 513 | "syn", 514 | ] 515 | 516 | [[package]] 517 | name = "clap_generate" 518 | version = "3.0.0-rc.3" 519 | source = "registry+https://github.com/rust-lang/crates.io-index" 520 | checksum = "e6348a4d94b0a7554e2725a77db6c6e2f897688f77230c083f51856ef021eb7d" 521 | dependencies = [ 522 | "clap", 523 | ] 524 | 525 | [[package]] 526 | name = "constant_time_eq" 527 | version = "0.1.5" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" 530 | 531 | [[package]] 532 | name = "core-foundation" 533 | version = "0.9.2" 534 | source = "registry+https://github.com/rust-lang/crates.io-index" 535 | checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" 536 | dependencies = [ 537 | "core-foundation-sys", 538 | "libc", 539 | ] 540 | 541 | [[package]] 542 | name = "core-foundation-sys" 543 | version = "0.8.3" 544 | source = "registry+https://github.com/rust-lang/crates.io-index" 545 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" 546 | 547 | [[package]] 548 | name = "crc32fast" 549 | version = "1.3.0" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836" 552 | dependencies = [ 553 | "cfg-if", 554 | ] 555 | 556 | [[package]] 557 | name = "crossbeam-channel" 558 | version = "0.5.1" 559 | source = "registry+https://github.com/rust-lang/crates.io-index" 560 | checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" 561 | dependencies = [ 562 | "cfg-if", 563 | "crossbeam-utils", 564 | ] 565 | 566 | [[package]] 567 | name = "crossbeam-utils" 568 | version = "0.8.5" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" 571 | dependencies = [ 572 | "cfg-if", 573 | "lazy_static", 574 | ] 575 | 576 | [[package]] 577 | name = "csv" 578 | version = "1.1.6" 579 | source = "registry+https://github.com/rust-lang/crates.io-index" 580 | checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" 581 | dependencies = [ 582 | "bstr", 583 | "csv-core", 584 | "itoa", 585 | "ryu", 586 | "serde", 587 | ] 588 | 589 | [[package]] 590 | name = "csv-core" 591 | version = "0.1.10" 592 | source = "registry+https://github.com/rust-lang/crates.io-index" 593 | checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" 594 | dependencies = [ 595 | "memchr", 596 | ] 597 | 598 | [[package]] 599 | name = "ct-logs" 600 | version = "0.8.0" 601 | source = "registry+https://github.com/rust-lang/crates.io-index" 602 | checksum = "c1a816186fa68d9e426e3cb4ae4dff1fcd8e4a2c34b781bf7a822574a0d0aac8" 603 | dependencies = [ 604 | "sct", 605 | ] 606 | 607 | [[package]] 608 | name = "deploy-rs" 609 | version = "0.1.0" 610 | source = "git+https://github.com/input-output-hk/deploy-rs#0c02577acd42015b9575594dea31737ec033dc06" 611 | dependencies = [ 612 | "clap", 613 | "envmnt", 614 | "flexi_logger", 615 | "futures-util", 616 | "linked_hash_set", 617 | "log", 618 | "merge", 619 | "notify", 620 | "rnix", 621 | "serde", 622 | "serde_json", 623 | "signal-hook", 624 | "smol_str", 625 | "thiserror", 626 | "tokio", 627 | "toml", 628 | "whoami", 629 | "yn", 630 | ] 631 | 632 | [[package]] 633 | name = "dirs" 634 | version = "1.0.5" 635 | source = "registry+https://github.com/rust-lang/crates.io-index" 636 | checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" 637 | dependencies = [ 638 | "libc", 639 | "redox_users", 640 | "winapi", 641 | ] 642 | 643 | [[package]] 644 | name = "dunce" 645 | version = "1.0.2" 646 | source = "registry+https://github.com/rust-lang/crates.io-index" 647 | checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541" 648 | 649 | [[package]] 650 | name = "either" 651 | version = "1.6.1" 652 | source = "registry+https://github.com/rust-lang/crates.io-index" 653 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 654 | 655 | [[package]] 656 | name = "encode_unicode" 657 | version = "0.3.6" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 660 | 661 | [[package]] 662 | name = "encoding_rs" 663 | version = "0.8.30" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" 666 | dependencies = [ 667 | "cfg-if", 668 | ] 669 | 670 | [[package]] 671 | name = "enum-utils" 672 | version = "0.1.2" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "ed327f716d0d351d86c9fd3398d20ee39ad8f681873cc081da2ca1c10fed398a" 675 | dependencies = [ 676 | "enum-utils-from-str", 677 | "failure", 678 | "proc-macro2", 679 | "quote", 680 | "serde_derive_internals", 681 | "syn", 682 | ] 683 | 684 | [[package]] 685 | name = "enum-utils-from-str" 686 | version = "0.1.2" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "d49be08bad6e4ca87b2b8e74146987d4e5cb3b7512efa50ef505b51a22227ee1" 689 | dependencies = [ 690 | "proc-macro2", 691 | "quote", 692 | ] 693 | 694 | [[package]] 695 | name = "env_logger" 696 | version = "0.7.1" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" 699 | dependencies = [ 700 | "atty", 701 | "humantime", 702 | "log", 703 | "regex", 704 | "termcolor", 705 | ] 706 | 707 | [[package]] 708 | name = "envmnt" 709 | version = "0.9.1" 710 | source = "registry+https://github.com/rust-lang/crates.io-index" 711 | checksum = "0f96dd862f12fac698dec3932dff0e6fb34bffeb5515ae5932d620cfe076571e" 712 | dependencies = [ 713 | "fsio", 714 | "indexmap", 715 | ] 716 | 717 | [[package]] 718 | name = "failure" 719 | version = "0.1.8" 720 | source = "registry+https://github.com/rust-lang/crates.io-index" 721 | checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" 722 | dependencies = [ 723 | "backtrace", 724 | ] 725 | 726 | [[package]] 727 | name = "fastrand" 728 | version = "1.5.0" 729 | source = "registry+https://github.com/rust-lang/crates.io-index" 730 | checksum = "b394ed3d285a429378d3b384b9eb1285267e7df4b166df24b7a6939a04dc392e" 731 | dependencies = [ 732 | "instant", 733 | ] 734 | 735 | [[package]] 736 | name = "filetime" 737 | version = "0.2.15" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" 740 | dependencies = [ 741 | "cfg-if", 742 | "libc", 743 | "redox_syscall 0.2.10", 744 | "winapi", 745 | ] 746 | 747 | [[package]] 748 | name = "flate2" 749 | version = "1.0.22" 750 | source = "registry+https://github.com/rust-lang/crates.io-index" 751 | checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" 752 | dependencies = [ 753 | "cfg-if", 754 | "crc32fast", 755 | "libc", 756 | "miniz_oxide", 757 | ] 758 | 759 | [[package]] 760 | name = "flexi_logger" 761 | version = "0.16.3" 762 | source = "registry+https://github.com/rust-lang/crates.io-index" 763 | checksum = "291b6ce7b3ed2dda82efa6aee4c6bdb55fd11bc88b06c55b01851e94b96e5322" 764 | dependencies = [ 765 | "atty", 766 | "chrono", 767 | "glob", 768 | "lazy_static", 769 | "log", 770 | "regex", 771 | "thiserror", 772 | "yansi", 773 | ] 774 | 775 | [[package]] 776 | name = "fnv" 777 | version = "1.0.7" 778 | source = "registry+https://github.com/rust-lang/crates.io-index" 779 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 780 | 781 | [[package]] 782 | name = "foreign-types" 783 | version = "0.3.2" 784 | source = "registry+https://github.com/rust-lang/crates.io-index" 785 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 786 | dependencies = [ 787 | "foreign-types-shared", 788 | ] 789 | 790 | [[package]] 791 | name = "foreign-types-shared" 792 | version = "0.1.1" 793 | source = "registry+https://github.com/rust-lang/crates.io-index" 794 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 795 | 796 | [[package]] 797 | name = "form_urlencoded" 798 | version = "1.0.1" 799 | source = "registry+https://github.com/rust-lang/crates.io-index" 800 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 801 | dependencies = [ 802 | "matches", 803 | "percent-encoding", 804 | ] 805 | 806 | [[package]] 807 | name = "fsevent-sys" 808 | version = "4.0.0" 809 | source = "registry+https://github.com/rust-lang/crates.io-index" 810 | checksum = "5c0e564d24da983c053beff1bb7178e237501206840a3e6bf4e267b9e8ae734a" 811 | dependencies = [ 812 | "libc", 813 | ] 814 | 815 | [[package]] 816 | name = "fsio" 817 | version = "0.3.0" 818 | source = "registry+https://github.com/rust-lang/crates.io-index" 819 | checksum = "09e87827efaf94c7a44b562ff57de06930712fe21b530c3797cdede26e6377eb" 820 | dependencies = [ 821 | "dunce", 822 | ] 823 | 824 | [[package]] 825 | name = "futures-channel" 826 | version = "0.3.18" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27" 829 | dependencies = [ 830 | "futures-core", 831 | ] 832 | 833 | [[package]] 834 | name = "futures-core" 835 | version = "0.3.18" 836 | source = "registry+https://github.com/rust-lang/crates.io-index" 837 | checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445" 838 | 839 | [[package]] 840 | name = "futures-macro" 841 | version = "0.3.18" 842 | source = "registry+https://github.com/rust-lang/crates.io-index" 843 | checksum = "a89f17b21645bc4ed773c69af9c9a0effd4a3f1a3876eadd453469f8854e7fdd" 844 | dependencies = [ 845 | "proc-macro2", 846 | "quote", 847 | "syn", 848 | ] 849 | 850 | [[package]] 851 | name = "futures-sink" 852 | version = "0.3.18" 853 | source = "registry+https://github.com/rust-lang/crates.io-index" 854 | checksum = "996c6442437b62d21a32cd9906f9c41e7dc1e19a9579843fad948696769305af" 855 | 856 | [[package]] 857 | name = "futures-task" 858 | version = "0.3.18" 859 | source = "registry+https://github.com/rust-lang/crates.io-index" 860 | checksum = "dabf1872aaab32c886832f2276d2f5399887e2bd613698a02359e4ea83f8de12" 861 | 862 | [[package]] 863 | name = "futures-util" 864 | version = "0.3.18" 865 | source = "registry+https://github.com/rust-lang/crates.io-index" 866 | checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e" 867 | dependencies = [ 868 | "futures-core", 869 | "futures-macro", 870 | "futures-task", 871 | "pin-project-lite", 872 | "pin-utils", 873 | "slab", 874 | ] 875 | 876 | [[package]] 877 | name = "getrandom" 878 | version = "0.1.16" 879 | source = "registry+https://github.com/rust-lang/crates.io-index" 880 | checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" 881 | dependencies = [ 882 | "cfg-if", 883 | "libc", 884 | "wasi 0.9.0+wasi-snapshot-preview1", 885 | ] 886 | 887 | [[package]] 888 | name = "getrandom" 889 | version = "0.2.3" 890 | source = "registry+https://github.com/rust-lang/crates.io-index" 891 | checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" 892 | dependencies = [ 893 | "cfg-if", 894 | "libc", 895 | "wasi 0.10.2+wasi-snapshot-preview1", 896 | ] 897 | 898 | [[package]] 899 | name = "gimli" 900 | version = "0.26.1" 901 | source = "registry+https://github.com/rust-lang/crates.io-index" 902 | checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" 903 | 904 | [[package]] 905 | name = "glob" 906 | version = "0.3.0" 907 | source = "registry+https://github.com/rust-lang/crates.io-index" 908 | checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" 909 | 910 | [[package]] 911 | name = "h2" 912 | version = "0.3.9" 913 | source = "registry+https://github.com/rust-lang/crates.io-index" 914 | checksum = "8f072413d126e57991455e0a922b31e4c8ba7c2ffbebf6b78b4f8521397d65cd" 915 | dependencies = [ 916 | "bytes", 917 | "fnv", 918 | "futures-core", 919 | "futures-sink", 920 | "futures-util", 921 | "http", 922 | "indexmap", 923 | "slab", 924 | "tokio", 925 | "tokio-util", 926 | "tracing", 927 | ] 928 | 929 | [[package]] 930 | name = "hashbrown" 931 | version = "0.11.2" 932 | source = "registry+https://github.com/rust-lang/crates.io-index" 933 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 934 | 935 | [[package]] 936 | name = "heck" 937 | version = "0.3.3" 938 | source = "registry+https://github.com/rust-lang/crates.io-index" 939 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 940 | dependencies = [ 941 | "unicode-segmentation", 942 | ] 943 | 944 | [[package]] 945 | name = "hermit-abi" 946 | version = "0.1.19" 947 | source = "registry+https://github.com/rust-lang/crates.io-index" 948 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 949 | dependencies = [ 950 | "libc", 951 | ] 952 | 953 | [[package]] 954 | name = "hex" 955 | version = "0.4.3" 956 | source = "registry+https://github.com/rust-lang/crates.io-index" 957 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 958 | 959 | [[package]] 960 | name = "http" 961 | version = "0.2.5" 962 | source = "registry+https://github.com/rust-lang/crates.io-index" 963 | checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" 964 | dependencies = [ 965 | "bytes", 966 | "fnv", 967 | "itoa", 968 | ] 969 | 970 | [[package]] 971 | name = "http-body" 972 | version = "0.4.4" 973 | source = "registry+https://github.com/rust-lang/crates.io-index" 974 | checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" 975 | dependencies = [ 976 | "bytes", 977 | "http", 978 | "pin-project-lite", 979 | ] 980 | 981 | [[package]] 982 | name = "httparse" 983 | version = "1.5.1" 984 | source = "registry+https://github.com/rust-lang/crates.io-index" 985 | checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" 986 | 987 | [[package]] 988 | name = "httpdate" 989 | version = "1.0.2" 990 | source = "registry+https://github.com/rust-lang/crates.io-index" 991 | checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" 992 | 993 | [[package]] 994 | name = "humantime" 995 | version = "1.3.0" 996 | source = "registry+https://github.com/rust-lang/crates.io-index" 997 | checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" 998 | dependencies = [ 999 | "quick-error", 1000 | ] 1001 | 1002 | [[package]] 1003 | name = "hyper" 1004 | version = "0.14.16" 1005 | source = "registry+https://github.com/rust-lang/crates.io-index" 1006 | checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" 1007 | dependencies = [ 1008 | "bytes", 1009 | "futures-channel", 1010 | "futures-core", 1011 | "futures-util", 1012 | "h2", 1013 | "http", 1014 | "http-body", 1015 | "httparse", 1016 | "httpdate", 1017 | "itoa", 1018 | "pin-project-lite", 1019 | "socket2", 1020 | "tokio", 1021 | "tower-service", 1022 | "tracing", 1023 | "want", 1024 | ] 1025 | 1026 | [[package]] 1027 | name = "hyper-rustls" 1028 | version = "0.22.1" 1029 | source = "registry+https://github.com/rust-lang/crates.io-index" 1030 | checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" 1031 | dependencies = [ 1032 | "ct-logs", 1033 | "futures-util", 1034 | "hyper", 1035 | "log", 1036 | "rustls", 1037 | "rustls-native-certs", 1038 | "tokio", 1039 | "tokio-rustls", 1040 | "webpki", 1041 | ] 1042 | 1043 | [[package]] 1044 | name = "hyper-tls" 1045 | version = "0.5.0" 1046 | source = "registry+https://github.com/rust-lang/crates.io-index" 1047 | checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" 1048 | dependencies = [ 1049 | "bytes", 1050 | "hyper", 1051 | "native-tls", 1052 | "tokio", 1053 | "tokio-native-tls", 1054 | ] 1055 | 1056 | [[package]] 1057 | name = "idna" 1058 | version = "0.2.3" 1059 | source = "registry+https://github.com/rust-lang/crates.io-index" 1060 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 1061 | dependencies = [ 1062 | "matches", 1063 | "unicode-bidi", 1064 | "unicode-normalization", 1065 | ] 1066 | 1067 | [[package]] 1068 | name = "indexmap" 1069 | version = "1.7.0" 1070 | source = "registry+https://github.com/rust-lang/crates.io-index" 1071 | checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" 1072 | dependencies = [ 1073 | "autocfg", 1074 | "hashbrown", 1075 | ] 1076 | 1077 | [[package]] 1078 | name = "inotify" 1079 | version = "0.9.6" 1080 | source = "registry+https://github.com/rust-lang/crates.io-index" 1081 | checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" 1082 | dependencies = [ 1083 | "bitflags", 1084 | "inotify-sys", 1085 | "libc", 1086 | ] 1087 | 1088 | [[package]] 1089 | name = "inotify-sys" 1090 | version = "0.1.5" 1091 | source = "registry+https://github.com/rust-lang/crates.io-index" 1092 | checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" 1093 | dependencies = [ 1094 | "libc", 1095 | ] 1096 | 1097 | [[package]] 1098 | name = "instant" 1099 | version = "0.1.12" 1100 | source = "registry+https://github.com/rust-lang/crates.io-index" 1101 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 1102 | dependencies = [ 1103 | "cfg-if", 1104 | ] 1105 | 1106 | [[package]] 1107 | name = "ipnet" 1108 | version = "2.3.1" 1109 | source = "registry+https://github.com/rust-lang/crates.io-index" 1110 | checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" 1111 | 1112 | [[package]] 1113 | name = "itoa" 1114 | version = "0.4.8" 1115 | source = "registry+https://github.com/rust-lang/crates.io-index" 1116 | checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" 1117 | 1118 | [[package]] 1119 | name = "js-sys" 1120 | version = "0.3.55" 1121 | source = "registry+https://github.com/rust-lang/crates.io-index" 1122 | checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" 1123 | dependencies = [ 1124 | "wasm-bindgen", 1125 | ] 1126 | 1127 | [[package]] 1128 | name = "kqueue" 1129 | version = "1.0.4" 1130 | source = "registry+https://github.com/rust-lang/crates.io-index" 1131 | checksum = "058a107a784f8be94c7d35c1300f4facced2e93d2fbe5b1452b44e905ddca4a9" 1132 | dependencies = [ 1133 | "kqueue-sys", 1134 | "libc", 1135 | ] 1136 | 1137 | [[package]] 1138 | name = "kqueue-sys" 1139 | version = "1.0.3" 1140 | source = "registry+https://github.com/rust-lang/crates.io-index" 1141 | checksum = "8367585489f01bc55dd27404dcf56b95e6da061a256a666ab23be9ba96a2e587" 1142 | dependencies = [ 1143 | "bitflags", 1144 | "libc", 1145 | ] 1146 | 1147 | [[package]] 1148 | name = "lazy_static" 1149 | version = "1.4.0" 1150 | source = "registry+https://github.com/rust-lang/crates.io-index" 1151 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 1152 | 1153 | [[package]] 1154 | name = "libc" 1155 | version = "0.2.109" 1156 | source = "registry+https://github.com/rust-lang/crates.io-index" 1157 | checksum = "f98a04dce437184842841303488f70d0188c5f51437d2a834dc097eafa909a01" 1158 | 1159 | [[package]] 1160 | name = "linked-hash-map" 1161 | version = "0.5.4" 1162 | source = "registry+https://github.com/rust-lang/crates.io-index" 1163 | checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" 1164 | 1165 | [[package]] 1166 | name = "linked_hash_set" 1167 | version = "0.1.4" 1168 | source = "registry+https://github.com/rust-lang/crates.io-index" 1169 | checksum = "47186c6da4d81ca383c7c47c1bfc80f4b95f4720514d860a5407aaf4233f9588" 1170 | dependencies = [ 1171 | "linked-hash-map", 1172 | ] 1173 | 1174 | [[package]] 1175 | name = "lock_api" 1176 | version = "0.4.5" 1177 | source = "registry+https://github.com/rust-lang/crates.io-index" 1178 | checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" 1179 | dependencies = [ 1180 | "scopeguard", 1181 | ] 1182 | 1183 | [[package]] 1184 | name = "log" 1185 | version = "0.4.14" 1186 | source = "registry+https://github.com/rust-lang/crates.io-index" 1187 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 1188 | dependencies = [ 1189 | "cfg-if", 1190 | ] 1191 | 1192 | [[package]] 1193 | name = "matches" 1194 | version = "0.1.9" 1195 | source = "registry+https://github.com/rust-lang/crates.io-index" 1196 | checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" 1197 | 1198 | [[package]] 1199 | name = "memchr" 1200 | version = "2.4.1" 1201 | source = "registry+https://github.com/rust-lang/crates.io-index" 1202 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 1203 | 1204 | [[package]] 1205 | name = "merge" 1206 | version = "0.1.0" 1207 | source = "registry+https://github.com/rust-lang/crates.io-index" 1208 | checksum = "10bbef93abb1da61525bbc45eeaff6473a41907d19f8f9aa5168d214e10693e9" 1209 | dependencies = [ 1210 | "merge_derive", 1211 | "num-traits", 1212 | ] 1213 | 1214 | [[package]] 1215 | name = "merge_derive" 1216 | version = "0.1.0" 1217 | source = "registry+https://github.com/rust-lang/crates.io-index" 1218 | checksum = "209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07" 1219 | dependencies = [ 1220 | "proc-macro-error", 1221 | "proc-macro2", 1222 | "quote", 1223 | "syn", 1224 | ] 1225 | 1226 | [[package]] 1227 | name = "mime" 1228 | version = "0.3.16" 1229 | source = "registry+https://github.com/rust-lang/crates.io-index" 1230 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 1231 | 1232 | [[package]] 1233 | name = "miniz_oxide" 1234 | version = "0.4.4" 1235 | source = "registry+https://github.com/rust-lang/crates.io-index" 1236 | checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" 1237 | dependencies = [ 1238 | "adler", 1239 | "autocfg", 1240 | ] 1241 | 1242 | [[package]] 1243 | name = "mio" 1244 | version = "0.7.14" 1245 | source = "registry+https://github.com/rust-lang/crates.io-index" 1246 | checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" 1247 | dependencies = [ 1248 | "libc", 1249 | "log", 1250 | "miow", 1251 | "ntapi", 1252 | "winapi", 1253 | ] 1254 | 1255 | [[package]] 1256 | name = "miow" 1257 | version = "0.3.7" 1258 | source = "registry+https://github.com/rust-lang/crates.io-index" 1259 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 1260 | dependencies = [ 1261 | "winapi", 1262 | ] 1263 | 1264 | [[package]] 1265 | name = "native-tls" 1266 | version = "0.2.8" 1267 | source = "registry+https://github.com/rust-lang/crates.io-index" 1268 | checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" 1269 | dependencies = [ 1270 | "lazy_static", 1271 | "libc", 1272 | "log", 1273 | "openssl", 1274 | "openssl-probe", 1275 | "openssl-sys", 1276 | "schannel", 1277 | "security-framework", 1278 | "security-framework-sys", 1279 | "tempfile", 1280 | ] 1281 | 1282 | [[package]] 1283 | name = "netrc-rs" 1284 | version = "0.1.2" 1285 | source = "registry+https://github.com/rust-lang/crates.io-index" 1286 | checksum = "ea2970fbbc8c785e8246234a7bd004ed66cd1ed1a35ec73669a92545e419b836" 1287 | 1288 | [[package]] 1289 | name = "notify" 1290 | version = "5.0.0-pre.13" 1291 | source = "registry+https://github.com/rust-lang/crates.io-index" 1292 | checksum = "245d358380e2352c2d020e8ee62baac09b3420f1f6c012a31326cfced4ad487d" 1293 | dependencies = [ 1294 | "bitflags", 1295 | "crossbeam-channel", 1296 | "filetime", 1297 | "fsevent-sys", 1298 | "inotify", 1299 | "kqueue", 1300 | "libc", 1301 | "mio", 1302 | "walkdir", 1303 | "winapi", 1304 | ] 1305 | 1306 | [[package]] 1307 | name = "ntapi" 1308 | version = "0.3.6" 1309 | source = "registry+https://github.com/rust-lang/crates.io-index" 1310 | checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" 1311 | dependencies = [ 1312 | "winapi", 1313 | ] 1314 | 1315 | [[package]] 1316 | name = "num-integer" 1317 | version = "0.1.44" 1318 | source = "registry+https://github.com/rust-lang/crates.io-index" 1319 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 1320 | dependencies = [ 1321 | "autocfg", 1322 | "num-traits", 1323 | ] 1324 | 1325 | [[package]] 1326 | name = "num-traits" 1327 | version = "0.2.14" 1328 | source = "registry+https://github.com/rust-lang/crates.io-index" 1329 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 1330 | dependencies = [ 1331 | "autocfg", 1332 | ] 1333 | 1334 | [[package]] 1335 | name = "num_cpus" 1336 | version = "1.13.0" 1337 | source = "registry+https://github.com/rust-lang/crates.io-index" 1338 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 1339 | dependencies = [ 1340 | "hermit-abi", 1341 | "libc", 1342 | ] 1343 | 1344 | [[package]] 1345 | name = "object" 1346 | version = "0.27.1" 1347 | source = "registry+https://github.com/rust-lang/crates.io-index" 1348 | checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" 1349 | dependencies = [ 1350 | "memchr", 1351 | ] 1352 | 1353 | [[package]] 1354 | name = "once_cell" 1355 | version = "1.8.0" 1356 | source = "registry+https://github.com/rust-lang/crates.io-index" 1357 | checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" 1358 | 1359 | [[package]] 1360 | name = "openssl" 1361 | version = "0.10.38" 1362 | source = "registry+https://github.com/rust-lang/crates.io-index" 1363 | checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" 1364 | dependencies = [ 1365 | "bitflags", 1366 | "cfg-if", 1367 | "foreign-types", 1368 | "libc", 1369 | "once_cell", 1370 | "openssl-sys", 1371 | ] 1372 | 1373 | [[package]] 1374 | name = "openssl-probe" 1375 | version = "0.1.4" 1376 | source = "registry+https://github.com/rust-lang/crates.io-index" 1377 | checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" 1378 | 1379 | [[package]] 1380 | name = "openssl-sys" 1381 | version = "0.9.71" 1382 | source = "registry+https://github.com/rust-lang/crates.io-index" 1383 | checksum = "7df13d165e607909b363a4757a6f133f8a818a74e9d3a98d09c6128e15fa4c73" 1384 | dependencies = [ 1385 | "autocfg", 1386 | "cc", 1387 | "libc", 1388 | "pkg-config", 1389 | "vcpkg", 1390 | ] 1391 | 1392 | [[package]] 1393 | name = "os_str_bytes" 1394 | version = "6.0.0" 1395 | source = "registry+https://github.com/rust-lang/crates.io-index" 1396 | checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" 1397 | dependencies = [ 1398 | "memchr", 1399 | ] 1400 | 1401 | [[package]] 1402 | name = "parking_lot" 1403 | version = "0.11.2" 1404 | source = "registry+https://github.com/rust-lang/crates.io-index" 1405 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 1406 | dependencies = [ 1407 | "instant", 1408 | "lock_api", 1409 | "parking_lot_core", 1410 | ] 1411 | 1412 | [[package]] 1413 | name = "parking_lot_core" 1414 | version = "0.8.5" 1415 | source = "registry+https://github.com/rust-lang/crates.io-index" 1416 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 1417 | dependencies = [ 1418 | "cfg-if", 1419 | "instant", 1420 | "libc", 1421 | "redox_syscall 0.2.10", 1422 | "smallvec", 1423 | "winapi", 1424 | ] 1425 | 1426 | [[package]] 1427 | name = "percent-encoding" 1428 | version = "2.1.0" 1429 | source = "registry+https://github.com/rust-lang/crates.io-index" 1430 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 1431 | 1432 | [[package]] 1433 | name = "pin-project" 1434 | version = "1.0.8" 1435 | source = "registry+https://github.com/rust-lang/crates.io-index" 1436 | checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" 1437 | dependencies = [ 1438 | "pin-project-internal", 1439 | ] 1440 | 1441 | [[package]] 1442 | name = "pin-project-internal" 1443 | version = "1.0.8" 1444 | source = "registry+https://github.com/rust-lang/crates.io-index" 1445 | checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" 1446 | dependencies = [ 1447 | "proc-macro2", 1448 | "quote", 1449 | "syn", 1450 | ] 1451 | 1452 | [[package]] 1453 | name = "pin-project-lite" 1454 | version = "0.2.7" 1455 | source = "registry+https://github.com/rust-lang/crates.io-index" 1456 | checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" 1457 | 1458 | [[package]] 1459 | name = "pin-utils" 1460 | version = "0.1.0" 1461 | source = "registry+https://github.com/rust-lang/crates.io-index" 1462 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1463 | 1464 | [[package]] 1465 | name = "pkg-config" 1466 | version = "0.3.23" 1467 | source = "registry+https://github.com/rust-lang/crates.io-index" 1468 | checksum = "d1a3ea4f0dd7f1f3e512cf97bf100819aa547f36a6eccac8dbaae839eb92363e" 1469 | 1470 | [[package]] 1471 | name = "ppv-lite86" 1472 | version = "0.2.15" 1473 | source = "registry+https://github.com/rust-lang/crates.io-index" 1474 | checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" 1475 | 1476 | [[package]] 1477 | name = "pretty_env_logger" 1478 | version = "0.4.0" 1479 | source = "registry+https://github.com/rust-lang/crates.io-index" 1480 | checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" 1481 | dependencies = [ 1482 | "env_logger", 1483 | "log", 1484 | ] 1485 | 1486 | [[package]] 1487 | name = "prettytable-rs" 1488 | version = "0.8.0" 1489 | source = "registry+https://github.com/rust-lang/crates.io-index" 1490 | checksum = "0fd04b170004fa2daccf418a7f8253aaf033c27760b5f225889024cf66d7ac2e" 1491 | dependencies = [ 1492 | "atty", 1493 | "csv", 1494 | "encode_unicode", 1495 | "lazy_static", 1496 | "term", 1497 | "unicode-width", 1498 | ] 1499 | 1500 | [[package]] 1501 | name = "proc-macro-error" 1502 | version = "1.0.4" 1503 | source = "registry+https://github.com/rust-lang/crates.io-index" 1504 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 1505 | dependencies = [ 1506 | "proc-macro-error-attr", 1507 | "proc-macro2", 1508 | "quote", 1509 | "syn", 1510 | "version_check", 1511 | ] 1512 | 1513 | [[package]] 1514 | name = "proc-macro-error-attr" 1515 | version = "1.0.4" 1516 | source = "registry+https://github.com/rust-lang/crates.io-index" 1517 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 1518 | dependencies = [ 1519 | "proc-macro2", 1520 | "quote", 1521 | "version_check", 1522 | ] 1523 | 1524 | [[package]] 1525 | name = "proc-macro2" 1526 | version = "1.0.33" 1527 | source = "registry+https://github.com/rust-lang/crates.io-index" 1528 | checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a" 1529 | dependencies = [ 1530 | "unicode-xid", 1531 | ] 1532 | 1533 | [[package]] 1534 | name = "quick-error" 1535 | version = "1.2.3" 1536 | source = "registry+https://github.com/rust-lang/crates.io-index" 1537 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 1538 | 1539 | [[package]] 1540 | name = "quote" 1541 | version = "1.0.10" 1542 | source = "registry+https://github.com/rust-lang/crates.io-index" 1543 | checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" 1544 | dependencies = [ 1545 | "proc-macro2", 1546 | ] 1547 | 1548 | [[package]] 1549 | name = "rand" 1550 | version = "0.8.4" 1551 | source = "registry+https://github.com/rust-lang/crates.io-index" 1552 | checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" 1553 | dependencies = [ 1554 | "libc", 1555 | "rand_chacha", 1556 | "rand_core", 1557 | "rand_hc", 1558 | ] 1559 | 1560 | [[package]] 1561 | name = "rand_chacha" 1562 | version = "0.3.1" 1563 | source = "registry+https://github.com/rust-lang/crates.io-index" 1564 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1565 | dependencies = [ 1566 | "ppv-lite86", 1567 | "rand_core", 1568 | ] 1569 | 1570 | [[package]] 1571 | name = "rand_core" 1572 | version = "0.6.3" 1573 | source = "registry+https://github.com/rust-lang/crates.io-index" 1574 | checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" 1575 | dependencies = [ 1576 | "getrandom 0.2.3", 1577 | ] 1578 | 1579 | [[package]] 1580 | name = "rand_hc" 1581 | version = "0.3.1" 1582 | source = "registry+https://github.com/rust-lang/crates.io-index" 1583 | checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" 1584 | dependencies = [ 1585 | "rand_core", 1586 | ] 1587 | 1588 | [[package]] 1589 | name = "redox_syscall" 1590 | version = "0.1.57" 1591 | source = "registry+https://github.com/rust-lang/crates.io-index" 1592 | checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" 1593 | 1594 | [[package]] 1595 | name = "redox_syscall" 1596 | version = "0.2.10" 1597 | source = "registry+https://github.com/rust-lang/crates.io-index" 1598 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" 1599 | dependencies = [ 1600 | "bitflags", 1601 | ] 1602 | 1603 | [[package]] 1604 | name = "redox_users" 1605 | version = "0.3.5" 1606 | source = "registry+https://github.com/rust-lang/crates.io-index" 1607 | checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" 1608 | dependencies = [ 1609 | "getrandom 0.1.16", 1610 | "redox_syscall 0.1.57", 1611 | "rust-argon2", 1612 | ] 1613 | 1614 | [[package]] 1615 | name = "regex" 1616 | version = "1.5.4" 1617 | source = "registry+https://github.com/rust-lang/crates.io-index" 1618 | checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" 1619 | dependencies = [ 1620 | "aho-corasick", 1621 | "memchr", 1622 | "regex-syntax", 1623 | ] 1624 | 1625 | [[package]] 1626 | name = "regex-automata" 1627 | version = "0.1.10" 1628 | source = "registry+https://github.com/rust-lang/crates.io-index" 1629 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 1630 | 1631 | [[package]] 1632 | name = "regex-syntax" 1633 | version = "0.6.25" 1634 | source = "registry+https://github.com/rust-lang/crates.io-index" 1635 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 1636 | 1637 | [[package]] 1638 | name = "remove_dir_all" 1639 | version = "0.5.3" 1640 | source = "registry+https://github.com/rust-lang/crates.io-index" 1641 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 1642 | dependencies = [ 1643 | "winapi", 1644 | ] 1645 | 1646 | [[package]] 1647 | name = "reqwest" 1648 | version = "0.11.7" 1649 | source = "registry+https://github.com/rust-lang/crates.io-index" 1650 | checksum = "07bea77bc708afa10e59905c3d4af7c8fd43c9214251673095ff8b14345fcbc5" 1651 | dependencies = [ 1652 | "async-compression", 1653 | "base64", 1654 | "bytes", 1655 | "encoding_rs", 1656 | "futures-core", 1657 | "futures-util", 1658 | "http", 1659 | "http-body", 1660 | "hyper", 1661 | "hyper-tls", 1662 | "ipnet", 1663 | "js-sys", 1664 | "lazy_static", 1665 | "log", 1666 | "mime", 1667 | "native-tls", 1668 | "percent-encoding", 1669 | "pin-project-lite", 1670 | "serde", 1671 | "serde_json", 1672 | "serde_urlencoded", 1673 | "tokio", 1674 | "tokio-native-tls", 1675 | "tokio-util", 1676 | "url", 1677 | "wasm-bindgen", 1678 | "wasm-bindgen-futures", 1679 | "web-sys", 1680 | "winreg", 1681 | ] 1682 | 1683 | [[package]] 1684 | name = "ring" 1685 | version = "0.16.20" 1686 | source = "registry+https://github.com/rust-lang/crates.io-index" 1687 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 1688 | dependencies = [ 1689 | "cc", 1690 | "libc", 1691 | "once_cell", 1692 | "spin", 1693 | "untrusted", 1694 | "web-sys", 1695 | "winapi", 1696 | ] 1697 | 1698 | [[package]] 1699 | name = "rnix" 1700 | version = "0.8.1" 1701 | source = "registry+https://github.com/rust-lang/crates.io-index" 1702 | checksum = "0a9b645f0edba447dbfc6473dd22999f46a1d00ab39e777a2713a1cf34a1597b" 1703 | dependencies = [ 1704 | "cbitset", 1705 | "rowan", 1706 | ] 1707 | 1708 | [[package]] 1709 | name = "rowan" 1710 | version = "0.9.1" 1711 | source = "registry+https://github.com/rust-lang/crates.io-index" 1712 | checksum = "1ea7cadf87a9d8432e85cb4eb86bd2e765ace60c24ef86e79084dcae5d1c5a19" 1713 | dependencies = [ 1714 | "rustc-hash", 1715 | "smol_str", 1716 | "text_unit", 1717 | "thin-dst", 1718 | ] 1719 | 1720 | [[package]] 1721 | name = "rust-argon2" 1722 | version = "0.8.3" 1723 | source = "registry+https://github.com/rust-lang/crates.io-index" 1724 | checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" 1725 | dependencies = [ 1726 | "base64", 1727 | "blake2b_simd", 1728 | "constant_time_eq", 1729 | "crossbeam-utils", 1730 | ] 1731 | 1732 | [[package]] 1733 | name = "rustc-demangle" 1734 | version = "0.1.21" 1735 | source = "registry+https://github.com/rust-lang/crates.io-index" 1736 | checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" 1737 | 1738 | [[package]] 1739 | name = "rustc-hash" 1740 | version = "1.1.0" 1741 | source = "registry+https://github.com/rust-lang/crates.io-index" 1742 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 1743 | 1744 | [[package]] 1745 | name = "rustc_version" 1746 | version = "0.4.0" 1747 | source = "registry+https://github.com/rust-lang/crates.io-index" 1748 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 1749 | dependencies = [ 1750 | "semver", 1751 | ] 1752 | 1753 | [[package]] 1754 | name = "rustls" 1755 | version = "0.19.1" 1756 | source = "registry+https://github.com/rust-lang/crates.io-index" 1757 | checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" 1758 | dependencies = [ 1759 | "base64", 1760 | "log", 1761 | "ring", 1762 | "sct", 1763 | "webpki", 1764 | ] 1765 | 1766 | [[package]] 1767 | name = "rustls-native-certs" 1768 | version = "0.5.0" 1769 | source = "registry+https://github.com/rust-lang/crates.io-index" 1770 | checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092" 1771 | dependencies = [ 1772 | "openssl-probe", 1773 | "rustls", 1774 | "schannel", 1775 | "security-framework", 1776 | ] 1777 | 1778 | [[package]] 1779 | name = "ryu" 1780 | version = "1.0.6" 1781 | source = "registry+https://github.com/rust-lang/crates.io-index" 1782 | checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568" 1783 | 1784 | [[package]] 1785 | name = "same-file" 1786 | version = "1.0.6" 1787 | source = "registry+https://github.com/rust-lang/crates.io-index" 1788 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 1789 | dependencies = [ 1790 | "winapi-util", 1791 | ] 1792 | 1793 | [[package]] 1794 | name = "schannel" 1795 | version = "0.1.19" 1796 | source = "registry+https://github.com/rust-lang/crates.io-index" 1797 | checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" 1798 | dependencies = [ 1799 | "lazy_static", 1800 | "winapi", 1801 | ] 1802 | 1803 | [[package]] 1804 | name = "scopeguard" 1805 | version = "1.1.0" 1806 | source = "registry+https://github.com/rust-lang/crates.io-index" 1807 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1808 | 1809 | [[package]] 1810 | name = "sct" 1811 | version = "0.6.1" 1812 | source = "registry+https://github.com/rust-lang/crates.io-index" 1813 | checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" 1814 | dependencies = [ 1815 | "ring", 1816 | "untrusted", 1817 | ] 1818 | 1819 | [[package]] 1820 | name = "security-framework" 1821 | version = "2.4.2" 1822 | source = "registry+https://github.com/rust-lang/crates.io-index" 1823 | checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" 1824 | dependencies = [ 1825 | "bitflags", 1826 | "core-foundation", 1827 | "core-foundation-sys", 1828 | "libc", 1829 | "security-framework-sys", 1830 | ] 1831 | 1832 | [[package]] 1833 | name = "security-framework-sys" 1834 | version = "2.4.2" 1835 | source = "registry+https://github.com/rust-lang/crates.io-index" 1836 | checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" 1837 | dependencies = [ 1838 | "core-foundation-sys", 1839 | "libc", 1840 | ] 1841 | 1842 | [[package]] 1843 | name = "semver" 1844 | version = "1.0.4" 1845 | source = "registry+https://github.com/rust-lang/crates.io-index" 1846 | checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" 1847 | 1848 | [[package]] 1849 | name = "serde" 1850 | version = "1.0.131" 1851 | source = "registry+https://github.com/rust-lang/crates.io-index" 1852 | checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" 1853 | dependencies = [ 1854 | "serde_derive", 1855 | ] 1856 | 1857 | [[package]] 1858 | name = "serde_derive" 1859 | version = "1.0.131" 1860 | source = "registry+https://github.com/rust-lang/crates.io-index" 1861 | checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2" 1862 | dependencies = [ 1863 | "proc-macro2", 1864 | "quote", 1865 | "syn", 1866 | ] 1867 | 1868 | [[package]] 1869 | name = "serde_derive_internals" 1870 | version = "0.25.0" 1871 | source = "registry+https://github.com/rust-lang/crates.io-index" 1872 | checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" 1873 | dependencies = [ 1874 | "proc-macro2", 1875 | "quote", 1876 | "syn", 1877 | ] 1878 | 1879 | [[package]] 1880 | name = "serde_json" 1881 | version = "1.0.72" 1882 | source = "registry+https://github.com/rust-lang/crates.io-index" 1883 | checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527" 1884 | dependencies = [ 1885 | "itoa", 1886 | "ryu", 1887 | "serde", 1888 | ] 1889 | 1890 | [[package]] 1891 | name = "serde_urlencoded" 1892 | version = "0.7.0" 1893 | source = "registry+https://github.com/rust-lang/crates.io-index" 1894 | checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" 1895 | dependencies = [ 1896 | "form_urlencoded", 1897 | "itoa", 1898 | "ryu", 1899 | "serde", 1900 | ] 1901 | 1902 | [[package]] 1903 | name = "signal-hook" 1904 | version = "0.3.12" 1905 | source = "registry+https://github.com/rust-lang/crates.io-index" 1906 | checksum = "c35dfd12afb7828318348b8c408383cf5071a086c1d4ab1c0f9840ec92dbb922" 1907 | dependencies = [ 1908 | "libc", 1909 | "signal-hook-registry", 1910 | ] 1911 | 1912 | [[package]] 1913 | name = "signal-hook-registry" 1914 | version = "1.4.0" 1915 | source = "registry+https://github.com/rust-lang/crates.io-index" 1916 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 1917 | dependencies = [ 1918 | "libc", 1919 | ] 1920 | 1921 | [[package]] 1922 | name = "slab" 1923 | version = "0.4.5" 1924 | source = "registry+https://github.com/rust-lang/crates.io-index" 1925 | checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" 1926 | 1927 | [[package]] 1928 | name = "smallvec" 1929 | version = "1.7.0" 1930 | source = "registry+https://github.com/rust-lang/crates.io-index" 1931 | checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" 1932 | 1933 | [[package]] 1934 | name = "smol_str" 1935 | version = "0.1.16" 1936 | source = "registry+https://github.com/rust-lang/crates.io-index" 1937 | checksum = "2f7909a1d8bc166a862124d84fdc11bda0ea4ed3157ccca662296919c2972db1" 1938 | 1939 | [[package]] 1940 | name = "socket2" 1941 | version = "0.4.2" 1942 | source = "registry+https://github.com/rust-lang/crates.io-index" 1943 | checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" 1944 | dependencies = [ 1945 | "libc", 1946 | "winapi", 1947 | ] 1948 | 1949 | [[package]] 1950 | name = "spin" 1951 | version = "0.5.2" 1952 | source = "registry+https://github.com/rust-lang/crates.io-index" 1953 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 1954 | 1955 | [[package]] 1956 | name = "strsim" 1957 | version = "0.10.0" 1958 | source = "registry+https://github.com/rust-lang/crates.io-index" 1959 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 1960 | 1961 | [[package]] 1962 | name = "syn" 1963 | version = "1.0.82" 1964 | source = "registry+https://github.com/rust-lang/crates.io-index" 1965 | checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" 1966 | dependencies = [ 1967 | "proc-macro2", 1968 | "quote", 1969 | "unicode-xid", 1970 | ] 1971 | 1972 | [[package]] 1973 | name = "tempfile" 1974 | version = "3.2.0" 1975 | source = "registry+https://github.com/rust-lang/crates.io-index" 1976 | checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" 1977 | dependencies = [ 1978 | "cfg-if", 1979 | "libc", 1980 | "rand", 1981 | "redox_syscall 0.2.10", 1982 | "remove_dir_all", 1983 | "winapi", 1984 | ] 1985 | 1986 | [[package]] 1987 | name = "term" 1988 | version = "0.5.2" 1989 | source = "registry+https://github.com/rust-lang/crates.io-index" 1990 | checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" 1991 | dependencies = [ 1992 | "byteorder", 1993 | "dirs", 1994 | "winapi", 1995 | ] 1996 | 1997 | [[package]] 1998 | name = "termcolor" 1999 | version = "1.1.2" 2000 | source = "registry+https://github.com/rust-lang/crates.io-index" 2001 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 2002 | dependencies = [ 2003 | "winapi-util", 2004 | ] 2005 | 2006 | [[package]] 2007 | name = "terminal_size" 2008 | version = "0.1.17" 2009 | source = "registry+https://github.com/rust-lang/crates.io-index" 2010 | checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" 2011 | dependencies = [ 2012 | "libc", 2013 | "winapi", 2014 | ] 2015 | 2016 | [[package]] 2017 | name = "text_unit" 2018 | version = "0.1.10" 2019 | source = "registry+https://github.com/rust-lang/crates.io-index" 2020 | checksum = "20431e104bfecc1a40872578dbc390e10290a0e9c35fffe3ce6f73c15a9dbfc2" 2021 | 2022 | [[package]] 2023 | name = "textwrap" 2024 | version = "0.14.2" 2025 | source = "registry+https://github.com/rust-lang/crates.io-index" 2026 | checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" 2027 | dependencies = [ 2028 | "terminal_size", 2029 | ] 2030 | 2031 | [[package]] 2032 | name = "thin-dst" 2033 | version = "1.1.0" 2034 | source = "registry+https://github.com/rust-lang/crates.io-index" 2035 | checksum = "db3c46be180f1af9673ebb27bc1235396f61ef6965b3fe0dbb2e624deb604f0e" 2036 | 2037 | [[package]] 2038 | name = "thiserror" 2039 | version = "1.0.30" 2040 | source = "registry+https://github.com/rust-lang/crates.io-index" 2041 | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" 2042 | dependencies = [ 2043 | "thiserror-impl", 2044 | ] 2045 | 2046 | [[package]] 2047 | name = "thiserror-impl" 2048 | version = "1.0.30" 2049 | source = "registry+https://github.com/rust-lang/crates.io-index" 2050 | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" 2051 | dependencies = [ 2052 | "proc-macro2", 2053 | "quote", 2054 | "syn", 2055 | ] 2056 | 2057 | [[package]] 2058 | name = "time" 2059 | version = "0.1.43" 2060 | source = "registry+https://github.com/rust-lang/crates.io-index" 2061 | checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" 2062 | dependencies = [ 2063 | "libc", 2064 | "winapi", 2065 | ] 2066 | 2067 | [[package]] 2068 | name = "time" 2069 | version = "0.3.5" 2070 | source = "registry+https://github.com/rust-lang/crates.io-index" 2071 | checksum = "41effe7cfa8af36f439fac33861b66b049edc6f9a32331e2312660529c1c24ad" 2072 | dependencies = [ 2073 | "libc", 2074 | ] 2075 | 2076 | [[package]] 2077 | name = "tinyvec" 2078 | version = "1.5.1" 2079 | source = "registry+https://github.com/rust-lang/crates.io-index" 2080 | checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" 2081 | dependencies = [ 2082 | "tinyvec_macros", 2083 | ] 2084 | 2085 | [[package]] 2086 | name = "tinyvec_macros" 2087 | version = "0.1.0" 2088 | source = "registry+https://github.com/rust-lang/crates.io-index" 2089 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 2090 | 2091 | [[package]] 2092 | name = "tokio" 2093 | version = "1.14.0" 2094 | source = "registry+https://github.com/rust-lang/crates.io-index" 2095 | checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144" 2096 | dependencies = [ 2097 | "autocfg", 2098 | "bytes", 2099 | "libc", 2100 | "memchr", 2101 | "mio", 2102 | "num_cpus", 2103 | "once_cell", 2104 | "parking_lot", 2105 | "pin-project-lite", 2106 | "signal-hook-registry", 2107 | "tokio-macros", 2108 | "winapi", 2109 | ] 2110 | 2111 | [[package]] 2112 | name = "tokio-macros" 2113 | version = "1.6.0" 2114 | source = "registry+https://github.com/rust-lang/crates.io-index" 2115 | checksum = "c9efc1aba077437943f7515666aa2b882dfabfbfdf89c819ea75a8d6e9eaba5e" 2116 | dependencies = [ 2117 | "proc-macro2", 2118 | "quote", 2119 | "syn", 2120 | ] 2121 | 2122 | [[package]] 2123 | name = "tokio-native-tls" 2124 | version = "0.3.0" 2125 | source = "registry+https://github.com/rust-lang/crates.io-index" 2126 | checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" 2127 | dependencies = [ 2128 | "native-tls", 2129 | "tokio", 2130 | ] 2131 | 2132 | [[package]] 2133 | name = "tokio-rustls" 2134 | version = "0.22.0" 2135 | source = "registry+https://github.com/rust-lang/crates.io-index" 2136 | checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" 2137 | dependencies = [ 2138 | "rustls", 2139 | "tokio", 2140 | "webpki", 2141 | ] 2142 | 2143 | [[package]] 2144 | name = "tokio-util" 2145 | version = "0.6.9" 2146 | source = "registry+https://github.com/rust-lang/crates.io-index" 2147 | checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" 2148 | dependencies = [ 2149 | "bytes", 2150 | "futures-core", 2151 | "futures-sink", 2152 | "log", 2153 | "pin-project-lite", 2154 | "tokio", 2155 | ] 2156 | 2157 | [[package]] 2158 | name = "toml" 2159 | version = "0.5.8" 2160 | source = "registry+https://github.com/rust-lang/crates.io-index" 2161 | checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" 2162 | dependencies = [ 2163 | "serde", 2164 | ] 2165 | 2166 | [[package]] 2167 | name = "tower" 2168 | version = "0.4.11" 2169 | source = "registry+https://github.com/rust-lang/crates.io-index" 2170 | checksum = "5651b5f6860a99bd1adb59dbfe1db8beb433e73709d9032b413a77e2fb7c066a" 2171 | dependencies = [ 2172 | "futures-core", 2173 | "futures-util", 2174 | "pin-project", 2175 | "pin-project-lite", 2176 | "tokio", 2177 | "tower-layer", 2178 | "tower-service", 2179 | "tracing", 2180 | ] 2181 | 2182 | [[package]] 2183 | name = "tower-layer" 2184 | version = "0.3.1" 2185 | source = "registry+https://github.com/rust-lang/crates.io-index" 2186 | checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" 2187 | 2188 | [[package]] 2189 | name = "tower-service" 2190 | version = "0.3.1" 2191 | source = "registry+https://github.com/rust-lang/crates.io-index" 2192 | checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" 2193 | 2194 | [[package]] 2195 | name = "tracing" 2196 | version = "0.1.29" 2197 | source = "registry+https://github.com/rust-lang/crates.io-index" 2198 | checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" 2199 | dependencies = [ 2200 | "cfg-if", 2201 | "log", 2202 | "pin-project-lite", 2203 | "tracing-attributes", 2204 | "tracing-core", 2205 | ] 2206 | 2207 | [[package]] 2208 | name = "tracing-attributes" 2209 | version = "0.1.18" 2210 | source = "registry+https://github.com/rust-lang/crates.io-index" 2211 | checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" 2212 | dependencies = [ 2213 | "proc-macro2", 2214 | "quote", 2215 | "syn", 2216 | ] 2217 | 2218 | [[package]] 2219 | name = "tracing-core" 2220 | version = "0.1.21" 2221 | source = "registry+https://github.com/rust-lang/crates.io-index" 2222 | checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" 2223 | dependencies = [ 2224 | "lazy_static", 2225 | ] 2226 | 2227 | [[package]] 2228 | name = "try-lock" 2229 | version = "0.2.3" 2230 | source = "registry+https://github.com/rust-lang/crates.io-index" 2231 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 2232 | 2233 | [[package]] 2234 | name = "unicode-bidi" 2235 | version = "0.3.7" 2236 | source = "registry+https://github.com/rust-lang/crates.io-index" 2237 | checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" 2238 | 2239 | [[package]] 2240 | name = "unicode-normalization" 2241 | version = "0.1.19" 2242 | source = "registry+https://github.com/rust-lang/crates.io-index" 2243 | checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" 2244 | dependencies = [ 2245 | "tinyvec", 2246 | ] 2247 | 2248 | [[package]] 2249 | name = "unicode-segmentation" 2250 | version = "1.8.0" 2251 | source = "registry+https://github.com/rust-lang/crates.io-index" 2252 | checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" 2253 | 2254 | [[package]] 2255 | name = "unicode-width" 2256 | version = "0.1.9" 2257 | source = "registry+https://github.com/rust-lang/crates.io-index" 2258 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" 2259 | 2260 | [[package]] 2261 | name = "unicode-xid" 2262 | version = "0.2.2" 2263 | source = "registry+https://github.com/rust-lang/crates.io-index" 2264 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 2265 | 2266 | [[package]] 2267 | name = "untrusted" 2268 | version = "0.7.1" 2269 | source = "registry+https://github.com/rust-lang/crates.io-index" 2270 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 2271 | 2272 | [[package]] 2273 | name = "url" 2274 | version = "2.2.2" 2275 | source = "registry+https://github.com/rust-lang/crates.io-index" 2276 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 2277 | dependencies = [ 2278 | "form_urlencoded", 2279 | "idna", 2280 | "matches", 2281 | "percent-encoding", 2282 | ] 2283 | 2284 | [[package]] 2285 | name = "urlencoding" 2286 | version = "1.3.3" 2287 | source = "registry+https://github.com/rust-lang/crates.io-index" 2288 | checksum = "5a1f0175e03a0973cf4afd476bef05c26e228520400eb1fd473ad417b1c00ffb" 2289 | 2290 | [[package]] 2291 | name = "uuid" 2292 | version = "0.8.2" 2293 | source = "registry+https://github.com/rust-lang/crates.io-index" 2294 | checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" 2295 | dependencies = [ 2296 | "serde", 2297 | ] 2298 | 2299 | [[package]] 2300 | name = "vcpkg" 2301 | version = "0.2.15" 2302 | source = "registry+https://github.com/rust-lang/crates.io-index" 2303 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 2304 | 2305 | [[package]] 2306 | name = "version_check" 2307 | version = "0.9.3" 2308 | source = "registry+https://github.com/rust-lang/crates.io-index" 2309 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 2310 | 2311 | [[package]] 2312 | name = "walkdir" 2313 | version = "2.3.2" 2314 | source = "registry+https://github.com/rust-lang/crates.io-index" 2315 | checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" 2316 | dependencies = [ 2317 | "same-file", 2318 | "winapi", 2319 | "winapi-util", 2320 | ] 2321 | 2322 | [[package]] 2323 | name = "want" 2324 | version = "0.3.0" 2325 | source = "registry+https://github.com/rust-lang/crates.io-index" 2326 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 2327 | dependencies = [ 2328 | "log", 2329 | "try-lock", 2330 | ] 2331 | 2332 | [[package]] 2333 | name = "wasi" 2334 | version = "0.9.0+wasi-snapshot-preview1" 2335 | source = "registry+https://github.com/rust-lang/crates.io-index" 2336 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 2337 | 2338 | [[package]] 2339 | name = "wasi" 2340 | version = "0.10.2+wasi-snapshot-preview1" 2341 | source = "registry+https://github.com/rust-lang/crates.io-index" 2342 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 2343 | 2344 | [[package]] 2345 | name = "wasm-bindgen" 2346 | version = "0.2.78" 2347 | source = "registry+https://github.com/rust-lang/crates.io-index" 2348 | checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" 2349 | dependencies = [ 2350 | "cfg-if", 2351 | "wasm-bindgen-macro", 2352 | ] 2353 | 2354 | [[package]] 2355 | name = "wasm-bindgen-backend" 2356 | version = "0.2.78" 2357 | source = "registry+https://github.com/rust-lang/crates.io-index" 2358 | checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" 2359 | dependencies = [ 2360 | "bumpalo", 2361 | "lazy_static", 2362 | "log", 2363 | "proc-macro2", 2364 | "quote", 2365 | "syn", 2366 | "wasm-bindgen-shared", 2367 | ] 2368 | 2369 | [[package]] 2370 | name = "wasm-bindgen-futures" 2371 | version = "0.4.28" 2372 | source = "registry+https://github.com/rust-lang/crates.io-index" 2373 | checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" 2374 | dependencies = [ 2375 | "cfg-if", 2376 | "js-sys", 2377 | "wasm-bindgen", 2378 | "web-sys", 2379 | ] 2380 | 2381 | [[package]] 2382 | name = "wasm-bindgen-macro" 2383 | version = "0.2.78" 2384 | source = "registry+https://github.com/rust-lang/crates.io-index" 2385 | checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" 2386 | dependencies = [ 2387 | "quote", 2388 | "wasm-bindgen-macro-support", 2389 | ] 2390 | 2391 | [[package]] 2392 | name = "wasm-bindgen-macro-support" 2393 | version = "0.2.78" 2394 | source = "registry+https://github.com/rust-lang/crates.io-index" 2395 | checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" 2396 | dependencies = [ 2397 | "proc-macro2", 2398 | "quote", 2399 | "syn", 2400 | "wasm-bindgen-backend", 2401 | "wasm-bindgen-shared", 2402 | ] 2403 | 2404 | [[package]] 2405 | name = "wasm-bindgen-shared" 2406 | version = "0.2.78" 2407 | source = "registry+https://github.com/rust-lang/crates.io-index" 2408 | checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" 2409 | 2410 | [[package]] 2411 | name = "web-sys" 2412 | version = "0.3.55" 2413 | source = "registry+https://github.com/rust-lang/crates.io-index" 2414 | checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" 2415 | dependencies = [ 2416 | "js-sys", 2417 | "wasm-bindgen", 2418 | ] 2419 | 2420 | [[package]] 2421 | name = "webpki" 2422 | version = "0.21.4" 2423 | source = "registry+https://github.com/rust-lang/crates.io-index" 2424 | checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" 2425 | dependencies = [ 2426 | "ring", 2427 | "untrusted", 2428 | ] 2429 | 2430 | [[package]] 2431 | name = "whoami" 2432 | version = "0.9.0" 2433 | source = "registry+https://github.com/rust-lang/crates.io-index" 2434 | checksum = "7884773ab69074615cb8f8425d0e53f11710786158704fca70f53e71b0e05504" 2435 | 2436 | [[package]] 2437 | name = "winapi" 2438 | version = "0.3.9" 2439 | source = "registry+https://github.com/rust-lang/crates.io-index" 2440 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2441 | dependencies = [ 2442 | "winapi-i686-pc-windows-gnu", 2443 | "winapi-x86_64-pc-windows-gnu", 2444 | ] 2445 | 2446 | [[package]] 2447 | name = "winapi-i686-pc-windows-gnu" 2448 | version = "0.4.0" 2449 | source = "registry+https://github.com/rust-lang/crates.io-index" 2450 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2451 | 2452 | [[package]] 2453 | name = "winapi-util" 2454 | version = "0.1.5" 2455 | source = "registry+https://github.com/rust-lang/crates.io-index" 2456 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 2457 | dependencies = [ 2458 | "winapi", 2459 | ] 2460 | 2461 | [[package]] 2462 | name = "winapi-x86_64-pc-windows-gnu" 2463 | version = "0.4.0" 2464 | source = "registry+https://github.com/rust-lang/crates.io-index" 2465 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2466 | 2467 | [[package]] 2468 | name = "winreg" 2469 | version = "0.7.0" 2470 | source = "registry+https://github.com/rust-lang/crates.io-index" 2471 | checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" 2472 | dependencies = [ 2473 | "winapi", 2474 | ] 2475 | 2476 | [[package]] 2477 | name = "xmlparser" 2478 | version = "0.13.3" 2479 | source = "registry+https://github.com/rust-lang/crates.io-index" 2480 | checksum = "114ba2b24d2167ef6d67d7d04c8cc86522b87f490025f39f0303b7db5bf5e3d8" 2481 | 2482 | [[package]] 2483 | name = "yansi" 2484 | version = "0.5.0" 2485 | source = "registry+https://github.com/rust-lang/crates.io-index" 2486 | checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71" 2487 | 2488 | [[package]] 2489 | name = "yn" 2490 | version = "0.1.1" 2491 | source = "registry+https://github.com/rust-lang/crates.io-index" 2492 | checksum = "d789b24a50ca067124e6e6ad3061c48151da174043cb09285ba934425e8739ec" 2493 | 2494 | [[package]] 2495 | name = "zeroize" 2496 | version = "1.4.3" 2497 | source = "registry+https://github.com/rust-lang/crates.io-index" 2498 | checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619" 2499 | -------------------------------------------------------------------------------- /cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bitte" 3 | version = "0.5.0-dev" 4 | authors = ["manveru ", "nrdxp "] 5 | description = "Deploy all the things!" 6 | edition = "2021" 7 | 8 | [dependencies] 9 | regex = "*" 10 | serde_json = "^1.0.0" 11 | serde = { version = "1.0", features = [ "derive", "rc" ] } 12 | prettytable-rs = "^0.8.0" 13 | tokio = "^1.0.0" 14 | log = "^0.4.0" 15 | pretty_env_logger = "^0.4.0" 16 | anyhow = "^1.0.0" 17 | deploy-rs = { git = "https://github.com/input-output-hk/deploy-rs" } 18 | uuid = { version = "^0.8.0", features = ["serde"] } 19 | reqwest = { version = "^0.11.0", features = ["json", "gzip"] } 20 | thiserror = "^1.0.0" 21 | netrc-rs = "0.1.2" 22 | enum-utils = "0.1.2" 23 | clap_generate = "^3.0.0-rc.3" 24 | aws-config = "0.2.0" 25 | aws-sdk-ec2 = "0.2.0" 26 | 27 | [dependencies.clap] 28 | version = "^3.0.0-rc.3" 29 | features = ["wrap_help", "derive", "env"] 30 | 31 | [profile.release] 32 | lto = "thin" 33 | opt-level = 3 34 | -------------------------------------------------------------------------------- /cli/package.nix: -------------------------------------------------------------------------------- 1 | { stdenv 2 | , lib 3 | , pkg-config 4 | , openssl 5 | , zlib 6 | , makeRustPlatform 7 | , fenix 8 | # darwin dependencies 9 | , darwin 10 | , toolchain 11 | }: 12 | 13 | (makeRustPlatform { inherit (fenix.${toolchain}) cargo rustc; }).buildRustPackage 14 | { 15 | 16 | inherit (with builtins; (fromTOML (readFile ./Cargo.toml)).package) 17 | name version; 18 | 19 | src = lib.cleanSource ./.; 20 | cargoLock.lockFile = ./Cargo.lock; 21 | cargoLock.outputHashes = { 22 | "deploy-rs-0.1.0" = "sha256-cDFOojpoHdRt2NFM/39GPPjqARoVuy+yVk0/BgYHwv0="; 23 | }; 24 | 25 | nativeBuildInputs = [ pkg-config ]; 26 | buildInputs = [ openssl zlib ] ++ lib.optionals stdenv.isDarwin 27 | (with darwin.apple_sdk.frameworks; [ 28 | SystemConfiguration 29 | Security 30 | CoreFoundation 31 | darwin.libiconv 32 | darwin.libresolv 33 | darwin.Libsystem 34 | ]); 35 | 36 | doCheck = false; 37 | 38 | postInstall = '' 39 | export BITTE_CLUSTER=b 40 | export BITTE_PROVIDER=aws 41 | export BITTE_DOMAIN=b.b.b 42 | 43 | mkdir -p $out/share/zsh/site-functions 44 | $out/bin/bitte comp zsh > $out/share/zsh/site-functions/_bitte 45 | 46 | mkdir -p $out/share/bash-completion/completions 47 | $out/bin/bitte comp bash > $out/share/bash-completion/completions/bitte 48 | ''; 49 | } // { 50 | meta.description = "A swiss knife for the bitte cluster"; 51 | } 52 | -------------------------------------------------------------------------------- /cli/src/cli.rs: -------------------------------------------------------------------------------- 1 | mod args; 2 | pub mod opts; 3 | pub mod subs; 4 | 5 | use crate::types::{BitteFind, ClusterHandle}; 6 | use anyhow::{anyhow, Context, Result}; 7 | use clap::{App, ArgMatches, FromArgMatches}; 8 | use clap_generate::{generate, generators}; 9 | use deploy::cli as deployCli; 10 | use deploy::cli::Opts as ExtDeployOpts; 11 | use log::*; 12 | use prettytable::{cell, format, row, Table}; 13 | use std::collections::HashMap; 14 | use std::net::IpAddr; 15 | use std::{env, io, path::Path, process::Command, process::Stdio, time::Duration}; 16 | use tokio::task::JoinHandle; 17 | 18 | pub fn init_log(level: u64) { 19 | let level = match level { 20 | 0 => "warn", 21 | 1 => "info", 22 | 2 => "debug", 23 | _ => "trace", 24 | }; 25 | env::set_var("RUST_LOG", &level); 26 | pretty_env_logger::init() 27 | } 28 | 29 | pub(crate) async fn ssh(sub: &ArgMatches, cluster: ClusterHandle) -> Result<()> { 30 | let mut args = sub.values_of_lossy("args").unwrap_or_default(); 31 | let job: Vec = sub.values_of_t("job").unwrap_or_default(); 32 | let delay = Duration::from_secs(sub.value_of_t::("delay").unwrap_or(0)); 33 | 34 | let namespace: String = sub.value_of_t("namespace").unwrap_or_default(); 35 | 36 | let ip: IpAddr; 37 | 38 | let cluster = cluster.await??; 39 | 40 | if sub.is_present("all") { 41 | let nodes = if sub.is_present("clients") { 42 | cluster.nodes.find_clients() 43 | } else { 44 | cluster.nodes 45 | }; 46 | 47 | let mut iter = nodes.iter().peekable(); 48 | 49 | while let Some(node) = iter.next() { 50 | init_ssh(node.pub_ip, args.clone(), cluster.name.clone()).await?; 51 | if sub.is_present("delay") && iter.peek().is_some() { 52 | tokio::time::sleep(delay).await; 53 | } 54 | } 55 | 56 | return Ok(()); 57 | } else if sub.is_present("parallel") { 58 | let nodes = if sub.is_present("clients") { 59 | cluster.nodes.find_clients() 60 | } else { 61 | cluster.nodes 62 | }; 63 | 64 | let mut handles: Vec>> = Vec::with_capacity(nodes.len()); 65 | 66 | for node in nodes.into_iter() { 67 | let args = args.clone(); 68 | let name = cluster.name.clone(); 69 | let handle = tokio::spawn(async move { init_ssh(node.pub_ip, args, name).await }); 70 | handles.push(handle); 71 | } 72 | 73 | for handle in handles.into_iter() { 74 | handle.await??; 75 | } 76 | 77 | return Ok(()); 78 | } else if sub.is_present("job") { 79 | let (name, group, index) = (&*job[0], &*job[1], &job[2]); 80 | 81 | let nodes = cluster.nodes; 82 | let (node, alloc) = nodes.find_with_job(name, group, index, namespace.as_ref())?; 83 | if args.is_empty() { 84 | args.extend(vec![ 85 | "-t".into(), 86 | format!("cd /var/lib/nomad/alloc/{}; bash", alloc.id), 87 | ]); 88 | } 89 | 90 | ip = node.pub_ip; 91 | } else { 92 | let needle = args.first(); 93 | 94 | if needle.is_none() { 95 | return Err(anyhow!("first arg must be a host")); 96 | } 97 | 98 | let needle = needle.unwrap().clone(); 99 | args = args.drain(1..).collect(); 100 | 101 | let nodes = cluster.nodes; 102 | let node = nodes.find_needle(&needle)?; 103 | 104 | ip = node.pub_ip; 105 | }; 106 | 107 | init_ssh(ip, args, cluster.name).await 108 | } 109 | 110 | async fn init_ssh(ip: IpAddr, args: Vec, cluster: String) -> Result<()> { 111 | let user_host = &*format!("root@{}", ip); 112 | let mut flags = vec!["-x", "-p", "22"]; 113 | 114 | let ssh_key_path = format!("secrets/ssh-{}", cluster); 115 | let ssh_key = Path::new(&ssh_key_path); 116 | if ssh_key.is_file() { 117 | flags.push("-i"); 118 | flags.push(&*ssh_key_path); 119 | } 120 | 121 | flags.append(&mut vec!["-o", "StrictHostKeyChecking=accept-new"]); 122 | 123 | flags.push(user_host); 124 | 125 | if !args.is_empty() { 126 | flags.append(&mut args.iter().map(|string| string.as_str()).collect()); 127 | } 128 | let ssh_args = flags.into_iter(); 129 | 130 | let mut cmd = Command::new("ssh"); 131 | let cmd_with_args = cmd.args(ssh_args); 132 | info!("cmd: {:?}", cmd_with_args); 133 | 134 | cmd.spawn() 135 | .with_context(|| "ssh command failed")? 136 | .wait() 137 | .with_context(|| "ssh command didn't finish?")?; 138 | Ok(()) 139 | } 140 | 141 | pub(crate) async fn deploy(sub: &ArgMatches, cluster: ClusterHandle) -> Result<()> { 142 | let opts = ::from_arg_matches(sub).unwrap_or_default(); 143 | let cluster = cluster.await??; 144 | 145 | info!("node needles: {:?}", opts.nodes); 146 | 147 | let instances = if opts.clients { 148 | cluster.nodes.find_clients() 149 | } else { 150 | cluster 151 | .nodes 152 | .find_needles(opts.nodes.iter().map(AsRef::as_ref).collect()) 153 | }; 154 | 155 | let nixos_configurations: Vec = instances 156 | .iter() 157 | .map(|i| i.nixos.clone()) 158 | .collect::>(); 159 | info!("regenerate secrets for: {:?}", nixos_configurations); 160 | 161 | for nixos_configuration in nixos_configurations { 162 | let output = Command::new("nix") 163 | .arg("run") 164 | .arg(format!( 165 | ".#nixosConfigurations.'{}'.config.secrets.generateScript", 166 | nixos_configuration 167 | )) 168 | .stderr(Stdio::piped()) 169 | .stdout(Stdio::piped()) 170 | .output()?; 171 | 172 | if !output.status.success() { 173 | error!( 174 | "Secret generation on {} failed with exit code {}", 175 | nixos_configuration, 176 | output.status.code().unwrap(), 177 | ); 178 | } 179 | } 180 | 181 | let targets: Vec = instances 182 | .iter() 183 | .map(|i| format!(".#{}@{}:22", i.nixos, i.pub_ip)) 184 | .collect(); 185 | 186 | info!("redeploy: {:?}", targets); 187 | // TODO: disable these options for the general public (target & targets) 188 | let opts = ExtDeployOpts { 189 | hostname: None, 190 | target: None, 191 | targets: Some(targets), 192 | flags: opts.flags, 193 | generic_settings: opts.generic_settings, 194 | }; 195 | // wait_for_ssh(&instance.pub_ip).await?; 196 | if let Err(err) = deployCli::run(Some(opts)).await { 197 | error!("{}", err); 198 | // NB: if your up for a mass rebuild you are expected to: 199 | // - Randomly check on a representative single node before 200 | // - Eventually use the dry-run fearure 201 | // - Watch the logs closely 202 | // - Kill the deployment manually if things appear to go out 203 | // of hand 204 | // std::process::exit(1); 205 | } 206 | Ok(()) 207 | } 208 | 209 | pub(crate) async fn info(sub: &ArgMatches, cluster: ClusterHandle) -> Result<()> { 210 | let json: bool = sub.is_present("json"); 211 | info_print(cluster, json).await?; 212 | Ok(()) 213 | } 214 | 215 | async fn info_print(cluster: ClusterHandle, json: bool) -> Result<()> { 216 | let cluster = cluster.await??; 217 | if json { 218 | let stdout = io::stdout(); 219 | let handle = stdout.lock(); 220 | env::set_var("BITTE_INFO_NO_ALLOCS", ""); 221 | serde_json::to_writer_pretty(handle, &cluster)?; 222 | } else { 223 | let mut core_nodes_table = Table::new(); 224 | core_nodes_table.set_format(*format::consts::FORMAT_BOX_CHARS); 225 | core_nodes_table 226 | .add_row(row![ bc => format!("{} Core Instance", cluster.provider), "Private IP", "Public IP", "Zone"]); 227 | 228 | let mut client_nodes_table_map: HashMap = HashMap::new(); 229 | 230 | let mut nodes = cluster.nodes; 231 | nodes.sort(); 232 | 233 | for node in nodes.into_iter() { 234 | match node.asg { 235 | Some(asg) => { 236 | let name: String = asg.to_string(); 237 | // TODO extract true client group 238 | let group: String = { 239 | let suffix = name.split('-').last().unwrap_or_default().to_owned(); 240 | let i_type = node 241 | .node_type 242 | .clone() 243 | .unwrap_or_default() 244 | .split('.') 245 | .last() 246 | .unwrap_or_default() 247 | .to_owned(); 248 | if suffix == i_type { 249 | "".to_string() 250 | } else { 251 | format!(" ({})", suffix) 252 | } 253 | }; 254 | 255 | let client_nodes_table = 256 | client_nodes_table_map.entry(group.clone()).or_insert({ 257 | let mut client_nodes_table = Table::new(); 258 | client_nodes_table.set_format(*format::consts::FORMAT_BOX_CHARS); 259 | client_nodes_table.add_row(row![ bc => 260 | format!("{} Instance ID{}", cluster.provider, group), 261 | "Private IP", 262 | "Public IP", 263 | "Zone", 264 | ]); 265 | client_nodes_table 266 | }); 267 | client_nodes_table.add_row(row![ 268 | node.id, 269 | node.priv_ip, 270 | node.pub_ip, 271 | node.zone.unwrap_or_default(), 272 | ]); 273 | } 274 | None => { 275 | core_nodes_table.add_row(row![ 276 | node.name, 277 | node.priv_ip, 278 | node.pub_ip, 279 | node.zone.unwrap_or_default(), 280 | ]); 281 | } 282 | } 283 | } 284 | core_nodes_table.printstd(); 285 | for val in client_nodes_table_map.values() { 286 | val.printstd(); 287 | } 288 | } 289 | 290 | Ok(()) 291 | } 292 | 293 | pub(crate) async fn completions(sub: &ArgMatches, mut app: App<'_>) -> Result<()> { 294 | match sub.subcommand() { 295 | Some(("bash", _)) => generate(generators::Bash, &mut app, "bitte", &mut std::io::stdout()), 296 | Some(("zsh", _)) => generate(generators::Zsh, &mut app, "bitte", &mut std::io::stdout()), 297 | Some(("fish", _)) => generate(generators::Fish, &mut app, "bitte", &mut std::io::stdout()), 298 | _ => (), 299 | }; 300 | Ok(()) 301 | } 302 | -------------------------------------------------------------------------------- /cli/src/cli/args.rs: -------------------------------------------------------------------------------- 1 | use crate::types::BitteProvider; 2 | use clap::Parser; 3 | 4 | #[derive(Parser)] 5 | struct Provider { 6 | #[clap(arg_enum)] 7 | name: BitteProvider, 8 | } 9 | -------------------------------------------------------------------------------- /cli/src/cli/opts.rs: -------------------------------------------------------------------------------- 1 | use super::subs::SubCommands; 2 | use crate::types::BitteProvider; 3 | use clap::Parser; 4 | 5 | #[derive(Parser)] 6 | #[clap(author, version, about)] 7 | pub struct Bitte { 8 | #[clap(arg_enum, long, env = "BITTE_PROVIDER", ignore_case = true)] 9 | /// The cluster infrastructure provider 10 | provider: BitteProvider, 11 | #[clap(long, env = "BITTE_DOMAIN", value_name = "NAME")] 12 | /// The public domain of the cluster 13 | domain: String, 14 | #[clap(long = "cluster", env = "BITTE_CLUSTER", value_name = "TITLE")] 15 | /// The unique name of the cluster 16 | name: String, 17 | #[clap( 18 | long, 19 | env = "AWS_DEFAULT_REGION", 20 | value_name = "REGION", 21 | required_if_eq("provider", "AWS") 22 | )] 23 | /// The default AWS region 24 | aws_region: Option, 25 | #[clap( 26 | long, 27 | env = "AWS_ASG_REGIONS", 28 | value_name = "REGIONS", 29 | required_if_eq("provider", "AWS"), 30 | value_delimiter(':'), 31 | require_delimiter = true 32 | )] 33 | /// Regions containing Nomad clients 34 | aws_asg_regions: Option>, 35 | #[clap(short, long, parse(from_occurrences), global = true, env = "RUST_LOG")] 36 | /// set log level: 'unset' is 'warn', '-v' is 'info', '-vv' is 'debug', ... 37 | verbose: i32, 38 | #[clap(subcommand)] 39 | commands: SubCommands, 40 | } 41 | -------------------------------------------------------------------------------- /cli/src/cli/subs.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{Context, Result}; 2 | use clap::{AppSettings, ArgSettings, Parser}; 3 | use deploy::data as deployData; 4 | use deploy::settings as deploySettings; 5 | use uuid::Uuid; 6 | 7 | #[derive(Parser)] 8 | pub enum SubCommands { 9 | Info(Info), 10 | Ssh(Ssh), 11 | Deploy(Deploy), 12 | #[clap(setting = AppSettings::Hidden)] 13 | Completions(Completions), 14 | } 15 | 16 | #[derive(Parser)] 17 | /// Show information about instances and auto-scaling groups 18 | pub struct Info { 19 | #[clap(short, long)] 20 | /// output as JSON 21 | json: bool, 22 | } 23 | 24 | #[derive(Parser, Default)] 25 | /// Deploy core and client nodes 26 | pub struct Deploy { 27 | #[clap(long, short = 'l')] 28 | /// (re-)deploy all client nodes 29 | pub clients: bool, 30 | #[clap(flatten)] 31 | pub flags: deployData::Flags, 32 | 33 | #[clap(flatten)] 34 | pub generic_settings: deploySettings::GenericSettings, 35 | /// nodes to deploy; takes one or more needles to match against: 36 | /// private & public ip, node name and aws client id 37 | pub nodes: Vec, 38 | } 39 | 40 | #[derive(Parser)] 41 | /// SSH to instances 42 | pub struct Ssh { 43 | #[clap( 44 | short, 45 | long, 46 | requires_all = &["nomad", "namespace"], 47 | number_of_values = 3, 48 | value_names = &["JOB", "GROUP", "INDEX"], 49 | )] 50 | /// specify client by: job, group, alloc_index; 51 | /// this will also 'cd' to the alloc dir if is empty 52 | job: Option, 53 | #[clap( 54 | long, 55 | value_name = "TOKEN", 56 | env = "NOMAD_TOKEN", 57 | parse(try_from_str = token_context), 58 | setting = ArgSettings::HideEnvValues 59 | )] 60 | /// for '-j': The Nomad token used to query node information 61 | nomad: Option, 62 | #[clap( 63 | long, 64 | short, 65 | group = "multi", 66 | conflicts_with = "job", 67 | requires = "args" 68 | )] 69 | /// run on all nodes 70 | all: bool, 71 | #[clap( 72 | long, 73 | short, 74 | group = "multi", 75 | conflicts_with_all = &["all", "job"], 76 | requires = "args" 77 | )] 78 | /// run on nodes in parallel 79 | parallel: bool, 80 | #[clap(long, short, env = "NOMAD_NAMESPACE")] 81 | /// for '-j': specify nomad namespace to search for 82 | namespace: Option, 83 | #[clap(long, short = 'l', requires = "multi")] 84 | /// for '-a' or '-p': execute commands only on Nomad clients 85 | clients: bool, 86 | #[clap(long, short, requires = "all")] 87 | /// for '-a': seconds to delay between commands 88 | delay: Option, 89 | #[clap(multiple_values = true)] 90 | /// arguments to ssh 91 | args: Option, 92 | } 93 | 94 | #[derive(Parser)] 95 | #[clap(alias = "comp")] 96 | /// Generate CLI completions 97 | pub struct Completions { 98 | #[clap(subcommand)] 99 | shells: Shells, 100 | } 101 | 102 | #[derive(Parser)] 103 | pub enum Shells { 104 | Bash, 105 | Zsh, 106 | Fish, 107 | } 108 | 109 | fn token_context(string: &str) -> Result { 110 | Uuid::parse_str(string).with_context(|| format!("'{}' is not a valid UUID", string)) 111 | } 112 | -------------------------------------------------------------------------------- /cli/src/main.rs: -------------------------------------------------------------------------------- 1 | mod cli; 2 | mod types; 3 | mod utils; 4 | 5 | use anyhow::Result; 6 | use clap::{App, IntoApp}; 7 | use cli::opts::Bitte; 8 | use types::BitteCluster; 9 | use uuid::Uuid; 10 | 11 | #[tokio::main] 12 | async fn main() -> Result<()> { 13 | let _toml = include_str!("../Cargo.toml"); 14 | 15 | let app: App = ::into_app(); 16 | 17 | let matches = app.clone().get_matches(); 18 | 19 | let run = |init_log: bool, token| { 20 | if init_log { 21 | cli::init_log(matches.occurrences_of("verbose")) 22 | }; 23 | BitteCluster::init(matches.clone(), token) 24 | }; 25 | 26 | match matches.subcommand() { 27 | Some(("deploy", sub)) => cli::deploy(sub, run(false, None)).await?, 28 | Some(("info", sub)) => cli::info(sub, run(true, None)).await?, 29 | Some(("ssh", sub)) => { 30 | let token: Option = if sub.is_present("job") { 31 | sub.value_of_t("nomad").ok() 32 | } else { 33 | None 34 | }; 35 | cli::ssh(sub, run(true, token)).await? 36 | } 37 | Some(("completions", sub)) => cli::completions(sub, app).await?, 38 | _ => (), 39 | } 40 | Ok(()) 41 | } 42 | -------------------------------------------------------------------------------- /cli/src/types.rs: -------------------------------------------------------------------------------- 1 | pub mod error; 2 | 3 | use aws_sdk_ec2::{ 4 | model::{Filter, Instance, Tag}, 5 | Client as Ec2Client, Region, 6 | }; 7 | use clap::{ArgEnum, ArgMatches}; 8 | use serde::{de::Deserializer, Deserialize, Serialize}; 9 | use std::cmp::Ordering; 10 | use std::collections::hash_set::HashSet; 11 | use std::env; 12 | use std::fmt::{Display, Formatter}; 13 | use std::str::FromStr; 14 | use std::sync::Arc; 15 | use std::time::{Duration, SystemTime}; 16 | 17 | use anyhow::{Context, Result}; 18 | use enum_utils::FromStr; 19 | use std::net::{IpAddr, Ipv4Addr}; 20 | use uuid::Uuid; 21 | 22 | use tokio::task::JoinHandle; 23 | 24 | use reqwest::{ 25 | header::{HeaderMap, HeaderValue}, 26 | Client, 27 | }; 28 | 29 | use error::Error; 30 | 31 | use regex::Regex; 32 | 33 | #[derive(Serialize, Deserialize)] 34 | pub struct VaultLogin { 35 | pub request_id: String, 36 | pub lease_id: String, 37 | pub renewable: bool, 38 | pub lease_duration: i64, 39 | pub auth: Auth, 40 | } 41 | 42 | #[derive(Serialize, Deserialize)] 43 | pub struct Auth { 44 | pub client_token: String, 45 | pub accessor: String, 46 | pub policies: Vec, 47 | pub token_policies: Vec, 48 | pub metadata: Metadata, 49 | pub lease_duration: i64, 50 | pub renewable: bool, 51 | pub entity_id: String, 52 | pub token_type: String, 53 | pub orphan: bool, 54 | } 55 | 56 | #[derive(Serialize, Deserialize)] 57 | pub struct Metadata { 58 | pub org: String, 59 | pub username: String, 60 | } 61 | 62 | /// A description of a Bitte cluster and its nodes 63 | #[derive(Debug, Serialize, Deserialize)] 64 | pub struct BitteCluster { 65 | pub name: String, 66 | pub nodes: BitteNodes, 67 | pub domain: String, 68 | pub provider: BitteProvider, 69 | #[serde(skip)] 70 | pub nomad_api_client: Option>, 71 | pub ttl: SystemTime, 72 | } 73 | 74 | #[derive(Debug, Serialize, Deserialize, Copy, Clone, FromStr, ArgEnum)] 75 | #[enumeration(case_insensitive)] 76 | #[allow(clippy::upper_case_acronyms)] 77 | pub enum BitteProvider { 78 | AWS, 79 | } 80 | 81 | impl Display for BitteProvider { 82 | fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { 83 | let provider = match *self { 84 | BitteProvider::AWS => "AWS", 85 | }; 86 | write!(f, "{}", provider) 87 | } 88 | } 89 | 90 | #[derive(Debug, Serialize, Deserialize, Clone, Default)] 91 | pub struct NomadClient { 92 | #[serde(rename = "ID")] 93 | pub id: Uuid, 94 | pub allocs: Option, 95 | #[serde(rename = "Address")] 96 | pub address: Option, 97 | } 98 | 99 | impl NomadClient { 100 | async fn find_nomad_nodes(client: Arc, domain: String) -> Result { 101 | let url = format!("https://nomad.{}/v1/nodes", domain); 102 | let nodes = client 103 | .get(&url) 104 | .send() 105 | .await 106 | .with_context(|| format!("failed to query: {}", &url))? 107 | .json::() 108 | .await 109 | .with_context(|| format!("failed to decode response from: {}", &url))?; 110 | Ok(nodes) 111 | } 112 | } 113 | 114 | #[derive(Debug, Serialize, Deserialize)] 115 | pub struct BitteNode { 116 | pub id: String, 117 | pub name: String, 118 | pub priv_ip: IpAddr, 119 | pub pub_ip: IpAddr, 120 | pub nixos: String, 121 | #[serde(skip_serializing_if = "skip_info")] 122 | pub nomad_client: Option, 123 | #[serde(skip_serializing_if = "Option::is_none")] 124 | pub node_type: Option, 125 | #[serde(skip_serializing_if = "Option::is_none")] 126 | pub zone: Option, 127 | #[serde(skip_serializing_if = "Option::is_none")] 128 | pub asg: Option, 129 | } 130 | 131 | fn skip_info(_: &Option) -> bool { 132 | env::var("BITTE_INFO_NO_ALLOCS").is_ok() 133 | } 134 | 135 | pub trait BitteFind 136 | where 137 | Self: IntoIterator, 138 | { 139 | fn find_needle(self, needle: &str) -> Result; 140 | fn find_needles(self, needles: Vec<&str>) -> Self; 141 | fn find_clients(self) -> Self; 142 | fn find_with_job( 143 | self, 144 | name: &str, 145 | group: &str, 146 | index: &str, 147 | namespace: &str, 148 | ) -> Result<(Self::Item, NomadAlloc)>; 149 | } 150 | 151 | impl Ord for BitteNode { 152 | fn cmp(&self, other: &Self) -> Ordering { 153 | self.name.cmp(&other.name) 154 | } 155 | } 156 | 157 | impl PartialOrd for BitteNode { 158 | fn partial_cmp(&self, other: &Self) -> Option { 159 | Some(self.cmp(other)) 160 | } 161 | } 162 | 163 | impl PartialEq for BitteNode { 164 | fn eq(&self, other: &Self) -> bool { 165 | self.name == other.name 166 | } 167 | } 168 | 169 | impl Eq for BitteNode {} 170 | 171 | impl BitteFind for BitteNodes { 172 | fn find_with_job( 173 | self, 174 | name: &str, 175 | group: &str, 176 | index: &str, 177 | namespace: &str, 178 | ) -> Result<(Self::Item, NomadAlloc)> { 179 | let node = self 180 | .into_iter() 181 | .find(|node| { 182 | let client = &node.nomad_client; 183 | if client.is_none() { 184 | return false; 185 | }; 186 | 187 | let allocs = &client.as_ref().unwrap().allocs; 188 | if allocs.is_none() || allocs.as_ref().unwrap().is_empty() { 189 | return false; 190 | }; 191 | 192 | allocs.as_ref().unwrap().iter().any(|alloc| { 193 | alloc.namespace == namespace 194 | && alloc.job_id == name 195 | && alloc.task_group == group 196 | && alloc.index.get() == index.parse().ok() 197 | && alloc.status == "running" 198 | }) 199 | }) 200 | .with_context(|| { 201 | format!( 202 | "{}, {}, {} does not match any running nomad allocations in namespace {}", 203 | name, group, index, namespace 204 | ) 205 | })?; 206 | let alloc = node 207 | .nomad_client 208 | .as_ref() 209 | .unwrap() 210 | .allocs 211 | .as_ref() 212 | .unwrap() 213 | .iter() 214 | .find(|alloc| { 215 | alloc.namespace == namespace 216 | && alloc.job_id == name 217 | && alloc.task_group == group 218 | && alloc.index.get() == index.parse().ok() 219 | && alloc.status == "running" 220 | }) 221 | .unwrap() 222 | .clone(); 223 | Ok((node, alloc)) 224 | } 225 | 226 | fn find_needle(self, needle: &str) -> Result { 227 | self.into_iter() 228 | .find(|node| { 229 | let ip = needle.parse::().ok(); 230 | 231 | node.id == needle 232 | || node.name == needle 233 | || node 234 | .nomad_client 235 | .as_ref() 236 | .unwrap_or(&Default::default()) 237 | .id 238 | .to_hyphenated() 239 | .to_string() 240 | == needle 241 | || Some(node.priv_ip) == ip 242 | || Some(node.pub_ip) == ip 243 | }) 244 | .with_context(|| format!("{} does not match any nodes", needle)) 245 | } 246 | 247 | fn find_clients(self) -> Self { 248 | self.into_iter().filter(|node| node.asg.is_some()).collect() 249 | } 250 | 251 | fn find_needles(self, needles: Vec<&str>) -> Self { 252 | self.into_iter() 253 | .filter(|node| { 254 | let ips: Vec> = needles 255 | .iter() 256 | .map(|needle| needle.parse::().ok()) 257 | .collect(); 258 | 259 | needles.contains(&&*node.id) 260 | || needles.contains(&&*node.name) 261 | || needles.contains( 262 | &&*node 263 | .nomad_client 264 | .as_ref() 265 | .unwrap_or(&Default::default()) 266 | .id 267 | .to_hyphenated() 268 | .to_string(), 269 | ) 270 | || ips.contains(&Some(node.priv_ip)) 271 | || ips.contains(&Some(node.pub_ip)) 272 | }) 273 | .collect() 274 | } 275 | } 276 | 277 | impl From for BitteNode { 278 | fn from(instance: Instance) -> Self { 279 | let tags = instance.tags.unwrap_or_default(); 280 | let empty_tag = Tag::builder().build(); 281 | 282 | let nixos = tags 283 | .iter() 284 | .find(|tag| tag.key == Some("UID".into())) 285 | .unwrap_or(&empty_tag) 286 | .value 287 | .as_ref(); 288 | 289 | let name = tags 290 | .iter() 291 | .find(|tag| tag.key == Some("Name".into())) 292 | .unwrap_or(&empty_tag) 293 | .value 294 | .as_ref(); 295 | 296 | let asg = tags 297 | .iter() 298 | .find(|tag| tag.key == Some("aws:autoscaling:groupName".into())) 299 | .unwrap_or(&empty_tag) 300 | .value 301 | .as_ref(); 302 | 303 | let no_ip = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)); 304 | 305 | let zone = if let Some(p) = instance.placement { 306 | p.availability_zone 307 | } else { 308 | None 309 | }; 310 | 311 | Self { 312 | id: instance.instance_id.unwrap_or_default(), 313 | name: match name { 314 | Some(name) => name.to_owned(), 315 | None => "".into(), 316 | }, 317 | priv_ip: IpAddr::from_str(&instance.private_ip_address.unwrap_or_default()) 318 | .unwrap_or(no_ip), 319 | pub_ip: IpAddr::from_str(&instance.public_ip_address.unwrap_or_default()) 320 | .unwrap_or(no_ip), 321 | nomad_client: None, 322 | nixos: match nixos { 323 | Some(nixos) => nixos.to_owned(), 324 | None => "".into(), 325 | }, 326 | node_type: instance.instance_type.map(|s| s.as_str().to_owned()), 327 | zone, 328 | asg: asg.map(|asg| asg.to_owned()), 329 | } 330 | } 331 | } 332 | 333 | impl BitteNode { 334 | async fn find_nodes( 335 | provider: BitteProvider, 336 | name: String, 337 | allocs: Option, 338 | clients: Option, 339 | args: ArgMatches, 340 | ) -> Result { 341 | match provider { 342 | BitteProvider::AWS => { 343 | let regions: HashSet = { 344 | let mut result = args.values_of_t("aws-asg-regions")?; 345 | let default = args.value_of_t("aws-region")?; 346 | result.push(default); 347 | result.into_iter().collect() 348 | }; 349 | 350 | let mut handles = Vec::with_capacity(regions.len()); 351 | 352 | for region_str in regions { 353 | let region = Region::new(region_str.clone()); 354 | let config = aws_config::from_env().region(region).load().await; 355 | let client = Ec2Client::new(&config); 356 | let request = client.describe_instances().set_filters(Some(vec![ 357 | Filter::builder() 358 | .set_name(Some("tag:Cluster".to_owned())) 359 | .set_values(Some(vec![name.to_owned()])) 360 | .build(), 361 | Filter::builder() 362 | .set_name(Some("instance-state-name".to_owned())) 363 | .set_values(Some(vec!["running".to_owned()])) 364 | .build(), 365 | ])); 366 | let response = tokio::spawn(async move { 367 | request.send().await.with_context(|| { 368 | format!("failed to connect to ec2.{}.amazonaws.com", region_str) 369 | }) 370 | }); 371 | handles.push(response); 372 | } 373 | 374 | let mut result: BitteNodes = Vec::new(); 375 | 376 | let allocs = if let Some(allocs) = allocs { 377 | allocs.await?? 378 | } else { 379 | Vec::new() 380 | }; 381 | let clients = if let Some(clients) = clients { 382 | clients.await?? 383 | } else { 384 | Vec::new() 385 | }; 386 | 387 | for response in handles.into_iter() { 388 | let response = response.await??; 389 | let iter = response.reservations.into_iter(); 390 | let mut nodes: BitteNodes = iter 391 | .flat_map(|reservations| { 392 | reservations 393 | .into_iter() 394 | .flat_map(|reservation| reservation.instances.unwrap_or_default()) 395 | }) 396 | .map(|instance| { 397 | let mut node = BitteNode::from(instance); 398 | node.nomad_client = match clients 399 | .iter() 400 | .find(|client| client.address == Some(node.priv_ip)) 401 | { 402 | Some(client) => { 403 | let mut client = client.to_owned(); 404 | client.allocs = { 405 | Some( 406 | allocs 407 | .iter() 408 | .filter(|alloc| alloc.node_id == client.id) 409 | .map(|alloc| alloc.to_owned()) 410 | .collect::(), 411 | ) 412 | }; 413 | Some(client) 414 | } 415 | None => None, 416 | }; 417 | 418 | node 419 | }) 420 | .collect(); 421 | 422 | result.append(&mut nodes); 423 | } 424 | 425 | Ok(result) 426 | } 427 | } 428 | } 429 | } 430 | 431 | type NomadClients = Vec; 432 | type NomadAllocs = Vec; 433 | type BitteNodes = Vec; 434 | pub type ClusterHandle = JoinHandle>; 435 | 436 | #[derive(Debug, Serialize, Deserialize, Clone)] 437 | #[serde(untagged)] 438 | pub enum AllocIndex { 439 | Int(u32), 440 | String(String), 441 | } 442 | 443 | impl AllocIndex { 444 | pub fn get(&self) -> Option { 445 | match self { 446 | Self::Int(i) => Some(*i), 447 | Self::String(_) => None, 448 | } 449 | } 450 | } 451 | 452 | #[derive(Debug, Serialize, Deserialize, Clone)] 453 | pub struct NomadAlloc { 454 | #[serde(rename = "ID")] 455 | pub id: Uuid, 456 | #[serde(rename = "JobID")] 457 | pub job_id: String, 458 | #[serde(rename = "Namespace")] 459 | pub namespace: String, 460 | #[serde(rename = "TaskGroup")] 461 | pub task_group: String, 462 | #[serde(rename = "ClientStatus")] 463 | pub status: String, 464 | #[serde( 465 | rename(deserialize = "Name", serialize = "Index"), 466 | deserialize_with = "pull_index" 467 | )] 468 | #[serde(alias = "Index")] 469 | pub index: AllocIndex, 470 | #[serde(rename = "NodeID")] 471 | pub node_id: Uuid, 472 | } 473 | 474 | impl NomadAlloc { 475 | async fn find_allocs(client: Arc, domain: String) -> Result { 476 | let url = format!("https://nomad.{}/v1/allocations", domain); 477 | let allocs = client 478 | .get(&url) 479 | .query(&[("namespace", "*"), ("task_states", "false")]) 480 | .send() 481 | .await 482 | .with_context(|| format!("failed to query: {}", &url))? 483 | .json::() 484 | .await 485 | .with_context(|| format!("failed to decode response from: {}", &url))?; 486 | Ok(allocs) 487 | } 488 | } 489 | 490 | fn pull_index<'de, D>(deserializer: D) -> Result 491 | where 492 | D: Deserializer<'de>, 493 | { 494 | let buf = AllocIndex::deserialize(deserializer)?; 495 | 496 | match buf { 497 | AllocIndex::Int(i) => Ok(AllocIndex::Int(i)), 498 | AllocIndex::String(s) => { 499 | let search = Regex::new("[0-9]*\\]$").unwrap().find(&s).unwrap().as_str(); 500 | 501 | let index = &search[0..search.len() - 1]; 502 | let index: u32 = index.parse().unwrap(); 503 | 504 | Ok(AllocIndex::Int(index)) 505 | } 506 | } 507 | } 508 | 509 | type ClientHandle = JoinHandle>; 510 | type AllocHandle = JoinHandle>; 511 | 512 | impl BitteCluster { 513 | pub async fn new(args: &ArgMatches, token: Option) -> Result { 514 | let name: String = args.value_of_t("name")?; 515 | let domain: String = args.value_of_t("domain")?; 516 | let provider: BitteProvider = { 517 | let provider: String = args.value_of_t("provider")?; 518 | match provider.parse() { 519 | Ok(v) => Ok(v), 520 | Err(_) => Err(Error::Provider { provider }), 521 | }? 522 | }; 523 | 524 | let nomad_api_client = match token { 525 | Some(token) => { 526 | let mut token = HeaderValue::from_str(&token.to_string())?; 527 | token.set_sensitive(true); 528 | let mut headers = HeaderMap::new(); 529 | headers.insert("X-Nomad-Token", token); 530 | Some(Arc::new( 531 | Client::builder() 532 | .default_headers(headers) 533 | .gzip(true) 534 | .build()?, 535 | )) 536 | } 537 | None => None, 538 | }; 539 | 540 | let nodes = if let Some(client) = &nomad_api_client { 541 | let allocs = tokio::spawn(NomadAlloc::find_allocs( 542 | Arc::clone(client), 543 | domain.to_owned(), 544 | )); 545 | 546 | let client_nodes = tokio::spawn(NomadClient::find_nomad_nodes( 547 | Arc::clone(client), 548 | domain.to_owned(), 549 | )); 550 | 551 | tokio::spawn(BitteNode::find_nodes( 552 | provider, 553 | name.to_owned(), 554 | Some(allocs), 555 | Some(client_nodes), 556 | args.clone(), 557 | )) 558 | .await?? 559 | } else { 560 | tokio::spawn(BitteNode::find_nodes( 561 | provider, 562 | name.to_owned(), 563 | None, 564 | None, 565 | args.clone(), 566 | )) 567 | .await?? 568 | }; 569 | 570 | let cluster = Self { 571 | name, 572 | domain, 573 | provider, 574 | nomad_api_client, 575 | nodes, 576 | ttl: SystemTime::now() 577 | .checked_add(Duration::from_secs(300)) 578 | .unwrap(), 579 | }; 580 | 581 | Ok(cluster) 582 | } 583 | 584 | #[inline(always)] 585 | pub fn init(args: ArgMatches, token: Option) -> ClusterHandle { 586 | tokio::spawn(async move { BitteCluster::new(&args, token).await }) 587 | } 588 | } 589 | -------------------------------------------------------------------------------- /cli/src/types/error.rs: -------------------------------------------------------------------------------- 1 | #[derive(thiserror::Error, Debug)] 2 | #[error(transparent)] 3 | pub enum Error { 4 | #[error("timeout elapsed")] 5 | Timeout(#[from] tokio::time::error::Elapsed), 6 | #[error("connection with {0} failed")] 7 | ConnectionFailed(#[from] std::io::Error), 8 | #[error("environment variable")] 9 | EnvVar(#[from] std::env::VarError), 10 | #[error("error parsing json")] 11 | Serde(#[from] serde_json::Error), 12 | #[error("error parsing netrc file")] 13 | Netrc(netrc_rs::Error), 14 | #[error("current BITTE_PROVIDER is not valid: {provider}")] 15 | Provider { provider: String }, 16 | } 17 | 18 | // NOTE netrc_rs doesn't impl StdError so can't simply `#[from]` 19 | impl From for Error { 20 | fn from(error: netrc_rs::Error) -> Self { 21 | Error::Netrc(error) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /cli/src/utils.rs: -------------------------------------------------------------------------------- 1 | pub mod nomad; 2 | 3 | #[derive(Clone)] 4 | pub struct Instance { 5 | pub public_ip: String, 6 | pub name: String, 7 | pub uid: String, 8 | pub flake_attr: String, 9 | pub s3_cache: String, 10 | } 11 | -------------------------------------------------------------------------------- /cli/src/utils/nomad.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::collections::HashMap; 3 | 4 | impl std::fmt::Display for Topic { 5 | fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 6 | formatter.write_fmt(format_args!("{:?}", self)) 7 | } 8 | } 9 | 10 | impl std::fmt::Display for NomadEvent { 11 | fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 12 | if let Some(events) = &self.events { 13 | for event in events { 14 | formatter.write_fmt(format_args!("Topic: {}\n", event.topic))?; 15 | formatter.write_fmt(format_args!(" Namespace: {}\n", event.namespace))?; 16 | formatter.write_fmt(format_args!(" Key: {}\n", event.key))?; 17 | formatter.write_fmt(format_args!(" Type: {:?}\n", event.event_type))?; 18 | formatter.write_fmt(format_args!(" Payload: {}\n", event.payload))?; 19 | } 20 | } 21 | Ok(()) 22 | } 23 | } 24 | 25 | impl std::fmt::Display for Payload { 26 | fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 27 | if let Some(allocation) = &self.allocation { 28 | formatter.write_fmt(format_args!("\n JobID: {}\n", allocation.job_id))?; 29 | }; 30 | if let Some(evaluation) = &self.evaluation { 31 | formatter.write_fmt(format_args!("\n JobID: {}\n", evaluation.job_id))?; 32 | }; 33 | if let Some(job) = &self.job { 34 | formatter.write_fmt(format_args!("\n Name: {}\n", job.name))?; 35 | }; 36 | if let Some(deployment) = &self.deployment { 37 | formatter.write_fmt(format_args!("\n JobID: {}\n", deployment.job_id))?; 38 | }; 39 | Ok(()) 40 | } 41 | } 42 | 43 | #[derive(Debug, Serialize, Deserialize)] 44 | pub struct NomadEvent { 45 | #[serde(rename = "Index")] 46 | pub index: Option, 47 | #[serde(rename = "Events")] 48 | pub events: Option>, 49 | } 50 | 51 | #[derive(Debug, Serialize, Deserialize)] 52 | pub struct EventsSortedEvent { 53 | #[serde(rename = "Topic")] 54 | pub topic: Topic, 55 | #[serde(rename = "Type")] 56 | pub event_type: NomadEventType, 57 | #[serde(rename = "Key")] 58 | pub key: String, 59 | #[serde(rename = "Namespace")] 60 | pub namespace: String, 61 | #[serde(rename = "FilterKeys")] 62 | pub filter_keys: Option>, 63 | #[serde(rename = "Index")] 64 | pub index: i64, 65 | #[serde(rename = "Payload")] 66 | pub payload: Payload, 67 | } 68 | 69 | #[derive(Debug, Serialize, Deserialize)] 70 | pub struct Payload { 71 | #[serde(rename = "Allocation")] 72 | pub allocation: Option, 73 | #[serde(rename = "Evaluation")] 74 | pub evaluation: Option, 75 | #[serde(rename = "Job")] 76 | pub job: Option, 77 | #[serde(rename = "Deployment")] 78 | pub deployment: Option, 79 | } 80 | 81 | #[derive(Debug, Serialize, Deserialize)] 82 | pub struct Allocation { 83 | #[serde(rename = "ID")] 84 | pub id: String, 85 | #[serde(rename = "Namespace")] 86 | pub namespace: String, 87 | #[serde(rename = "EvalID")] 88 | pub eval_id: String, 89 | #[serde(rename = "Name")] 90 | pub name: String, 91 | #[serde(rename = "NodeID")] 92 | pub node_id: String, 93 | #[serde(rename = "NodeName")] 94 | pub node_name: String, 95 | #[serde(rename = "JobID")] 96 | pub job_id: String, 97 | #[serde(rename = "Job")] 98 | pub job: Option, 99 | #[serde(rename = "TaskGroup")] 100 | pub task_group: String, 101 | #[serde(rename = "Resources")] 102 | pub resources: Resources, 103 | #[serde(rename = "SharedResources")] 104 | pub shared_resources: Resources, 105 | #[serde(rename = "TaskResources")] 106 | pub task_resources: TaskResources, 107 | #[serde(rename = "AllocatedResources")] 108 | pub allocated_resources: AllocatedResources, 109 | #[serde(rename = "Metrics")] 110 | pub metrics: Metrics, 111 | #[serde(rename = "DesiredStatus")] 112 | pub desired_status: DesiredStatus, 113 | #[serde(rename = "DesiredDescription")] 114 | pub desired_description: DesiredDescription, 115 | #[serde(rename = "DesiredTransition")] 116 | pub desired_transition: DesiredTransition, 117 | #[serde(rename = "ClientStatus")] 118 | pub client_status: Status, 119 | #[serde(rename = "ClientDescription")] 120 | pub client_description: ClientDescription, 121 | #[serde(rename = "TaskStates")] 122 | pub task_states: Option>, 123 | #[serde(rename = "AllocStates")] 124 | pub alloc_states: Option, 125 | #[serde(rename = "PreviousAllocation")] 126 | pub previous_allocation: String, 127 | #[serde(rename = "NextAllocation")] 128 | pub next_allocation: String, 129 | #[serde(rename = "DeploymentID")] 130 | pub deployment_id: String, 131 | #[serde(rename = "DeploymentStatus")] 132 | pub deployment_status: Option, 133 | #[serde(rename = "RescheduleTracker")] 134 | pub reschedule_tracker: Option, 135 | #[serde(rename = "NetworkStatus")] 136 | pub network_status: Option, 137 | #[serde(rename = "FollowupEvalID")] 138 | pub followup_eval_id: String, 139 | #[serde(rename = "PreemptedAllocations")] 140 | pub preempted_allocations: Option, 141 | #[serde(rename = "PreemptedByAllocation")] 142 | pub preempted_by_allocation: String, 143 | #[serde(rename = "CreateIndex")] 144 | pub create_index: i64, 145 | #[serde(rename = "ModifyIndex")] 146 | pub modify_index: i64, 147 | #[serde(rename = "AllocModifyIndex")] 148 | pub alloc_modify_index: i64, 149 | #[serde(rename = "CreateTime")] 150 | pub create_time: i64, 151 | #[serde(rename = "ModifyTime")] 152 | pub modify_time: i64, 153 | } 154 | 155 | #[derive(Debug, Serialize, Deserialize)] 156 | pub struct TaskState { 157 | #[serde(rename = "State")] 158 | pub state: String, 159 | #[serde(rename = "Failed")] 160 | pub failed: bool, 161 | #[serde(rename = "Restarts")] 162 | pub restarts: i64, 163 | #[serde(rename = "LastRestart")] 164 | pub last_restart: String, 165 | #[serde(rename = "StartedAt")] 166 | pub started_at: String, 167 | #[serde(rename = "FinishedAt")] 168 | pub finished_at: String, 169 | #[serde(rename = "Events")] 170 | pub events: Vec, 171 | } 172 | 173 | #[derive(Debug, Serialize, Deserialize)] 174 | pub struct AllocatedResources { 175 | #[serde(rename = "Tasks")] 176 | pub tasks: TaskResources, 177 | #[serde(rename = "TaskLifecycles")] 178 | pub task_lifecycles: TaskResources, 179 | #[serde(rename = "Shared")] 180 | pub shared: Shared, 181 | } 182 | 183 | #[derive(Debug, Serialize, Deserialize)] 184 | pub struct Shared { 185 | #[serde(rename = "Networks")] 186 | pub networks: Vec, 187 | #[serde(rename = "DiskMB")] 188 | pub disk_mb: i64, 189 | #[serde(rename = "Ports")] 190 | pub ports: Option>, 191 | } 192 | 193 | #[derive(Debug, Serialize, Deserialize)] 194 | pub struct Network { 195 | #[serde(rename = "Mode")] 196 | pub mode: Mode, 197 | #[serde(rename = "Device")] 198 | pub device: String, 199 | #[serde(rename = "CIDR")] 200 | pub cidr: String, 201 | #[serde(rename = "IP")] 202 | pub ip: String, 203 | #[serde(rename = "MBits")] 204 | pub m_bits: i64, 205 | #[serde(rename = "DNS")] 206 | pub dns: Option, 207 | #[serde(rename = "ReservedPorts")] 208 | pub reserved_ports: Option, 209 | #[serde(rename = "DynamicPorts")] 210 | pub dynamic_ports: Vec, 211 | } 212 | 213 | #[derive(Debug, Serialize, Deserialize)] 214 | pub struct Port { 215 | #[serde(rename = "Label")] 216 | pub label: String, 217 | #[serde(rename = "Value")] 218 | pub value: i64, 219 | #[serde(rename = "To")] 220 | pub to: i64, 221 | #[serde(rename = "HostNetwork")] 222 | pub host_network: Option, 223 | #[serde(rename = "HostIP")] 224 | pub host_ip: Option, 225 | } 226 | 227 | #[derive(Debug, Serialize, Deserialize)] 228 | pub struct Event { 229 | #[serde(rename = "Type")] 230 | pub event_type: String, 231 | #[serde(rename = "Time")] 232 | pub time: i64, 233 | #[serde(rename = "Message")] 234 | pub message: String, 235 | #[serde(rename = "DisplayMessage")] 236 | pub display_message: String, 237 | #[serde(rename = "Details")] 238 | pub details: Details, 239 | #[serde(rename = "FailsTask")] 240 | pub fails_task: bool, 241 | #[serde(rename = "RestartReason")] 242 | pub restart_reason: String, 243 | #[serde(rename = "SetupError")] 244 | pub setup_error: String, 245 | #[serde(rename = "DriverError")] 246 | pub driver_error: String, 247 | #[serde(rename = "ExitCode")] 248 | pub exit_code: i64, 249 | #[serde(rename = "Signal")] 250 | pub signal: i64, 251 | #[serde(rename = "KillTimeout")] 252 | pub kill_timeout: i64, 253 | #[serde(rename = "KillError")] 254 | pub kill_error: String, 255 | #[serde(rename = "KillReason")] 256 | pub kill_reason: String, 257 | #[serde(rename = "StartDelay")] 258 | pub start_delay: i64, 259 | #[serde(rename = "DownloadError")] 260 | pub download_error: String, 261 | #[serde(rename = "ValidationError")] 262 | pub validation_error: String, 263 | #[serde(rename = "DiskLimit")] 264 | pub disk_limit: i64, 265 | #[serde(rename = "FailedSibling")] 266 | pub failed_sibling: String, 267 | #[serde(rename = "VaultError")] 268 | pub vault_error: String, 269 | #[serde(rename = "TaskSignalReason")] 270 | pub task_signal_reason: String, 271 | #[serde(rename = "TaskSignal")] 272 | pub task_signal: String, 273 | #[serde(rename = "DriverMessage")] 274 | pub driver_message: String, 275 | #[serde(rename = "GenericSource")] 276 | pub generic_source: String, 277 | } 278 | 279 | #[derive(Debug, Serialize, Deserialize)] 280 | pub struct Cpu { 281 | #[serde(rename = "CpuShares")] 282 | pub cpu_shares: i64, 283 | } 284 | 285 | #[derive(Debug, Serialize, Deserialize)] 286 | pub struct Memory { 287 | #[serde(rename = "MemoryMB")] 288 | pub memory_mb: i64, 289 | } 290 | 291 | #[derive(Debug, Serialize, Deserialize)] 292 | pub struct Details { 293 | pub exit_code: Option, 294 | pub exit_message: Option, 295 | pub failed_sibling: Option, 296 | pub fails_task: Option, 297 | pub image: Option, 298 | pub kill_timeout: Option, 299 | pub message: Option, 300 | pub oom_killed: Option, 301 | pub restart_reason: Option, 302 | pub signal: Option, 303 | pub start_delay: Option, 304 | } 305 | 306 | #[derive(Debug, Serialize, Deserialize)] 307 | pub struct DeploymentStatus { 308 | #[serde(rename = "Healthy")] 309 | pub healthy: bool, 310 | #[serde(rename = "Timestamp")] 311 | pub timestamp: String, 312 | #[serde(rename = "Canary")] 313 | pub canary: bool, 314 | #[serde(rename = "ModifyIndex")] 315 | pub modify_index: i64, 316 | } 317 | 318 | #[derive(Debug, Serialize, Deserialize)] 319 | pub struct DesiredTransition { 320 | #[serde(rename = "Migrate")] 321 | pub migrate: Option, 322 | #[serde(rename = "Reschedule")] 323 | pub reschedule: Option, 324 | #[serde(rename = "ForceReschedule")] 325 | pub force_reschedule: Option, 326 | } 327 | 328 | #[derive(Debug, Serialize, Deserialize)] 329 | pub struct Metrics { 330 | #[serde(rename = "NodesEvaluated")] 331 | pub nodes_evaluated: i64, 332 | #[serde(rename = "NodesFiltered")] 333 | pub nodes_filtered: i64, 334 | #[serde(rename = "NodesAvailable")] 335 | pub nodes_available: NodesAvailable, 336 | #[serde(rename = "ClassFiltered")] 337 | pub class_filtered: Option, 338 | #[serde(rename = "ConstraintFiltered")] 339 | pub constraint_filtered: Option, 340 | #[serde(rename = "NodesExhausted")] 341 | pub nodes_exhausted: i64, 342 | #[serde(rename = "ClassExhausted")] 343 | pub class_exhausted: Option, 344 | #[serde(rename = "DimensionExhausted")] 345 | pub dimension_exhausted: Option, 346 | #[serde(rename = "QuotaExhausted")] 347 | pub quota_exhausted: Option, 348 | #[serde(rename = "Scores")] 349 | pub scores: Option, 350 | #[serde(rename = "ScoreMetaData")] 351 | pub score_meta_data: Vec, 352 | #[serde(rename = "AllocationTime")] 353 | pub allocation_time: i64, 354 | #[serde(rename = "CoalescedFailures")] 355 | pub coalesced_failures: i64, 356 | } 357 | 358 | #[derive(Debug, Serialize, Deserialize)] 359 | pub struct DimensionExhausted { 360 | pub memory: i64, 361 | } 362 | 363 | #[derive(Debug, Serialize, Deserialize)] 364 | pub struct NodesAvailable { 365 | #[serde(rename = "eu-central-1")] 366 | pub eu_central_1: i64, 367 | #[serde(rename = "us-east-2")] 368 | pub us_east_2: i64, 369 | } 370 | 371 | #[derive(Debug, Serialize, Deserialize)] 372 | pub struct ScoreMetaDatum { 373 | #[serde(rename = "NodeID")] 374 | pub node_id: String, 375 | #[serde(rename = "Scores")] 376 | pub scores: Scores, 377 | #[serde(rename = "NormScore")] 378 | pub norm_score: f64, 379 | } 380 | 381 | #[derive(Debug, Serialize, Deserialize)] 382 | pub struct Scores { 383 | pub binpack: f64, 384 | #[serde(rename = "job-anti-affinity")] 385 | pub job_anti_affinity: f64, 386 | #[serde(rename = "node-affinity")] 387 | pub node_affinity: i64, 388 | #[serde(rename = "node-reschedule-penalty")] 389 | pub node_reschedule_penalty: i64, 390 | } 391 | 392 | #[derive(Debug, Serialize, Deserialize)] 393 | pub struct NetworkStatus { 394 | #[serde(rename = "InterfaceName")] 395 | pub interface_name: String, 396 | #[serde(rename = "Address")] 397 | pub address: String, 398 | #[serde(rename = "DNS")] 399 | pub dns: Option, 400 | } 401 | 402 | #[derive(Debug, Serialize, Deserialize)] 403 | pub struct Dns { 404 | #[serde(rename = "Servers")] 405 | pub servers: Vec>, 406 | #[serde(rename = "Searches")] 407 | pub searches: Vec>, 408 | #[serde(rename = "Options")] 409 | pub options: Vec>, 410 | } 411 | 412 | #[derive(Debug, Serialize, Deserialize)] 413 | pub struct RescheduleTracker { 414 | #[serde(rename = "Events")] 415 | pub events: Vec, 416 | } 417 | 418 | #[derive(Debug, Serialize, Deserialize)] 419 | pub struct RescheduleTrackerEvent { 420 | #[serde(rename = "RescheduleTime")] 421 | pub reschedule_time: i64, 422 | #[serde(rename = "PrevAllocID")] 423 | pub prev_alloc_id: String, 424 | #[serde(rename = "PrevNodeID")] 425 | pub prev_node_id: String, 426 | #[serde(rename = "Delay")] 427 | pub delay: i64, 428 | } 429 | 430 | #[derive(Debug, Serialize, Deserialize)] 431 | pub struct Resources { 432 | #[serde(alias = "CPU", alias = "Cpu")] 433 | pub cpu: i64, 434 | #[serde(rename = "MemoryMB")] 435 | pub memory_mb: i64, 436 | #[serde(rename = "DiskMB")] 437 | pub disk_mb: i64, 438 | #[serde(rename = "IOPS")] 439 | pub iops: i64, 440 | #[serde(rename = "Networks")] 441 | pub networks: Option>, 442 | #[serde(rename = "Devices")] 443 | pub devices: Option, 444 | } 445 | 446 | #[derive(Debug, Serialize, Deserialize)] 447 | pub struct TaskResources { 448 | #[serde(rename = "Cpu")] 449 | pub explorer_cpu: Option, 450 | #[serde(rename = "Memory")] 451 | pub memory: Option, 452 | #[serde(rename = "Networks")] 453 | pub networks: Option, 454 | #[serde(rename = "Devices")] 455 | pub devices: Option, 456 | #[serde(rename = "CPU")] 457 | pub cpu: Option, 458 | #[serde(rename = "MemoryMB")] 459 | pub memory_mb: Option, 460 | #[serde(rename = "DiskMB")] 461 | pub disk_mb: Option, 462 | #[serde(rename = "IOPS")] 463 | pub iops: Option, 464 | #[serde(rename = "State")] 465 | pub state: Option, 466 | #[serde(rename = "Failed")] 467 | pub failed: Option, 468 | #[serde(rename = "Restarts")] 469 | pub restarts: Option, 470 | #[serde(rename = "LastRestart")] 471 | pub last_restart: Option, 472 | #[serde(rename = "StartedAt")] 473 | pub started_at: Option, 474 | #[serde(rename = "FinishedAt")] 475 | pub finished_at: Option, 476 | #[serde(rename = "Events")] 477 | pub events: Option>, 478 | } 479 | 480 | #[derive(Debug, Serialize, Deserialize)] 481 | pub struct Deployment { 482 | #[serde(rename = "ID")] 483 | pub id: String, 484 | #[serde(rename = "Namespace")] 485 | pub namespace: String, 486 | #[serde(rename = "JobID")] 487 | pub job_id: String, 488 | #[serde(rename = "JobVersion")] 489 | pub job_version: i64, 490 | #[serde(rename = "JobModifyIndex")] 491 | pub job_modify_index: i64, 492 | #[serde(rename = "JobSpecModifyIndex")] 493 | pub job_spec_modify_index: i64, 494 | #[serde(rename = "JobCreateIndex")] 495 | pub job_create_index: i64, 496 | #[serde(rename = "IsMultiregion")] 497 | pub is_multiregion: bool, 498 | #[serde(rename = "TaskGroups")] 499 | pub task_groups: TaskGroups, 500 | #[serde(rename = "Status")] 501 | pub status: DeploymentStatusEnum, 502 | #[serde(rename = "StatusDescription")] 503 | pub status_description: DeploymentStatusDescription, 504 | #[serde(rename = "CreateIndex")] 505 | pub create_index: i64, 506 | #[serde(rename = "ModifyIndex")] 507 | pub modify_index: i64, 508 | } 509 | 510 | #[derive(Debug, Serialize, Deserialize)] 511 | pub struct TaskGroups { 512 | pub mantis: Option, 513 | pub explorer: Option, 514 | } 515 | 516 | #[derive(Debug, Serialize, Deserialize)] 517 | pub struct MantisClass { 518 | #[serde(rename = "AutoRevert")] 519 | pub auto_revert: bool, 520 | #[serde(rename = "AutoPromote")] 521 | pub auto_promote: bool, 522 | #[serde(rename = "ProgressDeadline")] 523 | pub progress_deadline: i64, 524 | #[serde(rename = "RequireProgressBy")] 525 | pub require_progress_by: String, 526 | #[serde(rename = "Promoted")] 527 | pub promoted: bool, 528 | #[serde(rename = "PlacedCanaries")] 529 | pub placed_canaries: Option, 530 | #[serde(rename = "DesiredCanaries")] 531 | pub desired_canaries: i64, 532 | #[serde(rename = "DesiredTotal")] 533 | pub desired_total: i64, 534 | #[serde(rename = "PlacedAllocs")] 535 | pub placed_allocs: i64, 536 | #[serde(rename = "HealthyAllocs")] 537 | pub healthy_allocs: i64, 538 | #[serde(rename = "UnhealthyAllocs")] 539 | pub unhealthy_allocs: i64, 540 | } 541 | 542 | #[derive(Debug, Serialize, Deserialize)] 543 | pub struct Evaluation { 544 | #[serde(rename = "ID")] 545 | pub id: String, 546 | #[serde(rename = "Namespace")] 547 | pub namespace: String, 548 | #[serde(rename = "Priority")] 549 | pub priority: i64, 550 | #[serde(rename = "Type")] 551 | pub evaluation_type: EvaluationType, 552 | #[serde(rename = "TriggeredBy")] 553 | pub triggered_by: TriggeredBy, 554 | #[serde(rename = "JobID")] 555 | pub job_id: String, 556 | #[serde(rename = "JobModifyIndex")] 557 | pub job_modify_index: i64, 558 | #[serde(rename = "NodeID")] 559 | pub node_id: String, 560 | #[serde(rename = "NodeModifyIndex")] 561 | pub node_modify_index: i64, 562 | #[serde(rename = "DeploymentID")] 563 | pub deployment_id: String, 564 | #[serde(rename = "Status")] 565 | pub status: Status, 566 | #[serde(rename = "StatusDescription")] 567 | pub status_description: EvaluationStatusDescription, 568 | #[serde(rename = "Wait")] 569 | pub wait: i64, 570 | #[serde(rename = "WaitUntil")] 571 | pub wait_until: String, 572 | #[serde(rename = "NextEval")] 573 | pub next_eval: String, 574 | #[serde(rename = "PreviousEval")] 575 | pub previous_eval: String, 576 | #[serde(rename = "BlockedEval")] 577 | pub blocked_eval: String, 578 | #[serde(rename = "FailedTGAllocs")] 579 | pub failed_tg_allocs: Option, 580 | #[serde(rename = "ClassEligibility")] 581 | pub class_eligibility: Option, 582 | #[serde(rename = "QuotaLimitReached")] 583 | pub quota_limit_reached: String, 584 | #[serde(rename = "EscapedComputedClass")] 585 | pub escaped_computed_class: bool, 586 | #[serde(rename = "AnnotatePlan")] 587 | pub annotate_plan: bool, 588 | #[serde(rename = "QueuedAllocations")] 589 | pub queued_allocations: Option, 590 | #[serde(rename = "LeaderACL")] 591 | pub leader_acl: String, 592 | #[serde(rename = "SnapshotIndex")] 593 | pub snapshot_index: i64, 594 | #[serde(rename = "CreateIndex")] 595 | pub create_index: i64, 596 | #[serde(rename = "ModifyIndex")] 597 | pub modify_index: i64, 598 | #[serde(rename = "CreateTime")] 599 | pub create_time: i64, 600 | #[serde(rename = "ModifyTime")] 601 | pub modify_time: i64, 602 | } 603 | 604 | #[derive(Debug, Serialize, Deserialize)] 605 | pub struct QueuedAllocations { 606 | pub mantis: Option, 607 | pub explorer: Option, 608 | } 609 | 610 | #[derive(Debug, Serialize, Deserialize)] 611 | pub struct Job { 612 | #[serde(rename = "Stop")] 613 | pub stop: bool, 614 | #[serde(rename = "Region")] 615 | pub region: String, 616 | #[serde(rename = "Namespace")] 617 | pub namespace: String, 618 | #[serde(rename = "ID")] 619 | pub id: String, 620 | #[serde(rename = "ParentID")] 621 | pub parent_id: String, 622 | #[serde(rename = "Name")] 623 | pub name: String, 624 | #[serde(rename = "Type")] 625 | pub job_type: EvaluationType, 626 | #[serde(rename = "Priority")] 627 | pub priority: i64, 628 | #[serde(rename = "AllAtOnce")] 629 | pub all_at_once: bool, 630 | #[serde(rename = "Datacenters")] 631 | pub datacenters: Vec, 632 | #[serde(rename = "Affinities")] 633 | pub affinities: Option>>, 634 | #[serde(rename = "Constraints")] 635 | pub constraints: Option>>, 636 | #[serde(rename = "Spreads")] 637 | pub spreads: Option>>, 638 | #[serde(rename = "TaskGroups")] 639 | pub task_groups: Vec, 640 | #[serde(rename = "Update")] 641 | pub update: Update, 642 | #[serde(rename = "Multiregion")] 643 | pub multiregion: Option, 644 | #[serde(rename = "Periodic")] 645 | pub periodic: Option, 646 | #[serde(rename = "ParameterizedJob")] 647 | pub parameterized_job: Option, 648 | #[serde(rename = "Dispatched")] 649 | pub dispatched: bool, 650 | #[serde(rename = "Payload")] 651 | pub payload: Option, 652 | #[serde(rename = "Meta")] 653 | pub meta: Option>, 654 | #[serde(rename = "ConsulToken")] 655 | pub consul_token: String, 656 | #[serde(rename = "VaultToken")] 657 | pub vault_token: String, 658 | #[serde(rename = "VaultNamespace")] 659 | pub vault_namespace: String, 660 | #[serde(rename = "NomadTokenID")] 661 | pub nomad_token_id: String, 662 | #[serde(rename = "Status")] 663 | pub status: Stat, 664 | #[serde(rename = "StatusDescription")] 665 | pub status_description: String, 666 | #[serde(rename = "Stable")] 667 | pub stable: bool, 668 | #[serde(rename = "Version")] 669 | pub version: i64, 670 | #[serde(rename = "SubmitTime")] 671 | pub submit_time: i64, 672 | #[serde(rename = "CreateIndex")] 673 | pub create_index: i64, 674 | #[serde(rename = "ModifyIndex")] 675 | pub modify_index: i64, 676 | #[serde(rename = "JobModifyIndex")] 677 | pub job_modify_index: i64, 678 | } 679 | 680 | #[derive(Debug, Serialize, Deserialize)] 681 | pub struct TaskGroup { 682 | #[serde(rename = "Name")] 683 | pub name: String, 684 | #[serde(rename = "Count")] 685 | pub count: i64, 686 | #[serde(rename = "Update")] 687 | pub update: Update, 688 | #[serde(rename = "Migrate")] 689 | pub migrate: Migrate, 690 | #[serde(rename = "Affinities")] 691 | pub affinities: Option>>, 692 | #[serde(rename = "Constraints")] 693 | pub constraints: Option>>, 694 | #[serde(rename = "Spreads")] 695 | pub spreads: Option>>, 696 | #[serde(rename = "Scaling")] 697 | pub scaling: Option, 698 | #[serde(rename = "RestartPolicy")] 699 | pub restart_policy: RestartPolicy, 700 | #[serde(rename = "Tasks")] 701 | pub tasks: Vec, 702 | #[serde(rename = "EphemeralDisk")] 703 | pub ephemeral_disk: EphemeralDisk, 704 | #[serde(rename = "Meta")] 705 | pub meta: Option>, 706 | #[serde(rename = "ReschedulePolicy")] 707 | pub reschedule_policy: ReschedulePolicy, 708 | #[serde(rename = "Networks")] 709 | pub networks: Vec, 710 | #[serde(rename = "Services")] 711 | pub services: Vec, 712 | #[serde(rename = "Volumes")] 713 | pub volumes: Option, 714 | #[serde(rename = "ShutdownDelay")] 715 | pub shutdown_delay: i64, 716 | #[serde(rename = "StopAfterClientDisconnect")] 717 | pub stop_after_client_disconnect: Option, 718 | } 719 | 720 | #[derive(Debug, Serialize, Deserialize)] 721 | pub struct Constraint { 722 | #[serde(rename = "LTarget")] 723 | pub l_target: String, 724 | #[serde(rename = "RTarget")] 725 | pub r_target: String, 726 | #[serde(rename = "Operand")] 727 | pub operand: String, 728 | } 729 | 730 | #[derive(Debug, Serialize, Deserialize)] 731 | pub struct EphemeralDisk { 732 | #[serde(rename = "Sticky")] 733 | pub sticky: bool, 734 | #[serde(rename = "SizeMB")] 735 | pub size_mb: i64, 736 | #[serde(rename = "Migrate")] 737 | pub migrate: bool, 738 | } 739 | 740 | #[derive(Debug, Serialize, Deserialize)] 741 | pub struct Migrate { 742 | #[serde(rename = "MaxParallel")] 743 | pub max_parallel: i64, 744 | #[serde(rename = "HealthCheck")] 745 | pub health_check: HealthCheck, 746 | #[serde(rename = "MinHealthyTime")] 747 | pub min_healthy_time: i64, 748 | #[serde(rename = "HealthyDeadline")] 749 | pub healthy_deadline: i64, 750 | } 751 | 752 | #[derive(Debug, Serialize, Deserialize)] 753 | pub struct ReschedulePolicy { 754 | #[serde(rename = "Attempts")] 755 | pub attempts: i64, 756 | #[serde(rename = "Interval")] 757 | pub interval: i64, 758 | #[serde(rename = "Delay")] 759 | pub delay: i64, 760 | #[serde(rename = "DelayFunction")] 761 | pub delay_function: DelayFunction, 762 | #[serde(rename = "MaxDelay")] 763 | pub max_delay: i64, 764 | #[serde(rename = "Unlimited")] 765 | pub unlimited: bool, 766 | } 767 | 768 | #[derive(Debug, Serialize, Deserialize)] 769 | pub struct RestartPolicy { 770 | #[serde(rename = "Attempts")] 771 | pub attempts: i64, 772 | #[serde(rename = "Interval")] 773 | pub interval: i64, 774 | #[serde(rename = "Delay")] 775 | pub delay: i64, 776 | #[serde(rename = "Mode")] 777 | pub mode: RestartPolicyMode, 778 | } 779 | 780 | #[derive(Debug, Serialize, Deserialize)] 781 | pub struct Service { 782 | #[serde(rename = "Name")] 783 | pub name: String, 784 | #[serde(rename = "TaskName")] 785 | pub task_name: String, 786 | #[serde(rename = "PortLabel")] 787 | pub port_label: String, 788 | #[serde(rename = "AddressMode")] 789 | pub address_mode: AddressMode, 790 | #[serde(rename = "EnableTagOverride")] 791 | pub enable_tag_override: bool, 792 | #[serde(rename = "Tags")] 793 | pub tags: Vec, 794 | #[serde(rename = "CanaryTags")] 795 | pub canary_tags: Option>, 796 | #[serde(rename = "Checks")] 797 | pub checks: Option>, 798 | #[serde(rename = "Connect")] 799 | pub connect: Option, 800 | #[serde(rename = "Meta")] 801 | pub meta: Option>, 802 | #[serde(rename = "CanaryMeta")] 803 | pub canary_meta: Option>, 804 | } 805 | 806 | #[derive(Debug, Serialize, Deserialize)] 807 | pub struct Check { 808 | #[serde(rename = "Name")] 809 | pub name: String, 810 | #[serde(rename = "Type")] 811 | pub check_type: Type, 812 | #[serde(rename = "Command")] 813 | pub command: String, 814 | #[serde(rename = "Args")] 815 | pub args: Option>, 816 | #[serde(rename = "Path")] 817 | pub path: String, 818 | #[serde(rename = "Protocol")] 819 | pub protocol: String, 820 | #[serde(rename = "PortLabel")] 821 | pub port_label: String, 822 | #[serde(rename = "Expose")] 823 | pub expose: bool, 824 | #[serde(rename = "AddressMode")] 825 | pub address_mode: Mode, 826 | #[serde(rename = "Interval")] 827 | pub interval: i64, 828 | #[serde(rename = "Timeout")] 829 | pub timeout: i64, 830 | #[serde(rename = "InitialStatus")] 831 | pub initial_status: String, 832 | #[serde(rename = "TLSSkipVerify")] 833 | pub tls_skip_verify: bool, 834 | #[serde(rename = "Method")] 835 | pub method: String, 836 | #[serde(rename = "Header")] 837 | pub header: Option, 838 | #[serde(rename = "CheckRestart")] 839 | pub check_restart: CheckRestart, 840 | #[serde(rename = "GRPCService")] 841 | pub grpc_service: String, 842 | #[serde(rename = "GRPCUseTLS")] 843 | pub grpc_use_tls: bool, 844 | #[serde(rename = "TaskName")] 845 | pub task_name: String, 846 | #[serde(rename = "SuccessBeforePassing")] 847 | pub success_before_passing: i64, 848 | #[serde(rename = "FailuresBeforeCritical")] 849 | pub failures_before_critical: i64, 850 | } 851 | 852 | #[derive(Debug, Serialize, Deserialize)] 853 | pub struct CheckRestart { 854 | #[serde(rename = "Limit")] 855 | pub limit: i64, 856 | #[serde(rename = "Grace")] 857 | pub grace: i64, 858 | #[serde(rename = "IgnoreWarnings")] 859 | pub ignore_warnings: bool, 860 | } 861 | 862 | #[derive(Debug, Serialize, Deserialize)] 863 | pub struct Periodic { 864 | #[serde(rename = "Enabled")] 865 | pub enabled: bool, 866 | #[serde(rename = "TimeZone")] 867 | pub time_zone: String, 868 | #[serde(rename = "SpecType")] 869 | pub spec_type: String, 870 | #[serde(rename = "Spec")] 871 | pub spec: String, 872 | #[serde(rename = "ProhibitOverlap")] 873 | pub prohibit_overlap: bool, 874 | } 875 | 876 | #[derive(Debug, Serialize, Deserialize)] 877 | pub struct TaskElement { 878 | #[serde(rename = "Name")] 879 | pub name: String, 880 | #[serde(rename = "Driver")] 881 | pub driver: Driver, 882 | #[serde(rename = "User")] 883 | pub user: String, 884 | #[serde(rename = "Config")] 885 | pub config: Config, 886 | #[serde(rename = "Env")] 887 | pub env: Option>, 888 | #[serde(rename = "Services")] 889 | pub services: Option, 890 | #[serde(rename = "Vault")] 891 | pub vault: Option, 892 | #[serde(rename = "Templates")] 893 | pub templates: Vec