├── .dockerignore ├── .github └── workflows │ ├── build.yml │ └── test.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── LICENSE.md ├── PACKAGING.md ├── README.md ├── config.cfg ├── debian ├── changelog ├── compat ├── control ├── copyright ├── rules ├── source │ └── format ├── vigil-local.install ├── vigil-local.postinst └── vigil-local.service ├── scripts ├── build_packages.sh ├── release_binaries.sh └── sign_binaries.sh └── src ├── config ├── config.rs ├── defaults.rs ├── logger.rs ├── mod.rs └── reader.rs ├── main.rs └── probe ├── manager.rs ├── mod.rs ├── mode.rs ├── poll.rs ├── replica.rs ├── report.rs ├── script.rs └── status.rs /.dockerignore: -------------------------------------------------------------------------------- 1 | target/* 2 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: 4 | - "v*.*.*" 5 | 6 | name: Build and Release 7 | 8 | jobs: 9 | build-releases: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v2 15 | 16 | - name: Cache build artifacts 17 | id: cache-cargo 18 | uses: actions/cache@v4 19 | with: 20 | path: | 21 | ~/.cargo/bin 22 | ~/.cargo/registry 23 | ~/.cargo/git 24 | target 25 | key: build-${{ runner.os }}-cargo-any 26 | 27 | - name: Install Rust toolchain 28 | uses: actions-rs/toolchain@v1 29 | with: 30 | toolchain: stable 31 | components: rustfmt 32 | override: true 33 | 34 | - name: Install cross-compilation tools (if needed) 35 | run: which cross >/dev/null || cargo install cross 36 | 37 | - name: Verify versions 38 | run: rustc --version && rustup --version && cargo --version && cross --version 39 | 40 | - name: Get current tag 41 | id: current_tag 42 | uses: WyriHaximus/github-action-get-previous-tag@v1 43 | 44 | - name: Release package 45 | run: cargo publish --no-verify --token ${CRATES_TOKEN} 46 | env: 47 | CRATES_TOKEN: ${{ secrets.CRATES_TOKEN }} 48 | 49 | - name: Release binaries 50 | run: ./scripts/release_binaries.sh --version=${{ steps.current_tag.outputs.tag }} 51 | 52 | - name: Release new version 53 | uses: softprops/action-gh-release@v1 54 | with: 55 | tag_name: ${{ steps.current_tag.outputs.tag }} 56 | name: Vigil Local ${{ steps.current_tag.outputs.tag }} 57 | body: "⚠️ Changelog not yet provided." 58 | files: ./${{ steps.current_tag.outputs.tag }}-*.tar.gz 59 | env: 60 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 61 | 62 | build-packages: 63 | needs: build-releases 64 | runs-on: ubuntu-latest 65 | 66 | steps: 67 | - name: Checkout code 68 | uses: actions/checkout@v2 69 | 70 | - name: Build packages 71 | run: ./scripts/build_packages.sh 72 | 73 | - name: Push packages to Packagecloud 74 | uses: faucetsdn/action-packagecloud-upload-debian-packages@v1 75 | with: 76 | path: ./packages 77 | repo: ${{ secrets.PACKAGECLOUD_REPO }} 78 | token: ${{ secrets.PACKAGECLOUD_TOKEN }} 79 | 80 | build-docker: 81 | runs-on: ubuntu-latest 82 | 83 | steps: 84 | - name: Checkout code 85 | uses: actions/checkout@v2 86 | 87 | - name: Acquire Docker image metadata 88 | id: metadata 89 | uses: docker/metadata-action@v4 90 | with: 91 | images: valeriansaliou/vigil-local 92 | 93 | - name: Login to Docker Hub 94 | uses: docker/login-action@v2 95 | with: 96 | username: ${{ secrets.DOCKERHUB_USERNAME }} 97 | password: ${{ secrets.DOCKERHUB_TOKEN }} 98 | 99 | - name: Build and push Docker image 100 | uses: docker/build-push-action@v3 101 | with: 102 | context: . 103 | tags: ${{ steps.metadata.outputs.tags }} 104 | labels: ${{ steps.metadata.outputs.labels }} 105 | push: true 106 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | name: Test and Build 4 | 5 | jobs: 6 | test: 7 | strategy: 8 | matrix: 9 | os: [ubuntu-latest] 10 | rust-toolchain: [stable] 11 | fail-fast: false 12 | 13 | runs-on: ${{ matrix.os }} 14 | 15 | steps: 16 | - name: Checkout code 17 | uses: actions/checkout@v2 18 | 19 | - name: Cache build artifacts 20 | id: cache-cargo 21 | uses: actions/cache@v4 22 | with: 23 | path: | 24 | ~/.cargo/registry 25 | ~/.cargo/git 26 | target 27 | key: test-${{ runner.os }}-cargo-${{ matrix.rust-toolchain }} 28 | 29 | - name: Install Rust toolchain 30 | uses: actions-rs/toolchain@v1 31 | with: 32 | toolchain: ${{ matrix.rust-toolchain }} 33 | components: rustfmt 34 | override: true 35 | 36 | - name: Verify versions 37 | run: rustc --version && rustup --version && cargo --version 38 | 39 | - name: Build code 40 | run: cargo build 41 | 42 | - name: Test code 43 | run: cargo test 44 | 45 | - name: Check code style 46 | run: cargo fmt -- --check 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/* 2 | .DS_Store 3 | *~ 4 | *# 5 | .cargo 6 | 7 | build/ 8 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "anstream" 7 | version = "0.6.18" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" 10 | dependencies = [ 11 | "anstyle", 12 | "anstyle-parse", 13 | "anstyle-query", 14 | "anstyle-wincon", 15 | "colorchoice", 16 | "is_terminal_polyfill", 17 | "utf8parse", 18 | ] 19 | 20 | [[package]] 21 | name = "anstyle" 22 | version = "1.0.10" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" 25 | 26 | [[package]] 27 | name = "anstyle-parse" 28 | version = "0.2.6" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" 31 | dependencies = [ 32 | "utf8parse", 33 | ] 34 | 35 | [[package]] 36 | name = "anstyle-query" 37 | version = "1.1.2" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" 40 | dependencies = [ 41 | "windows-sys", 42 | ] 43 | 44 | [[package]] 45 | name = "anstyle-wincon" 46 | version = "3.0.6" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" 49 | dependencies = [ 50 | "anstyle", 51 | "windows-sys", 52 | ] 53 | 54 | [[package]] 55 | name = "base64" 56 | version = "0.13.1" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" 59 | 60 | [[package]] 61 | name = "base64" 62 | version = "0.21.7" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" 65 | 66 | [[package]] 67 | name = "bumpalo" 68 | version = "3.16.0" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 71 | 72 | [[package]] 73 | name = "byteorder" 74 | version = "1.5.0" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 77 | 78 | [[package]] 79 | name = "cc" 80 | version = "1.2.6" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333" 83 | dependencies = [ 84 | "shlex", 85 | ] 86 | 87 | [[package]] 88 | name = "cfg-if" 89 | version = "1.0.0" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 92 | 93 | [[package]] 94 | name = "clap" 95 | version = "4.5.23" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" 98 | dependencies = [ 99 | "clap_builder", 100 | ] 101 | 102 | [[package]] 103 | name = "clap_builder" 104 | version = "4.5.23" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" 107 | dependencies = [ 108 | "anstream", 109 | "anstyle", 110 | "clap_lex", 111 | "strsim", 112 | ] 113 | 114 | [[package]] 115 | name = "clap_lex" 116 | version = "0.7.4" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" 119 | 120 | [[package]] 121 | name = "colorchoice" 122 | version = "1.0.3" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" 125 | 126 | [[package]] 127 | name = "displaydoc" 128 | version = "0.2.5" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 131 | dependencies = [ 132 | "proc-macro2", 133 | "quote", 134 | "syn", 135 | ] 136 | 137 | [[package]] 138 | name = "dunce" 139 | version = "1.0.5" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" 142 | 143 | [[package]] 144 | name = "envsubst" 145 | version = "0.2.1" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "cf2f29f6ee674d1229e5715dfc7e24f14395a20d66949e36032de68b31542643" 148 | dependencies = [ 149 | "thiserror", 150 | ] 151 | 152 | [[package]] 153 | name = "equivalent" 154 | version = "1.0.1" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 157 | 158 | [[package]] 159 | name = "form_urlencoded" 160 | version = "1.2.1" 161 | source = "registry+https://github.com/rust-lang/crates.io-index" 162 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 163 | dependencies = [ 164 | "percent-encoding", 165 | ] 166 | 167 | [[package]] 168 | name = "fsio" 169 | version = "0.4.0" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "dad0ce30be0cc441b325c5d705c8b613a0ca0d92b6a8953d41bd236dc09a36d0" 172 | dependencies = [ 173 | "dunce", 174 | "rand", 175 | ] 176 | 177 | [[package]] 178 | name = "getrandom" 179 | version = "0.2.15" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 182 | dependencies = [ 183 | "cfg-if", 184 | "libc", 185 | "wasi", 186 | ] 187 | 188 | [[package]] 189 | name = "hashbrown" 190 | version = "0.15.2" 191 | source = "registry+https://github.com/rust-lang/crates.io-index" 192 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 193 | 194 | [[package]] 195 | name = "http_req" 196 | version = "0.9.3" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "42ce34c74ec562d68f2c23a532c62c1332ff1d1b6147fd118bd1938e090137d0" 199 | dependencies = [ 200 | "rustls", 201 | "unicase", 202 | "webpki", 203 | "webpki-roots", 204 | ] 205 | 206 | [[package]] 207 | name = "icu_collections" 208 | version = "1.5.0" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" 211 | dependencies = [ 212 | "displaydoc", 213 | "yoke", 214 | "zerofrom", 215 | "zerovec", 216 | ] 217 | 218 | [[package]] 219 | name = "icu_locid" 220 | version = "1.5.0" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" 223 | dependencies = [ 224 | "displaydoc", 225 | "litemap", 226 | "tinystr", 227 | "writeable", 228 | "zerovec", 229 | ] 230 | 231 | [[package]] 232 | name = "icu_locid_transform" 233 | version = "1.5.0" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" 236 | dependencies = [ 237 | "displaydoc", 238 | "icu_locid", 239 | "icu_locid_transform_data", 240 | "icu_provider", 241 | "tinystr", 242 | "zerovec", 243 | ] 244 | 245 | [[package]] 246 | name = "icu_locid_transform_data" 247 | version = "1.5.0" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" 250 | 251 | [[package]] 252 | name = "icu_normalizer" 253 | version = "1.5.0" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" 256 | dependencies = [ 257 | "displaydoc", 258 | "icu_collections", 259 | "icu_normalizer_data", 260 | "icu_properties", 261 | "icu_provider", 262 | "smallvec", 263 | "utf16_iter", 264 | "utf8_iter", 265 | "write16", 266 | "zerovec", 267 | ] 268 | 269 | [[package]] 270 | name = "icu_normalizer_data" 271 | version = "1.5.0" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" 274 | 275 | [[package]] 276 | name = "icu_properties" 277 | version = "1.5.1" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" 280 | dependencies = [ 281 | "displaydoc", 282 | "icu_collections", 283 | "icu_locid_transform", 284 | "icu_properties_data", 285 | "icu_provider", 286 | "tinystr", 287 | "zerovec", 288 | ] 289 | 290 | [[package]] 291 | name = "icu_properties_data" 292 | version = "1.5.0" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" 295 | 296 | [[package]] 297 | name = "icu_provider" 298 | version = "1.5.0" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" 301 | dependencies = [ 302 | "displaydoc", 303 | "icu_locid", 304 | "icu_provider_macros", 305 | "stable_deref_trait", 306 | "tinystr", 307 | "writeable", 308 | "yoke", 309 | "zerofrom", 310 | "zerovec", 311 | ] 312 | 313 | [[package]] 314 | name = "icu_provider_macros" 315 | version = "1.5.0" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" 318 | dependencies = [ 319 | "proc-macro2", 320 | "quote", 321 | "syn", 322 | ] 323 | 324 | [[package]] 325 | name = "idna" 326 | version = "1.0.3" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 329 | dependencies = [ 330 | "idna_adapter", 331 | "smallvec", 332 | "utf8_iter", 333 | ] 334 | 335 | [[package]] 336 | name = "idna_adapter" 337 | version = "1.2.0" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" 340 | dependencies = [ 341 | "icu_normalizer", 342 | "icu_properties", 343 | ] 344 | 345 | [[package]] 346 | name = "indexmap" 347 | version = "2.7.0" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" 350 | dependencies = [ 351 | "equivalent", 352 | "hashbrown", 353 | ] 354 | 355 | [[package]] 356 | name = "is_terminal_polyfill" 357 | version = "1.70.1" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 360 | 361 | [[package]] 362 | name = "itoa" 363 | version = "1.0.14" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" 366 | 367 | [[package]] 368 | name = "js-sys" 369 | version = "0.3.76" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" 372 | dependencies = [ 373 | "once_cell", 374 | "wasm-bindgen", 375 | ] 376 | 377 | [[package]] 378 | name = "lazy_static" 379 | version = "1.5.0" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 382 | 383 | [[package]] 384 | name = "libc" 385 | version = "0.2.169" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" 388 | 389 | [[package]] 390 | name = "litemap" 391 | version = "0.7.4" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" 394 | 395 | [[package]] 396 | name = "log" 397 | version = "0.4.22" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 400 | 401 | [[package]] 402 | name = "memchr" 403 | version = "2.7.4" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 406 | 407 | [[package]] 408 | name = "once_cell" 409 | version = "1.20.2" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 412 | 413 | [[package]] 414 | name = "percent-encoding" 415 | version = "2.3.1" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 418 | 419 | [[package]] 420 | name = "ping" 421 | version = "0.4.1" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "6370a87a1a5bacec2eb80fa24ff3b7f47a1d47404a96611230d3b0d2e0f51141" 424 | dependencies = [ 425 | "rand", 426 | "socket2", 427 | "thiserror", 428 | ] 429 | 430 | [[package]] 431 | name = "ppv-lite86" 432 | version = "0.2.20" 433 | source = "registry+https://github.com/rust-lang/crates.io-index" 434 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 435 | dependencies = [ 436 | "zerocopy", 437 | ] 438 | 439 | [[package]] 440 | name = "proc-macro2" 441 | version = "1.0.92" 442 | source = "registry+https://github.com/rust-lang/crates.io-index" 443 | checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" 444 | dependencies = [ 445 | "unicode-ident", 446 | ] 447 | 448 | [[package]] 449 | name = "quote" 450 | version = "1.0.38" 451 | source = "registry+https://github.com/rust-lang/crates.io-index" 452 | checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" 453 | dependencies = [ 454 | "proc-macro2", 455 | ] 456 | 457 | [[package]] 458 | name = "rand" 459 | version = "0.8.5" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 462 | dependencies = [ 463 | "libc", 464 | "rand_chacha", 465 | "rand_core", 466 | ] 467 | 468 | [[package]] 469 | name = "rand_chacha" 470 | version = "0.3.1" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 473 | dependencies = [ 474 | "ppv-lite86", 475 | "rand_core", 476 | ] 477 | 478 | [[package]] 479 | name = "rand_core" 480 | version = "0.6.4" 481 | source = "registry+https://github.com/rust-lang/crates.io-index" 482 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 483 | dependencies = [ 484 | "getrandom", 485 | ] 486 | 487 | [[package]] 488 | name = "ring" 489 | version = "0.16.20" 490 | source = "registry+https://github.com/rust-lang/crates.io-index" 491 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 492 | dependencies = [ 493 | "cc", 494 | "libc", 495 | "once_cell", 496 | "spin", 497 | "untrusted", 498 | "web-sys", 499 | "winapi", 500 | ] 501 | 502 | [[package]] 503 | name = "run_script" 504 | version = "0.10.1" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "829f98fdc58d78989dd9af83be28bc15c94a7d77f9ecdb54abbbc0b1829ba9c7" 507 | dependencies = [ 508 | "fsio", 509 | ] 510 | 511 | [[package]] 512 | name = "rustls" 513 | version = "0.19.1" 514 | source = "registry+https://github.com/rust-lang/crates.io-index" 515 | checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" 516 | dependencies = [ 517 | "base64 0.13.1", 518 | "log", 519 | "ring", 520 | "sct", 521 | "webpki", 522 | ] 523 | 524 | [[package]] 525 | name = "ryu" 526 | version = "1.0.18" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 529 | 530 | [[package]] 531 | name = "sct" 532 | version = "0.6.1" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" 535 | dependencies = [ 536 | "ring", 537 | "untrusted", 538 | ] 539 | 540 | [[package]] 541 | name = "serde" 542 | version = "1.0.217" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" 545 | dependencies = [ 546 | "serde_derive", 547 | ] 548 | 549 | [[package]] 550 | name = "serde_derive" 551 | version = "1.0.217" 552 | source = "registry+https://github.com/rust-lang/crates.io-index" 553 | checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" 554 | dependencies = [ 555 | "proc-macro2", 556 | "quote", 557 | "syn", 558 | ] 559 | 560 | [[package]] 561 | name = "serde_json" 562 | version = "1.0.134" 563 | source = "registry+https://github.com/rust-lang/crates.io-index" 564 | checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" 565 | dependencies = [ 566 | "itoa", 567 | "memchr", 568 | "ryu", 569 | "serde", 570 | ] 571 | 572 | [[package]] 573 | name = "serde_spanned" 574 | version = "0.6.8" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" 577 | dependencies = [ 578 | "serde", 579 | ] 580 | 581 | [[package]] 582 | name = "shlex" 583 | version = "1.3.0" 584 | source = "registry+https://github.com/rust-lang/crates.io-index" 585 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 586 | 587 | [[package]] 588 | name = "smallvec" 589 | version = "1.13.2" 590 | source = "registry+https://github.com/rust-lang/crates.io-index" 591 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 592 | 593 | [[package]] 594 | name = "socket2" 595 | version = "0.4.10" 596 | source = "registry+https://github.com/rust-lang/crates.io-index" 597 | checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" 598 | dependencies = [ 599 | "libc", 600 | "winapi", 601 | ] 602 | 603 | [[package]] 604 | name = "spin" 605 | version = "0.5.2" 606 | source = "registry+https://github.com/rust-lang/crates.io-index" 607 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 608 | 609 | [[package]] 610 | name = "stable_deref_trait" 611 | version = "1.2.0" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 614 | 615 | [[package]] 616 | name = "strsim" 617 | version = "0.11.1" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 620 | 621 | [[package]] 622 | name = "syn" 623 | version = "2.0.93" 624 | source = "registry+https://github.com/rust-lang/crates.io-index" 625 | checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058" 626 | dependencies = [ 627 | "proc-macro2", 628 | "quote", 629 | "unicode-ident", 630 | ] 631 | 632 | [[package]] 633 | name = "synstructure" 634 | version = "0.13.1" 635 | source = "registry+https://github.com/rust-lang/crates.io-index" 636 | checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" 637 | dependencies = [ 638 | "proc-macro2", 639 | "quote", 640 | "syn", 641 | ] 642 | 643 | [[package]] 644 | name = "thiserror" 645 | version = "1.0.69" 646 | source = "registry+https://github.com/rust-lang/crates.io-index" 647 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 648 | dependencies = [ 649 | "thiserror-impl", 650 | ] 651 | 652 | [[package]] 653 | name = "thiserror-impl" 654 | version = "1.0.69" 655 | source = "registry+https://github.com/rust-lang/crates.io-index" 656 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 657 | dependencies = [ 658 | "proc-macro2", 659 | "quote", 660 | "syn", 661 | ] 662 | 663 | [[package]] 664 | name = "tinystr" 665 | version = "0.7.6" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" 668 | dependencies = [ 669 | "displaydoc", 670 | "zerovec", 671 | ] 672 | 673 | [[package]] 674 | name = "toml" 675 | version = "0.7.8" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" 678 | dependencies = [ 679 | "serde", 680 | "serde_spanned", 681 | "toml_datetime", 682 | "toml_edit", 683 | ] 684 | 685 | [[package]] 686 | name = "toml_datetime" 687 | version = "0.6.8" 688 | source = "registry+https://github.com/rust-lang/crates.io-index" 689 | checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 690 | dependencies = [ 691 | "serde", 692 | ] 693 | 694 | [[package]] 695 | name = "toml_edit" 696 | version = "0.19.15" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" 699 | dependencies = [ 700 | "indexmap", 701 | "serde", 702 | "serde_spanned", 703 | "toml_datetime", 704 | "winnow", 705 | ] 706 | 707 | [[package]] 708 | name = "unicase" 709 | version = "2.8.1" 710 | source = "registry+https://github.com/rust-lang/crates.io-index" 711 | checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" 712 | 713 | [[package]] 714 | name = "unicode-ident" 715 | version = "1.0.14" 716 | source = "registry+https://github.com/rust-lang/crates.io-index" 717 | checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" 718 | 719 | [[package]] 720 | name = "untrusted" 721 | version = "0.7.1" 722 | source = "registry+https://github.com/rust-lang/crates.io-index" 723 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 724 | 725 | [[package]] 726 | name = "url" 727 | version = "2.5.4" 728 | source = "registry+https://github.com/rust-lang/crates.io-index" 729 | checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 730 | dependencies = [ 731 | "form_urlencoded", 732 | "idna", 733 | "percent-encoding", 734 | ] 735 | 736 | [[package]] 737 | name = "utf16_iter" 738 | version = "1.0.5" 739 | source = "registry+https://github.com/rust-lang/crates.io-index" 740 | checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" 741 | 742 | [[package]] 743 | name = "utf8_iter" 744 | version = "1.0.4" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 747 | 748 | [[package]] 749 | name = "utf8parse" 750 | version = "0.2.2" 751 | source = "registry+https://github.com/rust-lang/crates.io-index" 752 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 753 | 754 | [[package]] 755 | name = "vigil-local" 756 | version = "1.2.0" 757 | dependencies = [ 758 | "base64 0.21.7", 759 | "clap", 760 | "envsubst", 761 | "http_req", 762 | "lazy_static", 763 | "log", 764 | "ping", 765 | "run_script", 766 | "serde", 767 | "serde_derive", 768 | "serde_json", 769 | "toml", 770 | "url", 771 | ] 772 | 773 | [[package]] 774 | name = "wasi" 775 | version = "0.11.0+wasi-snapshot-preview1" 776 | source = "registry+https://github.com/rust-lang/crates.io-index" 777 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 778 | 779 | [[package]] 780 | name = "wasm-bindgen" 781 | version = "0.2.99" 782 | source = "registry+https://github.com/rust-lang/crates.io-index" 783 | checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" 784 | dependencies = [ 785 | "cfg-if", 786 | "once_cell", 787 | "wasm-bindgen-macro", 788 | ] 789 | 790 | [[package]] 791 | name = "wasm-bindgen-backend" 792 | version = "0.2.99" 793 | source = "registry+https://github.com/rust-lang/crates.io-index" 794 | checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" 795 | dependencies = [ 796 | "bumpalo", 797 | "log", 798 | "proc-macro2", 799 | "quote", 800 | "syn", 801 | "wasm-bindgen-shared", 802 | ] 803 | 804 | [[package]] 805 | name = "wasm-bindgen-macro" 806 | version = "0.2.99" 807 | source = "registry+https://github.com/rust-lang/crates.io-index" 808 | checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" 809 | dependencies = [ 810 | "quote", 811 | "wasm-bindgen-macro-support", 812 | ] 813 | 814 | [[package]] 815 | name = "wasm-bindgen-macro-support" 816 | version = "0.2.99" 817 | source = "registry+https://github.com/rust-lang/crates.io-index" 818 | checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" 819 | dependencies = [ 820 | "proc-macro2", 821 | "quote", 822 | "syn", 823 | "wasm-bindgen-backend", 824 | "wasm-bindgen-shared", 825 | ] 826 | 827 | [[package]] 828 | name = "wasm-bindgen-shared" 829 | version = "0.2.99" 830 | source = "registry+https://github.com/rust-lang/crates.io-index" 831 | checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" 832 | 833 | [[package]] 834 | name = "web-sys" 835 | version = "0.3.76" 836 | source = "registry+https://github.com/rust-lang/crates.io-index" 837 | checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" 838 | dependencies = [ 839 | "js-sys", 840 | "wasm-bindgen", 841 | ] 842 | 843 | [[package]] 844 | name = "webpki" 845 | version = "0.21.4" 846 | source = "registry+https://github.com/rust-lang/crates.io-index" 847 | checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" 848 | dependencies = [ 849 | "ring", 850 | "untrusted", 851 | ] 852 | 853 | [[package]] 854 | name = "webpki-roots" 855 | version = "0.21.1" 856 | source = "registry+https://github.com/rust-lang/crates.io-index" 857 | checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" 858 | dependencies = [ 859 | "webpki", 860 | ] 861 | 862 | [[package]] 863 | name = "winapi" 864 | version = "0.3.9" 865 | source = "registry+https://github.com/rust-lang/crates.io-index" 866 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 867 | dependencies = [ 868 | "winapi-i686-pc-windows-gnu", 869 | "winapi-x86_64-pc-windows-gnu", 870 | ] 871 | 872 | [[package]] 873 | name = "winapi-i686-pc-windows-gnu" 874 | version = "0.4.0" 875 | source = "registry+https://github.com/rust-lang/crates.io-index" 876 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 877 | 878 | [[package]] 879 | name = "winapi-x86_64-pc-windows-gnu" 880 | version = "0.4.0" 881 | source = "registry+https://github.com/rust-lang/crates.io-index" 882 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 883 | 884 | [[package]] 885 | name = "windows-sys" 886 | version = "0.59.0" 887 | source = "registry+https://github.com/rust-lang/crates.io-index" 888 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 889 | dependencies = [ 890 | "windows-targets", 891 | ] 892 | 893 | [[package]] 894 | name = "windows-targets" 895 | version = "0.52.6" 896 | source = "registry+https://github.com/rust-lang/crates.io-index" 897 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 898 | dependencies = [ 899 | "windows_aarch64_gnullvm", 900 | "windows_aarch64_msvc", 901 | "windows_i686_gnu", 902 | "windows_i686_gnullvm", 903 | "windows_i686_msvc", 904 | "windows_x86_64_gnu", 905 | "windows_x86_64_gnullvm", 906 | "windows_x86_64_msvc", 907 | ] 908 | 909 | [[package]] 910 | name = "windows_aarch64_gnullvm" 911 | version = "0.52.6" 912 | source = "registry+https://github.com/rust-lang/crates.io-index" 913 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 914 | 915 | [[package]] 916 | name = "windows_aarch64_msvc" 917 | version = "0.52.6" 918 | source = "registry+https://github.com/rust-lang/crates.io-index" 919 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 920 | 921 | [[package]] 922 | name = "windows_i686_gnu" 923 | version = "0.52.6" 924 | source = "registry+https://github.com/rust-lang/crates.io-index" 925 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 926 | 927 | [[package]] 928 | name = "windows_i686_gnullvm" 929 | version = "0.52.6" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 932 | 933 | [[package]] 934 | name = "windows_i686_msvc" 935 | version = "0.52.6" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 938 | 939 | [[package]] 940 | name = "windows_x86_64_gnu" 941 | version = "0.52.6" 942 | source = "registry+https://github.com/rust-lang/crates.io-index" 943 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 944 | 945 | [[package]] 946 | name = "windows_x86_64_gnullvm" 947 | version = "0.52.6" 948 | source = "registry+https://github.com/rust-lang/crates.io-index" 949 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 950 | 951 | [[package]] 952 | name = "windows_x86_64_msvc" 953 | version = "0.52.6" 954 | source = "registry+https://github.com/rust-lang/crates.io-index" 955 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 956 | 957 | [[package]] 958 | name = "winnow" 959 | version = "0.5.40" 960 | source = "registry+https://github.com/rust-lang/crates.io-index" 961 | checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" 962 | dependencies = [ 963 | "memchr", 964 | ] 965 | 966 | [[package]] 967 | name = "write16" 968 | version = "1.0.0" 969 | source = "registry+https://github.com/rust-lang/crates.io-index" 970 | checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" 971 | 972 | [[package]] 973 | name = "writeable" 974 | version = "0.5.5" 975 | source = "registry+https://github.com/rust-lang/crates.io-index" 976 | checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" 977 | 978 | [[package]] 979 | name = "yoke" 980 | version = "0.7.5" 981 | source = "registry+https://github.com/rust-lang/crates.io-index" 982 | checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" 983 | dependencies = [ 984 | "serde", 985 | "stable_deref_trait", 986 | "yoke-derive", 987 | "zerofrom", 988 | ] 989 | 990 | [[package]] 991 | name = "yoke-derive" 992 | version = "0.7.5" 993 | source = "registry+https://github.com/rust-lang/crates.io-index" 994 | checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" 995 | dependencies = [ 996 | "proc-macro2", 997 | "quote", 998 | "syn", 999 | "synstructure", 1000 | ] 1001 | 1002 | [[package]] 1003 | name = "zerocopy" 1004 | version = "0.7.35" 1005 | source = "registry+https://github.com/rust-lang/crates.io-index" 1006 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 1007 | dependencies = [ 1008 | "byteorder", 1009 | "zerocopy-derive", 1010 | ] 1011 | 1012 | [[package]] 1013 | name = "zerocopy-derive" 1014 | version = "0.7.35" 1015 | source = "registry+https://github.com/rust-lang/crates.io-index" 1016 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 1017 | dependencies = [ 1018 | "proc-macro2", 1019 | "quote", 1020 | "syn", 1021 | ] 1022 | 1023 | [[package]] 1024 | name = "zerofrom" 1025 | version = "0.1.5" 1026 | source = "registry+https://github.com/rust-lang/crates.io-index" 1027 | checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" 1028 | dependencies = [ 1029 | "zerofrom-derive", 1030 | ] 1031 | 1032 | [[package]] 1033 | name = "zerofrom-derive" 1034 | version = "0.1.5" 1035 | source = "registry+https://github.com/rust-lang/crates.io-index" 1036 | checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" 1037 | dependencies = [ 1038 | "proc-macro2", 1039 | "quote", 1040 | "syn", 1041 | "synstructure", 1042 | ] 1043 | 1044 | [[package]] 1045 | name = "zerovec" 1046 | version = "0.10.4" 1047 | source = "registry+https://github.com/rust-lang/crates.io-index" 1048 | checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" 1049 | dependencies = [ 1050 | "yoke", 1051 | "zerofrom", 1052 | "zerovec-derive", 1053 | ] 1054 | 1055 | [[package]] 1056 | name = "zerovec-derive" 1057 | version = "0.10.3" 1058 | source = "registry+https://github.com/rust-lang/crates.io-index" 1059 | checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" 1060 | dependencies = [ 1061 | "proc-macro2", 1062 | "quote", 1063 | "syn", 1064 | ] 1065 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vigil-local" 3 | version = "1.2.0" 4 | description = "Vigil Local daemon. Used as a slave service to monitor hosts behind a firewall and report their status to Vigil." 5 | readme = "README.md" 6 | license = "MPL-2.0" 7 | edition = "2018" 8 | homepage = "https://github.com/valeriansaliou/vigil-local" 9 | repository = "https://github.com/valeriansaliou/vigil-local.git" 10 | keywords = ["infrastructure", "status", "monitor"] 11 | categories = ["web-programming"] 12 | authors = ["Valerian Saliou "] 13 | 14 | [[bin]] 15 | name = "vigil-local" 16 | path = "src/main.rs" 17 | doc = false 18 | 19 | [dependencies] 20 | log = "0.4" 21 | clap = { version = "4.1", features = ["std", "cargo"] } 22 | lazy_static = "1.4" 23 | serde = { version = "1.0", default-features = false } 24 | serde_derive = "1.0" 25 | serde_json = "1.0" 26 | toml = "0.7" 27 | envsubst = "0.2" 28 | url = { version = "2.1", default-features = false } 29 | ping = "0.4" 30 | run_script = "0.10" 31 | http_req = { version = "0.9", features = ["rust-tls"], default-features = false } 32 | base64 = "0.21" 33 | 34 | [profile.dev] 35 | opt-level = 0 36 | debug = true 37 | debug-assertions = true 38 | 39 | [profile.release] 40 | opt-level = "s" 41 | lto = true 42 | debug = false 43 | debug-assertions = false 44 | panic = "abort" 45 | strip = true 46 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rustlang/rust:nightly-buster-slim AS build 2 | 3 | RUN apt-get update 4 | RUN apt-get install -y musl-tools 5 | 6 | RUN rustup --version 7 | RUN rustup target add x86_64-unknown-linux-musl 8 | 9 | RUN rustc --version && \ 10 | rustup --version && \ 11 | cargo --version 12 | 13 | WORKDIR /app 14 | COPY . /app 15 | RUN cargo clean && cargo build --release --target x86_64-unknown-linux-musl 16 | RUN strip ./target/x86_64-unknown-linux-musl/release/vigil-local 17 | 18 | FROM scratch 19 | 20 | WORKDIR /usr/src/vigil-local 21 | 22 | COPY --from=build /app/target/x86_64-unknown-linux-musl/release/vigil-local /usr/local/bin/vigil-local 23 | 24 | CMD [ "vigil-local", "-c", "/etc/vigil-local.cfg" ] 25 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | 6. Disclaimer of Warranty 262 | ------------------------- 263 | 264 | > Covered Software is provided under this License on an "as is" 265 | > basis, without warranty of any kind, either expressed, implied, or 266 | > statutory, including, without limitation, warranties that the 267 | > Covered Software is free of defects, merchantable, fit for a 268 | > particular purpose or non-infringing. The entire risk as to the 269 | > quality and performance of the Covered Software is with You. 270 | > Should any Covered Software prove defective in any respect, You 271 | > (not any Contributor) assume the cost of any necessary servicing, 272 | > repair, or correction. This disclaimer of warranty constitutes an 273 | > essential part of this License. No use of any Covered Software is 274 | > authorized under this License except under this disclaimer. 275 | 276 | 277 | 7. Limitation of Liability 278 | -------------------------- 279 | 280 | > Under no circumstances and under no legal theory, whether tort 281 | > (including negligence), contract, or otherwise, shall any 282 | > Contributor, or anyone who distributes Covered Software as 283 | > permitted above, be liable to You for any direct, indirect, 284 | > special, incidental, or consequential damages of any character 285 | > including, without limitation, damages for lost profits, loss of 286 | > goodwill, work stoppage, computer failure or malfunction, or any 287 | > and all other commercial damages or losses, even if such party 288 | > shall have been informed of the possibility of such damages. This 289 | > limitation of liability shall not apply to liability for death or 290 | > personal injury resulting from such party's negligence to the 291 | > extent applicable law prohibits such limitation. Some 292 | > jurisdictions do not allow the exclusion or limitation of 293 | > incidental or consequential damages, so this exclusion and 294 | > limitation may not apply to You. 295 | 296 | 8. Litigation 297 | ------------- 298 | 299 | Any litigation relating to this License may be brought only in the 300 | courts of a jurisdiction where the defendant maintains its principal 301 | place of business and such litigation shall be governed by laws of that 302 | jurisdiction, without reference to its conflict-of-law provisions. 303 | Nothing in this Section shall prevent a party's ability to bring 304 | cross-claims or counter-claims. 305 | 306 | 9. Miscellaneous 307 | ---------------- 308 | 309 | This License represents the complete agreement concerning the subject 310 | matter hereof. If any provision of this License is held to be 311 | unenforceable, such provision shall be reformed only to the extent 312 | necessary to make it enforceable. Any law or regulation which provides 313 | that the language of a contract shall be construed against the drafter 314 | shall not be used to construe this License against a Contributor. 315 | 316 | 10. Versions of the License 317 | --------------------------- 318 | 319 | 10.1. New Versions 320 | 321 | Mozilla Foundation is the license steward. Except as provided in Section 322 | 10.3, no one other than the license steward has the right to modify or 323 | publish new versions of this License. Each version will be given a 324 | distinguishing version number. 325 | 326 | 10.2. Effect of New Versions 327 | 328 | You may distribute the Covered Software under the terms of the version 329 | of the License under which You originally received the Covered Software, 330 | or under the terms of any subsequent version published by the license 331 | steward. 332 | 333 | 10.3. Modified Versions 334 | 335 | If you create software not governed by this License, and you want to 336 | create a new license for such software, you may create and use a 337 | modified version of this License if you rename the license and remove 338 | any references to the name of the license steward (except to note that 339 | such modified license differs from this License). 340 | 341 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 342 | Licenses 343 | 344 | If You choose to distribute Source Code Form that is Incompatible With 345 | Secondary Licenses under the terms of this version of the License, the 346 | notice described in Exhibit B of this License must be attached. 347 | 348 | Exhibit A - Source Code Form License Notice 349 | ------------------------------------------- 350 | 351 | This Source Code Form is subject to the terms of the Mozilla Public 352 | License, v. 2.0. If a copy of the MPL was not distributed with this 353 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 354 | 355 | If it is not possible or desirable to put the notice in a particular 356 | file, then You may include the notice in a location (such as a LICENSE 357 | file in a relevant directory) where a recipient would be likely to look 358 | for such a notice. 359 | 360 | You may add additional accurate notices of copyright ownership. 361 | 362 | Exhibit B - "Incompatible With Secondary Licenses" Notice 363 | --------------------------------------------------------- 364 | 365 | This Source Code Form is "Incompatible With Secondary Licenses", as 366 | defined by the Mozilla Public License, v. 2.0. 367 | -------------------------------------------------------------------------------- /PACKAGING.md: -------------------------------------------------------------------------------- 1 | Packaging 2 | ========= 3 | 4 | This file contains quick reminders and notes on how to package Vigil Local. 5 | 6 | We consider here the packaging flow of Vigil Local version `1.0.0` for Linux. 7 | 8 | 1. **How to bump Vigil Local version before a release:** 9 | 1. Bump version in `Cargo.toml` to `1.0.0` 10 | 2. Execute `cargo update` to bump `Cargo.lock` 11 | 3. Bump Debian package version in `debian/rules` to `1.0.0` 12 | 13 | 2. **How to build Vigil Local, package it and release it on Crates, GitHub, Docker Hub and Packagecloud (multiple architectures):** 14 | 1. Tag the latest Git commit corresponding to the release with tag `v1.0.0`, and push the tag 15 | 2. Wait for all release jobs to complete on the [actions](https://github.com/valeriansaliou/vigil-local/actions) page on GitHub 16 | 3. Download all release archives, and sign them locally using: `./scripts/sign_binaries.sh --version=1.0.0` 17 | 4. Publish a changelog and upload all the built archives, as well as their signatures on the [releases](https://github.com/valeriansaliou/vigil-local/releases) page on GitHub 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Vigil Local 2 | =========== 3 | 4 | [![Test and Build](https://github.com/valeriansaliou/vigil-local/workflows/Test%20and%20Build/badge.svg?branch=master)](https://github.com/valeriansaliou/vigil-local/actions?query=workflow%3A%22Test+and+Build%22) [![Build and Release](https://github.com/valeriansaliou/vigil-local/workflows/Build%20and%20Release/badge.svg)](https://github.com/valeriansaliou/vigil-local/actions?query=workflow%3A%22Build+and+Release%22) [![dependency status](https://deps.rs/repo/github/valeriansaliou/vigil-local/status.svg)](https://deps.rs/repo/github/valeriansaliou/vigil-local) [![Buy Me A Coffee](https://img.shields.io/badge/buy%20me%20a%20coffee-donate-yellow.svg)](https://www.buymeacoffee.com/valeriansaliou) 5 | 6 | **Vigil Local daemon. Used as a slave service to monitor hosts behind a firewall and report their status to Vigil.** 7 | 8 | Vigil Local is an (optional) slave daemon that you can use to report internal service health to your [Vigil-powered status page](https://github.com/valeriansaliou/vigil) master server. It is designed to be used behind a firewall, and _**to monitor hosts bound to a local loop or LAN network, that are not available to your main Vigil status page**_. It can prove useful as well if you want to fully isolate your Vigil status page from your internal services. 9 | 10 | Install Vigil Local on a server of yours and configure it with your Vigil endpoint URL and token; it will then start monitoring all configured nodes and report them to Vigil. Make sure that you pre-configure all local nodes as `local` in Vigil, and then as `poll` or `script` in Vigil Local, accordingly. The service identifier and node identifier must match on either sides, as they will be used to identify the replica status being reported from the Vigil Local slave to the Vigil master. 11 | 12 | Multiple slave daemons can run on separate servers or networks, and report a group of services and nodes to the same Vigil master. Make sure that multiple slaves are not double-reporting replicas on the same monitored service/node pair. 13 | 14 | _Tested at Rust version: `rustc 1.62.0 (a8314ef7d 2022-06-27)`_ 15 | 16 | **🇧🇬 Crafted in Sofia, Bulgaria.** 17 | 18 | ## What is Vigil? 19 | 20 | [Vigil is an open-source Status Page](https://github.com/valeriansaliou/vigil) you can host on your infrastructure, used to monitor all your servers and apps, and visible to your users. 21 | 22 | It lets you monitor your critical systems using a variety of methods: `push` for applications using a Vigil Reporter library, `poll` for Vigil-reachable HTTP, TCP & ICMP services, `script` to execute custom probes, and `local` for non-Vigil-reachable private services. 23 | 24 | Vigil Local lets you monitor nodes that are configured in `local` mode (in Vigil), aside other monitoring methods that do not require the Vigil Local utility (and thus can run on Vigil itself right away). 25 | 26 | ## How to use it? 27 | 28 | ### Installation 29 | 30 | **Install from binary:** 31 | 32 | A pre-built binary of Vigil Local is shared in the releases on GitHub. You can simply download the latest binary version from the [releases page](https://github.com/valeriansaliou/vigil-local/releases), and run it on your server. 33 | 34 | You will still need to provide the binary with the configuration file, so make sure you have a Vigil Local `config.cfg` file ready somewhere. 35 | 36 | _The binary provided is statically-linked, which means that it will be able to run on any Linux-based server. Still, it will not work on MacOS or Windows machines._ 37 | 38 | 👉 _Each release binary comes with an `.asc` signature file, which can be verified using [@valeriansaliou](https://github.com/valeriansaliou) GPG public key: [:key:valeriansaliou.gpg.pub.asc](https://valeriansaliou.name/files/keys/valeriansaliou.gpg.pub.asc)._ 39 | 40 | **Install from packages:** 41 | 42 | Vigil Local provides [pre-built packages](https://packagecloud.io/valeriansaliou/vigil-local) for Debian-based systems (Debian, Ubuntu, etc.). 43 | 44 | **Important: Vigil Local only provides 64 bits packages targeting Debian 10, 11 & 12 for now (codenames: `buster`, `bullseye` & `bookworm`). You will still be able to use them on other Debian versions, as well as Ubuntu.** 45 | 46 | First, add the Vigil Local APT repository (eg. for Debian `bookworm`): 47 | 48 | ```bash 49 | echo "deb [signed-by=/usr/share/keyrings/valeriansaliou_vigil-local.gpg] https://packagecloud.io/valeriansaliou/vigil-local/debian/ bookworm main" > /etc/apt/sources.list.d/valeriansaliou_vigil-local.list 50 | ``` 51 | 52 | ```bash 53 | curl -fsSL https://packagecloud.io/valeriansaliou/vigil-local/gpgkey | gpg --dearmor -o /usr/share/keyrings/valeriansaliou_vigil-local.gpg 54 | ``` 55 | 56 | ```bash 57 | apt-get update 58 | ``` 59 | 60 | Then, install the Vigil Local package: 61 | 62 | ```bash 63 | apt-get install vigil-local 64 | ``` 65 | 66 | Then, edit the pre-filled Vigil Local configuration file: 67 | 68 | ```bash 69 | nano /etc/vigil-local.cfg 70 | ``` 71 | 72 | Finally, restart Vigil Local: 73 | 74 | ``` 75 | service vigil-local restart 76 | ``` 77 | 78 | **Install from Cargo:** 79 | 80 | If you prefer managing `vigil-local` via Rust's Cargo, install it directly via `cargo install`: 81 | 82 | ```bash 83 | cargo install vigil-local 84 | ``` 85 | 86 | Ensure that your `$PATH` is properly configured to source the Crates binaries, and then run Vigil Local using the `vigil-local` command. 87 | 88 | **Install from source:** 89 | 90 | The last option is to pull the source code from Git and compile Vigil Local via `cargo`: 91 | 92 | ```bash 93 | cargo build --release 94 | ``` 95 | 96 | You can find the built binaries in the `./target/release` directory. 97 | 98 | **Install from Docker Hub:** 99 | 100 | You might find it convenient to run Vigil Local via Docker. You can find the pre-built Vigil Local image on Docker Hub as [valeriansaliou/vigil-local](https://hub.docker.com/r/valeriansaliou/vigil-local/). 101 | 102 | First, pull the `valeriansaliou/vigil-local` image: 103 | 104 | ```bash 105 | docker pull valeriansaliou/vigil-local:v1.2.0 106 | ``` 107 | 108 | Then, seed it a configuration file and run it (replace `/path/to/your/vigil-local/config.cfg` with the path to your configuration file): 109 | 110 | ```bash 111 | docker run -v /path/to/your/vigil-local/config.cfg:/etc/vigil-local.cfg valeriansaliou/vigil-local:v1.2.0 112 | ``` 113 | 114 | ### Configuration 115 | 116 | Use the sample [config.cfg](https://github.com/valeriansaliou/vigil-local/blob/master/config.cfg) configuration file and adjust it to your own environment. 117 | 118 | You can also use environment variables with string interpolation in your configuration file, eg. `token = ${VIGIL_TOKEN}`. 119 | 120 | **Available configuration options are commented below, with allowed values:** 121 | 122 | **[server]** 123 | 124 | * `log_level` (type: _string_, allowed: `debug`, `info`, `warn`, `error`, default: `error`) — Verbosity of logging, set it to `error` in production 125 | 126 | **[report]** 127 | 128 | * `endpoint` (type: _string_, allowed: URL, no default) — Vigil status page master reporting URL (can be public via eg. HTTPS, or private over LAN; without trailing slash, eg. `https://status.example.com`) 129 | * `token` (type: _string_, allowed: any string, no default) — Your master Vigil Reporter token (as configured in Vigil) 130 | 131 | **[metrics]** 132 | 133 | * `interval` (type: _integer_, allowed: seconds, default: `120`) — Interval for which to probe nodes in `poll` and `script` mode (ie. all nodes) 134 | * `poll_retry` (type: _integer_, allowed: seconds, default: `2`) — Interval after which to try probe for a second time nodes in `poll` mode (only when the first check fails) 135 | * `poll_delay_dead` (type: _integer_, allowed: seconds, default: `10`) — Delay after which a node in `poll` mode is to be considered `dead` (ie. check response delay) 136 | * `poll_delay_sick` (type: _integer_, allowed: seconds, default: `1`) — Delay after which a node in `poll` mode is to be considered `sick` (ie. check response delay) 137 | 138 | **[probe]** 139 | 140 | **[[probe.service]]** 141 | 142 | * `id` (type: _string_, allowed: any unique lowercase string, no default) — Unique identifier of the probed service 143 | 144 | **[[probe.service.node]]** 145 | 146 | * `id` (type: _string_, allowed: any unique lowercase string, no default) — Unique identifier of the probed service node 147 | * `mode` (type: _string_, allowed: `poll`, `script`, no default) — Probe mode for this node (ie. `poll` is direct HTTP, TCP or ICMP poll to the URLs set in `replicas`, while `script` is used to execute a shell script) 148 | * `replicas` (type: _array[string]_, allowed: TCP, ICMP or HTTP URLs, default: empty) — Node replica URLs to be probed (only used if `mode` is `poll`) 149 | * `scripts` (type: _array[string]_, allowed: shell scripts as source code, default: empty) — Shell scripts to be executed on the system as a Vigil Local sub-process; they are handy to build custom probes (only used if `mode` is `script`) 150 | 151 | ### Run 152 | 153 | Vigil Local can be run as such: 154 | 155 | `./vigil-local -c /path/to/config.cfg` 156 | 157 | ## :fire: Report A Vulnerability 158 | 159 | If you find a vulnerability in Vigil Local, you are more than welcome to report it directly to [@valeriansaliou](https://github.com/valeriansaliou) by sending an encrypted email to [valerian@valeriansaliou.name](mailto:valerian@valeriansaliou.name). Do not report vulnerabilities in public GitHub issues, as they may be exploited by malicious people to target production servers running an unpatched Vigil Local daemon. 160 | 161 | **:warning: You must encrypt your email using [@valeriansaliou](https://github.com/valeriansaliou) GPG public key: [:key:valeriansaliou.gpg.pub.asc](https://valeriansaliou.name/files/keys/valeriansaliou.gpg.pub.asc).** 162 | -------------------------------------------------------------------------------- /config.cfg: -------------------------------------------------------------------------------- 1 | # Vigil Local 2 | # Vigil local probe relay 3 | # Configuration file 4 | # Example: https://github.com/valeriansaliou/vigil-local/blob/master/config.cfg 5 | 6 | 7 | [server] 8 | 9 | log_level = "debug" 10 | 11 | [report] 12 | 13 | endpoint = "https://status.example.com" 14 | token = "YOUR_TOKEN_SECRET" 15 | 16 | [metrics] 17 | 18 | interval = 120 19 | 20 | poll_retry = 2 21 | 22 | poll_delay_dead = 10 23 | poll_delay_sick = 1 24 | 25 | [probe] 26 | 27 | [[probe.service]] 28 | 29 | id = "internal" 30 | 31 | [[probe.service.node]] 32 | 33 | id = "gateway" 34 | mode = "poll" 35 | 36 | replicas = [ 37 | "icmp://127.0.0.1", 38 | "icmp://192.168.1.1" 39 | ] 40 | 41 | [[probe.service.node]] 42 | 43 | id = "capacity" 44 | mode = "script" 45 | 46 | scripts = [ 47 | ''' 48 | # Consider as healthy 49 | exit 0 50 | ''' 51 | ] 52 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | vigil-local (0.0.0-1) UNRELEASED; urgency=medium 2 | 3 | * Initial release. 4 | 5 | -- Valerian Saliou Tue, 31 Aug 2023 12:00:00 +0000 6 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 10 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: vigil-local 2 | Section: net 3 | Priority: ext 4 | Maintainer: Valerian Saliou 5 | Standards-Version: 3.9.4 6 | Build-Depends: wget, ca-certificates 7 | Homepage: https://github.com/valeriansaliou/vigil-local 8 | 9 | Package: vigil-local 10 | Architecture: any 11 | Depends: adduser 12 | Provides: vigil-local 13 | Description: Vigil Local daemon. Used as a slave service to monitor hosts behind a firewall and report their status to Vigil. 14 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: vigil-local 3 | Upstream-Contact: Valerian Saliou 4 | Source: https://github.com/valeriansaliou/vigil-local 5 | 6 | Files: * 7 | Copyright: 2023 Valerian Saliou 8 | License: MPL-2 9 | 10 | License: MPL-2 11 | This Source Code Form is subject to the terms of the Mozilla Public License, 12 | v. 2.0. If a copy of the MPL was not distributed with this file, 13 | You can obtain one at http://mozilla.org/MPL/2.0/. 14 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | DISTRIBUTION = $(shell lsb_release -sr) 4 | VERSION = 1.2.0 5 | PACKAGEVERSION = $(VERSION)-0~$(DISTRIBUTION)0 6 | URL = https://github.com/valeriansaliou/vigil-local/releases/download/v$(VERSION)/ 7 | 8 | %: 9 | dh $@ --with systemd 10 | 11 | override_dh_auto_clean: 12 | override_dh_auto_test: 13 | override_dh_auto_build: 14 | override_dh_auto_install: 15 | $(eval ENV_ARCH := $(shell dpkg --print-architecture)) 16 | $(eval ENV_ISA := $(shell if [ "$(ENV_ARCH)" = "amd64" ]; then echo "x86_64"; else echo "$(ENV_ARCH)"; fi)) 17 | $(eval ENV_TARBALL := v$(VERSION)-$(ENV_ISA).tar.gz) 18 | 19 | echo "Architecture: $(ENV_ARCH)" 20 | echo "Instruction Set: $(ENV_ISA)" 21 | echo "Target: $(URL)$(ENV_TARBALL)" 22 | 23 | wget -N --progress=dot:mega $(URL)$(ENV_TARBALL) 24 | tar -xf $(ENV_TARBALL) 25 | strip vigil-local/vigil-local 26 | mv vigil-local/config.cfg vigil-local/vigil-local.cfg 27 | 28 | override_dh_gencontrol: 29 | dh_gencontrol -- -v$(PACKAGEVERSION) 30 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /debian/vigil-local.install: -------------------------------------------------------------------------------- 1 | vigil-local/vigil-local usr/bin/ 2 | vigil-local/vigil-local.cfg etc/ 3 | -------------------------------------------------------------------------------- /debian/vigil-local.postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | case "$1" in 6 | configure) 7 | adduser --system --disabled-password --disabled-login --home /var/empty \ 8 | --no-create-home --quiet --group vigil-local 9 | ;; 10 | esac 11 | 12 | #DEBHELPER# 13 | 14 | exit 0 15 | -------------------------------------------------------------------------------- /debian/vigil-local.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Vigil Local reporter daemon 3 | After=network.target 4 | 5 | [Service] 6 | Type=simple 7 | User=vigil-local 8 | Group=vigil-local 9 | ExecStart=/usr/bin/vigil-local -c /etc/vigil-local.cfg 10 | Restart=on-failure 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /scripts/build_packages.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## 4 | # Vigil Local 5 | # 6 | # Vigil local probe relay 7 | # Copyright: 2023, Valerian Saliou 8 | # License: Mozilla Public License v2.0 (MPL v2.0) 9 | ## 10 | 11 | # Define build pipeline 12 | function build_for_target { 13 | OS="$2" DIST="$3" ARCH="$1" ./packpack/packpack 14 | release_result=$? 15 | 16 | if [ $release_result -eq 0 ]; then 17 | mkdir -p "./packages/$2_$3/" 18 | mv ./build/*$4 "./packages/$2_$3/" 19 | 20 | echo "Result: Packaged architecture: $1 for OS: $2:$3 (*$4)" 21 | fi 22 | 23 | return $release_result 24 | } 25 | 26 | # Run release tasks 27 | ABSPATH=$(cd "$(dirname "$0")"; pwd) 28 | BASE_DIR="$ABSPATH/../" 29 | 30 | rc=0 31 | 32 | pushd "$BASE_DIR" > /dev/null 33 | echo "Executing packages build steps for Vigil Local..." 34 | 35 | # Initialize `packpack` 36 | rm -rf ./packpack && \ 37 | git clone https://github.com/packpack/packpack.git packpack 38 | rc=$? 39 | 40 | # Proceed build for each target? 41 | if [ $rc -eq 0 ]; then 42 | build_for_target "x86_64" "debian" "buster" ".deb" && \ 43 | build_for_target "x86_64" "debian" "bullseye" ".deb" && \ 44 | build_for_target "x86_64" "debian" "bookworm" ".deb" 45 | rc=$? 46 | fi 47 | 48 | # Cleanup environment 49 | rm -rf ./build ./packpack 50 | 51 | if [ $rc -eq 0 ]; then 52 | echo "Success: Done executing packages build steps for Vigil Local" 53 | else 54 | echo "Error: Failed executing packages build steps for Vigil Local" 55 | fi 56 | popd > /dev/null 57 | 58 | exit $rc 59 | -------------------------------------------------------------------------------- /scripts/release_binaries.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## 4 | # Vigil Local 5 | # 6 | # Vigil local probe relay 7 | # Copyright: 2020, Valerian Saliou 8 | # License: Mozilla Public License v2.0 (MPL v2.0) 9 | ## 10 | 11 | # Read arguments 12 | while [ "$1" != "" ]; do 13 | argument_key=`echo $1 | awk -F= '{print $1}'` 14 | argument_value=`echo $1 | awk -F= '{print $2}'` 15 | 16 | case $argument_key in 17 | -v | --version) 18 | # Notice: strip any leading 'v' to the version number 19 | VIGIL_LOCAL_VERSION="${argument_value/v}" 20 | ;; 21 | *) 22 | echo "Unknown argument received: '$argument_key'" 23 | exit 1 24 | ;; 25 | esac 26 | 27 | shift 28 | done 29 | 30 | # Ensure release version is provided 31 | if [ -z "$VIGIL_LOCAL_VERSION" ]; then 32 | echo "No Vigil Local release version was provided, please provide it using '--version'" 33 | 34 | exit 1 35 | fi 36 | 37 | # Define release pipeline 38 | function release_for_architecture { 39 | final_tar="v$VIGIL_LOCAL_VERSION-$1.tar.gz" 40 | 41 | rm -rf ./vigil-local/ && \ 42 | cross build --target "$2" --release && \ 43 | mkdir ./vigil-local && \ 44 | cp -p "target/$2/release/vigil-local" ./vigil-local/ && \ 45 | cp ./config.cfg vigil-local/ && \ 46 | tar --owner=0 --group=0 -czvf "$final_tar" ./vigil-local && \ 47 | rm -r ./vigil-local/ 48 | release_result=$? 49 | 50 | if [ $release_result -eq 0 ]; then 51 | echo "Result: Packed architecture: $1 to file: $final_tar" 52 | fi 53 | 54 | return $release_result 55 | } 56 | 57 | # Run release tasks 58 | ABSPATH=$(cd "$(dirname "$0")"; pwd) 59 | BASE_DIR="$ABSPATH/../" 60 | 61 | rc=0 62 | 63 | pushd "$BASE_DIR" > /dev/null 64 | echo "Executing release steps for Vigil Local v$VIGIL_LOCAL_VERSION..." 65 | 66 | release_for_architecture "x86_64" "x86_64-unknown-linux-musl" && \ 67 | release_for_architecture "armv7" "armv7-unknown-linux-musleabihf" 68 | rc=$? 69 | 70 | if [ $rc -eq 0 ]; then 71 | echo "Success: Done executing release steps for Vigil Local v$VIGIL_LOCAL_VERSION" 72 | else 73 | echo "Error: Failed executing release steps for Vigil Local v$VIGIL_LOCAL_VERSION" 74 | fi 75 | popd > /dev/null 76 | 77 | exit $rc 78 | -------------------------------------------------------------------------------- /scripts/sign_binaries.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## 4 | # Vigil Local 5 | # 6 | # Vigil local probe relay 7 | # Copyright: 2022, Valerian Saliou 8 | # License: Mozilla Public License v2.0 (MPL v2.0) 9 | ## 10 | 11 | # Read arguments 12 | while [ "$1" != "" ]; do 13 | argument_key=`echo $1 | awk -F= '{print $1}'` 14 | argument_value=`echo $1 | awk -F= '{print $2}'` 15 | 16 | case $argument_key in 17 | -v | --version) 18 | # Notice: strip any leading 'v' to the version number 19 | VIGIL_LOCAL_VERSION="${argument_value/v}" 20 | ;; 21 | *) 22 | echo "Unknown argument received: '$argument_key'" 23 | exit 1 24 | ;; 25 | esac 26 | 27 | shift 28 | done 29 | 30 | # Ensure release version is provided 31 | if [ -z "$VIGIL_LOCAL_VERSION" ]; then 32 | echo "No Vigil Local release version was provided, please provide it using '--version'" 33 | 34 | exit 1 35 | fi 36 | 37 | # Define sign pipeline 38 | function sign_for_architecture { 39 | final_tar="v$VIGIL_LOCAL_VERSION-$1.tar.gz" 40 | gpg_signer="valerian@valeriansaliou.name" 41 | 42 | gpg -u "$gpg_signer" --armor --detach-sign "$final_tar" 43 | sign_result=$? 44 | 45 | if [ $sign_result -eq 0 ]; then 46 | echo "Result: Signed architecture: $1 for file: $final_tar" 47 | fi 48 | 49 | return $sign_result 50 | } 51 | 52 | # Run sign tasks 53 | ABSPATH=$(cd "$(dirname "$0")"; pwd) 54 | BASE_DIR="$ABSPATH/../" 55 | 56 | rc=0 57 | 58 | pushd "$BASE_DIR" > /dev/null 59 | echo "Executing sign steps for Vigil Local v$VIGIL_LOCAL_VERSION..." 60 | 61 | sign_for_architecture "x86_64" && \ 62 | sign_for_architecture "armv7" 63 | rc=$? 64 | 65 | if [ $rc -eq 0 ]; then 66 | echo "Success: Done executing sign steps for Vigil Local v$VIGIL_LOCAL_VERSION" 67 | else 68 | echo "Error: Failed executing sign steps for Vigil Local v$VIGIL_LOCAL_VERSION" 69 | fi 70 | popd > /dev/null 71 | 72 | exit $rc 73 | -------------------------------------------------------------------------------- /src/config/config.rs: -------------------------------------------------------------------------------- 1 | // Vigil Local 2 | // 3 | // Vigil local probe relay 4 | // Copyright: 2020, Valerian Saliou 5 | // License: Mozilla Public License v2.0 (MPL v2.0) 6 | 7 | use super::defaults; 8 | use crate::probe::mode::Mode; 9 | use crate::probe::replica::ReplicaURL; 10 | 11 | #[derive(Deserialize)] 12 | pub struct Config { 13 | pub server: ConfigServer, 14 | pub report: ConfigReport, 15 | pub metrics: ConfigMetrics, 16 | pub probe: ConfigProbe, 17 | } 18 | 19 | #[derive(Deserialize)] 20 | pub struct ConfigServer { 21 | #[serde(default = "defaults::server_log_level")] 22 | pub log_level: String, 23 | } 24 | 25 | #[derive(Deserialize)] 26 | pub struct ConfigReport { 27 | pub endpoint: String, 28 | pub token: String, 29 | } 30 | 31 | #[derive(Deserialize)] 32 | pub struct ConfigMetrics { 33 | #[serde(default = "defaults::metrics_interval")] 34 | pub interval: u64, 35 | 36 | #[serde(default = "defaults::metrics_poll_retry")] 37 | pub poll_retry: u8, 38 | 39 | #[serde(default = "defaults::metrics_poll_delay_dead")] 40 | pub poll_delay_dead: u64, 41 | 42 | #[serde(default = "defaults::metrics_poll_delay_sick")] 43 | pub poll_delay_sick: u64, 44 | } 45 | 46 | #[derive(Deserialize)] 47 | pub struct ConfigProbe { 48 | pub service: Vec, 49 | } 50 | 51 | #[derive(Deserialize)] 52 | pub struct ConfigProbeService { 53 | pub id: String, 54 | pub node: Vec, 55 | } 56 | 57 | #[derive(Deserialize)] 58 | pub struct ConfigProbeServiceNode { 59 | pub id: String, 60 | pub mode: Mode, 61 | pub replicas: Option>, 62 | pub scripts: Option>, 63 | } 64 | -------------------------------------------------------------------------------- /src/config/defaults.rs: -------------------------------------------------------------------------------- 1 | // Vigil Local 2 | // 3 | // Vigil local probe relay 4 | // Copyright: 2020, Valerian Saliou 5 | // License: Mozilla Public License v2.0 (MPL v2.0) 6 | 7 | pub fn server_log_level() -> String { 8 | "error".to_string() 9 | } 10 | 11 | pub fn metrics_interval() -> u64 { 12 | 120 13 | } 14 | 15 | pub fn metrics_poll_retry() -> u8 { 16 | 2 17 | } 18 | 19 | pub fn metrics_poll_delay_dead() -> u64 { 20 | 10 21 | } 22 | 23 | pub fn metrics_poll_delay_sick() -> u64 { 24 | 1 25 | } 26 | -------------------------------------------------------------------------------- /src/config/logger.rs: -------------------------------------------------------------------------------- 1 | // Vigil Local 2 | // 3 | // Vigil local probe relay 4 | // Copyright: 2020, Valerian Saliou 5 | // License: Mozilla Public License v2.0 (MPL v2.0) 6 | 7 | use log::{self, Level, LevelFilter, Log, Metadata, Record, SetLoggerError}; 8 | 9 | pub struct ConfigLogger; 10 | 11 | impl Log for ConfigLogger { 12 | fn enabled(&self, metadata: &Metadata) -> bool { 13 | metadata.level() <= Level::Debug 14 | } 15 | 16 | fn log(&self, record: &Record) { 17 | if self.enabled(record.metadata()) { 18 | println!("({}) - {}", record.level(), record.args()); 19 | } 20 | } 21 | 22 | fn flush(&self) {} 23 | } 24 | 25 | impl ConfigLogger { 26 | pub fn init(level: LevelFilter) -> Result<(), SetLoggerError> { 27 | log::set_max_level(level); 28 | log::set_logger(&ConfigLogger) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/config/mod.rs: -------------------------------------------------------------------------------- 1 | // Vigil Local 2 | // 3 | // Vigil local probe relay 4 | // Copyright: 2020, Valerian Saliou 5 | // License: Mozilla Public License v2.0 (MPL v2.0) 6 | 7 | mod defaults; 8 | 9 | pub mod config; 10 | pub mod logger; 11 | pub mod reader; 12 | -------------------------------------------------------------------------------- /src/config/reader.rs: -------------------------------------------------------------------------------- 1 | // Vigil Local 2 | // 3 | // Vigil local probe relay 4 | // Copyright: 2020, Valerian Saliou 5 | // License: Mozilla Public License v2.0 (MPL v2.0) 6 | 7 | use std::{collections::HashMap, env, fs}; 8 | 9 | use envsubst::substitute; 10 | use toml; 11 | 12 | use super::config::*; 13 | use crate::APP_ARGS; 14 | 15 | pub struct ConfigReader; 16 | 17 | impl ConfigReader { 18 | pub fn make() -> Config { 19 | debug!("reading config file: {}", &APP_ARGS.config); 20 | 21 | // Read configuration 22 | let mut conf = fs::read_to_string(&APP_ARGS.config).expect("cannot find config file"); 23 | 24 | debug!("read config file: {}", &APP_ARGS.config); 25 | 26 | // Replace environment variables 27 | let environment = env::vars().collect::>(); 28 | 29 | conf = substitute(&conf, &environment).expect("cannot substitute environment variables"); 30 | 31 | // Parse configuration 32 | toml::from_str(&conf).expect("syntax error in config file") 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | // Vigil Local 2 | // 3 | // Vigil local probe relay 4 | // Copyright: 2020, Valerian Saliou 5 | // License: Mozilla Public License v2.0 (MPL v2.0) 6 | 7 | #[macro_use] 8 | extern crate log; 9 | #[macro_use] 10 | extern crate lazy_static; 11 | #[macro_use] 12 | extern crate serde_derive; 13 | 14 | mod config; 15 | mod probe; 16 | 17 | use std::ops::Deref; 18 | use std::str::FromStr; 19 | use std::thread; 20 | use std::time::Duration; 21 | 22 | use clap::{Arg, Command}; 23 | use log::LevelFilter; 24 | 25 | use config::config::Config; 26 | use config::logger::ConfigLogger; 27 | use config::reader::ConfigReader; 28 | use probe::manager::run as run_probe; 29 | 30 | struct AppArgs { 31 | config: String, 32 | } 33 | 34 | pub static THREAD_NAME_PROBE: &'static str = "vigil-local-probe"; 35 | 36 | lazy_static! { 37 | static ref APP_ARGS: AppArgs = make_app_args(); 38 | static ref APP_CONF: Config = ConfigReader::make(); 39 | } 40 | 41 | fn make_app_args() -> AppArgs { 42 | let matches = Command::new(clap::crate_name!()) 43 | .version(clap::crate_version!()) 44 | .author(clap::crate_authors!()) 45 | .about(clap::crate_description!()) 46 | .arg( 47 | Arg::new("config") 48 | .short('c') 49 | .long("config") 50 | .help("Path to configuration file") 51 | .default_value("./config.cfg"), 52 | ) 53 | .get_matches(); 54 | 55 | // Generate owned app arguments 56 | AppArgs { 57 | config: matches 58 | .get_one::("config") 59 | .expect("invalid config value") 60 | .to_owned(), 61 | } 62 | } 63 | 64 | fn ensure_states() { 65 | // Ensure all statics are valid (a `deref` is enough to lazily initialize them) 66 | let (_, _) = (APP_ARGS.deref(), APP_CONF.deref()); 67 | } 68 | 69 | fn spawn_probe() { 70 | debug!("spawn managed thread: probe"); 71 | 72 | let worker = thread::Builder::new() 73 | .name(THREAD_NAME_PROBE.to_string()) 74 | .spawn(run_probe); 75 | 76 | // Block on worker thread (join it) 77 | let has_error = if let Ok(worker_thread) = worker { 78 | worker_thread.join().is_err() 79 | } else { 80 | true 81 | }; 82 | 83 | // Worker thread crashed? 84 | if has_error == true { 85 | error!("managed thread crashed (probe), setting it up again"); 86 | 87 | // Prevents thread start loop floods 88 | // Notice: 5 seconds here to prevent network floods 89 | thread::sleep(Duration::from_secs(5)); 90 | 91 | spawn_probe(); 92 | } 93 | } 94 | 95 | fn main() { 96 | // Initialize shared logger 97 | let _logger = ConfigLogger::init( 98 | LevelFilter::from_str(&APP_CONF.server.log_level).expect("invalid log level"), 99 | ); 100 | 101 | info!("starting up"); 102 | 103 | // Ensure all states are bound 104 | ensure_states(); 105 | 106 | // Spawn probe (foreground thread) 107 | spawn_probe(); 108 | 109 | error!("could not start"); 110 | } 111 | -------------------------------------------------------------------------------- /src/probe/manager.rs: -------------------------------------------------------------------------------- 1 | // Vigil Local 2 | // 3 | // Vigil local probe relay 4 | // Copyright: 2020, Valerian Saliou 5 | // License: Mozilla Public License v2.0 (MPL v2.0) 6 | 7 | use std::thread; 8 | use std::time::Duration; 9 | 10 | use super::poll::dispatch as poll_dispatch; 11 | use super::script::dispatch as script_dispatch; 12 | use crate::probe::mode::Mode; 13 | use crate::APP_CONF; 14 | 15 | const PROBE_RUN_HOLD_SECONDS: u64 = 2; 16 | 17 | pub fn run() { 18 | // Hold on a bit before first cycle 19 | thread::sleep(Duration::from_secs(PROBE_RUN_HOLD_SECONDS)); 20 | 21 | debug!("will run first probe cycle"); 22 | 23 | // Start cycling 24 | loop { 25 | cycle(); 26 | 27 | info!( 28 | "done cycling probe, holding for next cycle: {}s", 29 | APP_CONF.metrics.interval 30 | ); 31 | 32 | // Hold for next aggregate run 33 | thread::sleep(Duration::from_secs(APP_CONF.metrics.interval)); 34 | 35 | debug!("holding for next probe cycle, will run next cycle"); 36 | } 37 | } 38 | 39 | fn cycle() { 40 | debug!("cycling through all services"); 41 | 42 | for service in &APP_CONF.probe.service { 43 | debug!("scanning for nodes in service: #{}", service.id); 44 | 45 | for node in &service.node { 46 | debug!("scanning for targets in service node: #{}", node.id); 47 | 48 | match node.mode { 49 | Mode::Poll => poll_dispatch(service, node, APP_CONF.metrics.interval), 50 | Mode::Script => script_dispatch(service, node, APP_CONF.metrics.interval), 51 | } 52 | } 53 | } 54 | 55 | info!("done cycling through all services"); 56 | } 57 | -------------------------------------------------------------------------------- /src/probe/mod.rs: -------------------------------------------------------------------------------- 1 | // Vigil Local 2 | // 3 | // Vigil local probe relay 4 | // Copyright: 2020, Valerian Saliou 5 | // License: Mozilla Public License v2.0 (MPL v2.0) 6 | 7 | mod status; 8 | 9 | pub mod manager; 10 | pub mod mode; 11 | pub mod poll; 12 | pub mod replica; 13 | pub mod report; 14 | pub mod script; 15 | -------------------------------------------------------------------------------- /src/probe/mode.rs: -------------------------------------------------------------------------------- 1 | // Vigil Local 2 | // 3 | // Vigil local probe relay 4 | // Copyright: 2020, Valerian Saliou 5 | // License: Mozilla Public License v2.0 (MPL v2.0) 6 | 7 | #[derive(Deserialize)] 8 | pub enum Mode { 9 | #[serde(rename = "poll")] 10 | Poll, 11 | 12 | #[serde(rename = "script")] 13 | Script, 14 | } 15 | -------------------------------------------------------------------------------- /src/probe/poll.rs: -------------------------------------------------------------------------------- 1 | // Vigil Local 2 | // 3 | // Vigil local probe relay 4 | // Copyright: 2020, Valerian Saliou 5 | // License: Mozilla Public License v2.0 (MPL v2.0) 6 | 7 | use http_req::{ 8 | request::{Method, Request}, 9 | uri::Uri, 10 | }; 11 | use ping::ping; 12 | 13 | use std::cmp::min; 14 | use std::convert::TryFrom; 15 | use std::net::{SocketAddr, TcpStream, ToSocketAddrs}; 16 | use std::thread; 17 | use std::time::Duration; 18 | use std::time::SystemTime; 19 | 20 | use super::replica::ReplicaURL; 21 | use super::report::{status as report_status, ReportReplica}; 22 | use super::status::Status; 23 | use crate::config::config::{ConfigProbeService, ConfigProbeServiceNode}; 24 | use crate::APP_CONF; 25 | 26 | const NODE_ICMP_TIMEOUT_MILLISECONDS: u64 = 1000; 27 | const RETRY_REPLICA_AFTER_MILLISECONDS: u64 = 200; 28 | 29 | const HTTP_STATUS_HEALTHY_ABOVE: u16 = 200; 30 | const HTTP_STATUS_HEALTHY_BELOW: u16 = 400; 31 | 32 | lazy_static! { 33 | static ref POLL_HTTP_HEADER_USERAGENT: String = 34 | format!("{}/{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); 35 | } 36 | 37 | pub fn dispatch(service: &ConfigProbeService, node: &ConfigProbeServiceNode, interval: u64) { 38 | if let Some(ref replicas) = node.replicas { 39 | if !replicas.is_empty() { 40 | debug!("poll node has replicas in service node: #{}", node.id); 41 | 42 | for replica in replicas { 43 | let replica_status = proceed_replica(&service.id, &node.id, replica); 44 | 45 | if replica_status == Status::Dead { 46 | warn!("got replica status upon poll: {:?}", replica_status); 47 | } else { 48 | debug!("got replica status upon poll: {:?}", replica_status); 49 | } 50 | 51 | match report_status( 52 | &service, 53 | node, 54 | ReportReplica::Poll(replica), 55 | &replica_status, 56 | interval, 57 | ) { 58 | Ok(_) => info!("reported poll replica status: {:?}", replica_status), 59 | Err(_) => error!("failed reporting poll replica status: {:?}", replica_status), 60 | } 61 | } 62 | 63 | return; 64 | } 65 | } 66 | 67 | warn!( 68 | "poll node has no usable replica in service node: #{}", 69 | node.id 70 | ); 71 | } 72 | 73 | pub fn proceed_replica(service_id: &str, node_id: &str, replica: &ReplicaURL) -> Status { 74 | // Attempt to acquire (first attempt) 75 | proceed_replica_attempt(service_id, node_id, replica, APP_CONF.metrics.poll_retry, 0) 76 | } 77 | 78 | fn proceed_replica_attempt( 79 | service_id: &str, 80 | node_id: &str, 81 | replica: &ReplicaURL, 82 | retry_times: u8, 83 | attempt: u8, 84 | ) -> Status { 85 | info!( 86 | "running poll replica scan attempt #{} on #{}:#{}:[{:?}]", 87 | attempt, service_id, node_id, replica 88 | ); 89 | 90 | match proceed_replica_request(service_id, node_id, replica) { 91 | Status::Healthy => Status::Healthy, 92 | Status::Sick => Status::Sick, 93 | Status::Dead => { 94 | let next_attempt = attempt + 1; 95 | 96 | if next_attempt > retry_times { 97 | Status::Dead 98 | } else { 99 | warn!( 100 | "poll replica scan attempt #{} failed on #{}:#{}:[{:?}], will retry", 101 | attempt, service_id, node_id, replica 102 | ); 103 | 104 | // Retry after delay 105 | thread::sleep(Duration::from_millis(RETRY_REPLICA_AFTER_MILLISECONDS)); 106 | 107 | proceed_replica_attempt(service_id, node_id, replica, retry_times, next_attempt) 108 | } 109 | } 110 | } 111 | } 112 | 113 | fn proceed_replica_request(service_id: &str, node_id: &str, replica: &ReplicaURL) -> Status { 114 | debug!( 115 | "scanning poll replica: #{}:#{}:[{:?}]", 116 | service_id, node_id, replica 117 | ); 118 | 119 | let start_time = SystemTime::now(); 120 | 121 | let (is_up, poll_duration) = match replica { 122 | &ReplicaURL::ICMP(_, ref host) => proceed_replica_request_icmp(host), 123 | &ReplicaURL::TCP(_, ref host, port) => proceed_replica_request_tcp(host, port), 124 | &ReplicaURL::HTTP(_, ref url) => proceed_replica_request_http(url), 125 | &ReplicaURL::HTTPS(_, ref url) => proceed_replica_request_http(url), 126 | }; 127 | 128 | if is_up == true { 129 | // Acquire poll duration latency 130 | let duration_latency = match poll_duration { 131 | Some(poll_duration) => poll_duration, 132 | None => SystemTime::now() 133 | .duration_since(start_time) 134 | .unwrap_or(Duration::from_secs(0)), 135 | }; 136 | 137 | if duration_latency >= Duration::from_secs(APP_CONF.metrics.poll_delay_sick) { 138 | Status::Sick 139 | } else { 140 | Status::Healthy 141 | } 142 | } else { 143 | Status::Dead 144 | } 145 | } 146 | 147 | fn proceed_replica_request_icmp(host: &str) -> (bool, Option) { 148 | // Notice: a dummy port of value '0' is set here, so that we can resolve the host to an actual \ 149 | // IP address using the standard library, which avoids depending on an additional library. 150 | let address_results = (host, 0).to_socket_addrs(); 151 | 152 | // Storage variable for the maximum round-trip-time found for received ping responses 153 | let mut maximum_rtt = None; 154 | 155 | match address_results { 156 | Ok(address) => { 157 | // Notice: the ICMP probe checker is a bit special, in the sense that it checks all \ 158 | // resolved addresses. As we check for an host health at the IP level (ie. not at \ 159 | // the application layer level), checking only the first host in the list is not \ 160 | // sufficient for the whole replica group to be up. This can be used as an handy way \ 161 | // to check for the health of a group of IP hosts, configured in a single DNS record. 162 | let address_values: Vec = address.collect(); 163 | 164 | if !address_values.is_empty() { 165 | debug!( 166 | "prober poll will fire for icmp host: {} ({} targets)", 167 | host, 168 | address_values.len() 169 | ); 170 | 171 | // As ICMP pings require a lower-than-usual timeout, an hard-coded ICMP \ 172 | // timeout value is used by default, though the configured dead delay value \ 173 | // is preferred in the event it is lower than the hard-coded value (unlikely \ 174 | // though possible in some setups). 175 | let pinger_timeout = Duration::from_secs(min( 176 | NODE_ICMP_TIMEOUT_MILLISECONDS, 177 | acquire_dead_timeout().as_secs() * 1000, 178 | )); 179 | 180 | // Probe all returned addresses (sequentially) 181 | for address_value in &address_values { 182 | let address_ip = address_value.ip(); 183 | 184 | debug!( 185 | "prober poll will send icmp ping to target: {} from host: {}", 186 | address_ip, host 187 | ); 188 | 189 | // Acquire ping start time (used for RTT calculation) 190 | let ping_start_time = SystemTime::now(); 191 | 192 | // Ping target IP address 193 | match ping(address_ip, Some(pinger_timeout), None, None, None, None) { 194 | Ok(_) => { 195 | debug!( 196 | "got prober poll response for icmp target: {} from host: {}", 197 | address_ip, host 198 | ); 199 | 200 | // Process ping RTT 201 | let ping_rtt = SystemTime::now() 202 | .duration_since(ping_start_time) 203 | .unwrap_or(Duration::from_secs(0)); 204 | 205 | // Do not return (consider address as reachable) 206 | // Notice: update maximum observed round-trip-time, if higher than \ 207 | // last highest observed. 208 | maximum_rtt = match maximum_rtt { 209 | Some(maximum_rtt) => { 210 | if ping_rtt > maximum_rtt { 211 | Some(ping_rtt) 212 | } else { 213 | Some(maximum_rtt) 214 | } 215 | } 216 | None => Some(ping_rtt), 217 | }; 218 | } 219 | Err(err) => { 220 | debug!( 221 | "prober poll error for icmp target: {} from host: {} (error: {})", 222 | address_ip, host, err 223 | ); 224 | 225 | // Consider ICMP errors as a failure 226 | return (false, None); 227 | } 228 | } 229 | } 230 | } else { 231 | debug!( 232 | "prober poll did not resolve any address for icmp replica: {}", 233 | host 234 | ); 235 | 236 | // Consider empty as a failure 237 | return (false, None); 238 | } 239 | } 240 | Err(err) => { 241 | error!( 242 | "prober poll address for icmp replica is invalid: {} (error: {})", 243 | host, err 244 | ); 245 | 246 | // Consider invalid URL as a failure 247 | return (false, None); 248 | } 249 | }; 250 | 251 | // If there was no early return, consider all the hosts as reachable for replica 252 | (true, maximum_rtt) 253 | } 254 | 255 | fn proceed_replica_request_tcp(host: &str, port: u16) -> (bool, Option) { 256 | let address_results = (host, port).to_socket_addrs(); 257 | 258 | if let Ok(mut address) = address_results { 259 | if let Some(address_value) = address.next() { 260 | debug!("prober poll will fire for tcp target: {}", address_value); 261 | 262 | return match TcpStream::connect_timeout(&address_value, acquire_dead_timeout()) { 263 | Ok(_) => (true, None), 264 | Err(_) => (false, None), 265 | }; 266 | } 267 | } 268 | 269 | (false, None) 270 | } 271 | 272 | fn proceed_replica_request_http(url: &str) -> (bool, Option) { 273 | debug!("prober poll will fire for http target: {}", &url); 274 | 275 | // Unpack dead timeout 276 | let dead_timeout = acquire_dead_timeout(); 277 | 278 | // Acquire replica response 279 | let mut response_body = Vec::new(); 280 | 281 | let response = Request::new(&Uri::try_from(url).expect("invalid replica request uri")) 282 | .connect_timeout(Some(dead_timeout)) 283 | .read_timeout(Some(dead_timeout)) 284 | .write_timeout(Some(dead_timeout)) 285 | .method(Method::HEAD) 286 | .header("User-Agent", &*POLL_HTTP_HEADER_USERAGENT) 287 | .send(&mut response_body); 288 | 289 | // Handle response 290 | if let Ok(response) = response { 291 | let status_code = u16::from(response.status_code()); 292 | 293 | debug!( 294 | "prober poll result received for url: {} with status: {}", 295 | &url, status_code 296 | ); 297 | 298 | // Consider as UP? 299 | if status_code >= HTTP_STATUS_HEALTHY_ABOVE && status_code < HTTP_STATUS_HEALTHY_BELOW { 300 | return (true, None); 301 | } 302 | } else { 303 | debug!("prober poll result was not received for url: {}", &url); 304 | } 305 | 306 | // Consider as DOWN. 307 | (false, None) 308 | } 309 | 310 | fn acquire_dead_timeout() -> Duration { 311 | Duration::from_secs(APP_CONF.metrics.poll_delay_dead) 312 | } 313 | -------------------------------------------------------------------------------- /src/probe/replica.rs: -------------------------------------------------------------------------------- 1 | // Vigil Local 2 | // 3 | // Vigil local probe relay 4 | // Copyright: 2020, Valerian Saliou 5 | // License: Mozilla Public License v2.0 (MPL v2.0) 6 | 7 | use std::fmt; 8 | 9 | use serde::de::{Error, Visitor}; 10 | use serde::{Deserialize, Deserializer}; 11 | use url::{Host, Url}; 12 | 13 | #[derive(Serialize, Debug, Clone)] 14 | pub enum ReplicaURL { 15 | ICMP(String, String), 16 | TCP(String, String, u16), 17 | HTTP(String, String), 18 | HTTPS(String, String), 19 | } 20 | 21 | impl ReplicaURL { 22 | pub fn parse_from(raw_url: &str) -> Result { 23 | match Url::parse(raw_url) { 24 | Ok(url) => match url.scheme() { 25 | "icmp" => match url.host() { 26 | Some(host) => Ok(ReplicaURL::ICMP( 27 | raw_url.to_owned(), 28 | Self::host_string(host), 29 | )), 30 | _ => Err(()), 31 | }, 32 | "tcp" => match (url.host(), url.port()) { 33 | (Some(host), Some(port)) => Ok(ReplicaURL::TCP( 34 | raw_url.to_owned(), 35 | Self::host_string(host), 36 | port, 37 | )), 38 | _ => Err(()), 39 | }, 40 | "http" => Ok(ReplicaURL::HTTP(raw_url.to_owned(), url.to_string())), 41 | "https" => Ok(ReplicaURL::HTTPS(raw_url.to_owned(), url.to_string())), 42 | _ => Err(()), 43 | }, 44 | _ => Err(()), 45 | } 46 | } 47 | 48 | pub fn get_raw(&self) -> &str { 49 | match self { 50 | &ReplicaURL::ICMP(ref raw_url, _) => raw_url, 51 | &ReplicaURL::TCP(ref raw_url, _, _) => raw_url, 52 | &ReplicaURL::HTTP(ref raw_url, _) => raw_url, 53 | &ReplicaURL::HTTPS(ref raw_url, _) => raw_url, 54 | } 55 | } 56 | 57 | fn host_string(host: Host<&str>) -> String { 58 | // Convert internal host value into string. This is especially useful for IPv6 addresses, \ 59 | // which we need returned in '::1' format; as they would otherwise be returned in \ 60 | // '[::1]' format using built-in top-level 'to_string()' method on the 'Host' trait. The \ 61 | // underlying address parser does not accept IPv6 addresses formatted as '[::1]', so \ 62 | // this seemingly overkill processing is obviously needed. 63 | match host { 64 | Host::Domain(domain_value) => domain_value.to_string(), 65 | Host::Ipv4(ipv4_value) => ipv4_value.to_string(), 66 | Host::Ipv6(ipv6_value) => ipv6_value.to_string(), 67 | } 68 | } 69 | } 70 | 71 | impl<'de> Deserialize<'de> for ReplicaURL { 72 | fn deserialize(de: D) -> Result 73 | where 74 | D: Deserializer<'de>, 75 | { 76 | struct ReplicaURLVisitor; 77 | 78 | impl<'de> Visitor<'de> for ReplicaURLVisitor { 79 | type Value = ReplicaURL; 80 | 81 | fn expecting(&self, format: &mut fmt::Formatter) -> fmt::Result { 82 | format.write_str("an ICMP, TCP, HTTP or HTTPS url") 83 | } 84 | 85 | fn visit_str(self, value: &str) -> Result { 86 | ReplicaURL::parse_from(value).map_err(|_| E::custom("invalid")) 87 | } 88 | } 89 | 90 | de.deserialize_str(ReplicaURLVisitor) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/probe/report.rs: -------------------------------------------------------------------------------- 1 | // Vigil Local 2 | // 3 | // Vigil local probe relay 4 | // Copyright: 2020, Valerian Saliou 5 | // License: Mozilla Public License v2.0 (MPL v2.0) 6 | 7 | use base64::engine::general_purpose::STANDARD as base64_encoder; 8 | use base64::Engine; 9 | use http_req::{ 10 | request::{Method, Request}, 11 | uri::Uri, 12 | }; 13 | use serde_json; 14 | 15 | use std::convert::TryFrom; 16 | use std::io; 17 | use std::thread; 18 | use std::time::Duration; 19 | 20 | use super::replica::ReplicaURL; 21 | use super::status::Status; 22 | use crate::config::config::{ConfigProbeService, ConfigProbeServiceNode}; 23 | use crate::APP_CONF; 24 | 25 | pub const REPORT_HTTP_CLIENT_TIMEOUT: Duration = Duration::from_secs(10); 26 | 27 | const RETRY_STATUS_TIMES: u8 = 4; 28 | const RETRY_STATUS_AFTER_SECONDS: u64 = 2; 29 | 30 | #[derive(Debug, Clone, Copy)] 31 | pub enum ReportReplica<'a> { 32 | Poll(&'a ReplicaURL), 33 | Script(&'a str), 34 | } 35 | 36 | #[derive(Serialize)] 37 | struct ReportPayload<'a> { 38 | replica: &'a str, 39 | health: &'a str, 40 | interval: u64, 41 | } 42 | 43 | lazy_static! { 44 | pub static ref REPORT_HTTP_HEADER_USERAGENT: String = 45 | format!("{}/{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); 46 | pub static ref REPORT_HTTP_HEADER_AUTHORIZATION: String = format!( 47 | "Basic {}", 48 | base64_encoder.encode(&format!(":{}", APP_CONF.report.token)) 49 | ); 50 | } 51 | 52 | impl<'a> ReportReplica<'a> { 53 | pub fn as_str(&self) -> &str { 54 | match self { 55 | Self::Poll(replica) => replica.get_raw(), 56 | Self::Script(replica) => replica, 57 | } 58 | } 59 | } 60 | 61 | pub fn generate_url(path: &str) -> String { 62 | format!("{}/{}", &APP_CONF.report.endpoint, path) 63 | } 64 | 65 | pub fn status<'a>( 66 | service: &ConfigProbeService, 67 | node: &ConfigProbeServiceNode, 68 | replica: ReportReplica<'a>, 69 | status: &Status, 70 | interval: u64, 71 | ) -> Result<(), ()> { 72 | // Attempt to acquire (first attempt) 73 | status_attempt(service, node, replica, status, interval, 0) 74 | } 75 | 76 | fn status_attempt<'a>( 77 | service: &ConfigProbeService, 78 | node: &ConfigProbeServiceNode, 79 | replica: ReportReplica<'a>, 80 | status: &Status, 81 | interval: u64, 82 | attempt: u8, 83 | ) -> Result<(), ()> { 84 | info!( 85 | "running status report attempt #{} on #{}:#{}:[{:?}]", 86 | attempt, service.id, node.id, replica 87 | ); 88 | 89 | match status_request(service, node, replica, status, interval) { 90 | Ok(_) => Ok(()), 91 | Err(_) => { 92 | let next_attempt = attempt + 1; 93 | 94 | if next_attempt >= RETRY_STATUS_TIMES { 95 | Err(()) 96 | } else { 97 | error!( 98 | "status report attempt #{} failed on #{}:#{}:[{:?}], will retry", 99 | attempt, service.id, node.id, replica 100 | ); 101 | 102 | // Retry after delay 103 | thread::sleep(Duration::from_secs(RETRY_STATUS_AFTER_SECONDS)); 104 | 105 | status_attempt(service, node, replica, status, interval, next_attempt) 106 | } 107 | } 108 | } 109 | } 110 | 111 | fn status_request<'a>( 112 | service: &ConfigProbeService, 113 | node: &ConfigProbeServiceNode, 114 | replica: ReportReplica<'a>, 115 | status: &Status, 116 | interval: u64, 117 | ) -> Result<(), ()> { 118 | // Generate report URL 119 | let report_url = generate_url(&format!("reporter/{}/{}/", &service.id, &node.id)); 120 | 121 | debug!("generated report url: {}", &report_url); 122 | 123 | // Generate report payload 124 | let payload = ReportPayload { 125 | replica: replica.as_str(), 126 | interval: interval, 127 | health: status.as_str(), 128 | }; 129 | 130 | // Encode payload to string 131 | // Notice: fail hard if payload is invalid (it should never be) 132 | let payload_json = serde_json::to_vec(&payload).expect("invalid status request payload"); 133 | 134 | // Generate request URI 135 | let request_uri = Uri::try_from(report_url.as_str()).expect("invalid status request uri"); 136 | 137 | // Acquire report response 138 | let mut response_sink = io::sink(); 139 | 140 | let response = Request::new(&request_uri) 141 | .connect_timeout(Some(REPORT_HTTP_CLIENT_TIMEOUT)) 142 | .read_timeout(Some(REPORT_HTTP_CLIENT_TIMEOUT)) 143 | .write_timeout(Some(REPORT_HTTP_CLIENT_TIMEOUT)) 144 | .method(Method::POST) 145 | .header("User-Agent", &*REPORT_HTTP_HEADER_USERAGENT) 146 | .header("Authorization", &*REPORT_HTTP_HEADER_AUTHORIZATION) 147 | .header("Content-Type", "application/json") 148 | .header("Content-Length", &payload_json.len()) 149 | .body(&payload_json) 150 | .send(&mut response_sink); 151 | 152 | match response { 153 | Ok(response) => { 154 | let status_code = response.status_code(); 155 | 156 | if status_code.is_success() { 157 | debug!("reported to probe url: {}", report_url); 158 | 159 | Ok(()) 160 | } else { 161 | debug!( 162 | "could not report to probe url: {} (got status code: {})", 163 | report_url, status_code 164 | ); 165 | 166 | Err(()) 167 | } 168 | } 169 | Err(err) => { 170 | warn!( 171 | "failed reporting to probe url: {} because: {}", 172 | report_url, err 173 | ); 174 | 175 | Err(()) 176 | } 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/probe/script.rs: -------------------------------------------------------------------------------- 1 | // Vigil Local 2 | // 3 | // Vigil local probe relay 4 | // Copyright: 2020, Valerian Saliou 5 | // License: Mozilla Public License v2.0 (MPL v2.0) 6 | 7 | use run_script::{self, ScriptOptions}; 8 | 9 | use super::report::{status as report_status, ReportReplica}; 10 | use super::status::Status; 11 | use crate::config::config::{ConfigProbeService, ConfigProbeServiceNode}; 12 | 13 | pub fn dispatch(service: &ConfigProbeService, node: &ConfigProbeServiceNode, interval: u64) { 14 | if let Some(ref scripts) = node.scripts { 15 | if !scripts.is_empty() { 16 | debug!("script node has scripts in service node: #{}", node.id); 17 | 18 | for (index, script) in scripts.iter().enumerate() { 19 | let replica_id = index.to_string(); 20 | let replica_status = proceed_replica(&service.id, &node.id, &replica_id, script); 21 | 22 | debug!("got replica status upon script: {:?}", replica_status); 23 | 24 | match report_status( 25 | &service, 26 | node, 27 | ReportReplica::Script(&replica_id), 28 | &replica_status, 29 | interval, 30 | ) { 31 | Ok(_) => info!("reported script replica status: {:?}", replica_status), 32 | Err(_) => error!( 33 | "failed reporting script replica status: {:?}", 34 | replica_status 35 | ), 36 | } 37 | } 38 | 39 | return; 40 | } 41 | } 42 | 43 | warn!( 44 | "script node has no usable script in service node: #{}", 45 | node.id 46 | ); 47 | } 48 | 49 | pub fn proceed_replica(service_id: &str, node_id: &str, replica_id: &str, script: &str) -> Status { 50 | info!( 51 | "executing script replica on #{}:#{}:[#{}]", 52 | service_id, node_id, replica_id 53 | ); 54 | 55 | match run_script::run(script, &Vec::new(), &ScriptOptions::new()) { 56 | Ok((code, _, _)) => { 57 | // Return code '0' goes for 'healthy', '1' goes for 'sick'; any other code is 'dead' 58 | let replica_status = match code { 59 | 0 => Status::Healthy, 60 | 1 => Status::Sick, 61 | _ => Status::Dead, 62 | }; 63 | 64 | if replica_status == Status::Dead { 65 | warn!( 66 | "script replica execution succeeded with {:?} return code: {}", 67 | replica_status, code 68 | ); 69 | } else { 70 | debug!( 71 | "script replica execution succeeded with {:?} return code: {}", 72 | replica_status, code 73 | ); 74 | } 75 | 76 | replica_status 77 | } 78 | Err(err) => { 79 | error!("script replica execution failed with error: {}", err); 80 | 81 | Status::Dead 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/probe/status.rs: -------------------------------------------------------------------------------- 1 | // Vigil Local 2 | // 3 | // Vigil local probe relay 4 | // Copyright: 2020, Valerian Saliou 5 | // License: Mozilla Public License v2.0 (MPL v2.0) 6 | 7 | #[derive(Debug, PartialEq)] 8 | pub enum Status { 9 | Healthy, 10 | Sick, 11 | Dead, 12 | } 13 | 14 | impl Status { 15 | pub fn as_str(&self) -> &'static str { 16 | match self { 17 | &Status::Healthy => "healthy", 18 | &Status::Sick => "sick", 19 | &Status::Dead => "dead", 20 | } 21 | } 22 | } 23 | --------------------------------------------------------------------------------