connected daemon to the brain (#2)
Instead of grabbing commands from files, the daemon now connects to the brain and receives commands via gRPC. Reviewed-on: SNP/daemon#2
This commit is contained in:
parent
3ba140a830
commit
3c6074f735
699
Cargo.lock
generated
699
Cargo.lock
generated
@ -17,12 +17,103 @@ version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
|
||||
|
||||
[[package]]
|
||||
name = "async-stream"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
|
||||
dependencies = [
|
||||
"async-stream-impl",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream-impl"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
@ -35,6 +126,53 @@ version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"itoa",
|
||||
"matchit",
|
||||
"memchr",
|
||||
"mime",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"serde",
|
||||
"sync_wrapper",
|
||||
"tower 0.5.2",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-core"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"sync_wrapper",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.74"
|
||||
@ -56,6 +194,12 @@ version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
@ -91,9 +235,9 @@ checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.3"
|
||||
version = "1.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d"
|
||||
checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
@ -105,13 +249,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cidr"
|
||||
version = "0.3.0"
|
||||
name = "colorchoice"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfc95a0c21d5409adc146dbbb152b5c65aaea32bc2d2f57cf12f850bffdd7ab8"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
@ -148,17 +295,65 @@ dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curve25519-dalek"
|
||||
version = "4.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"curve25519-dalek-derive",
|
||||
"digest",
|
||||
"fiat-crypto",
|
||||
"rustc_version",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curve25519-dalek-derive"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"pem-rfc7468",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "detee-snp-daemon"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cidr",
|
||||
"ed25519-dalek",
|
||||
"env_logger",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"prost",
|
||||
"prost-types",
|
||||
"rand",
|
||||
"rand_core",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_yaml",
|
||||
"sha2",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tonic",
|
||||
"tonic-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -182,6 +377,37 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ed25519"
|
||||
version = "2.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
|
||||
dependencies = [
|
||||
"pkcs8",
|
||||
"signature",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ed25519-dalek"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"ed25519",
|
||||
"rand_core",
|
||||
"serde",
|
||||
"sha2",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.35"
|
||||
@ -191,6 +417,29 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.11.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"env_filter",
|
||||
"humantime",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
@ -213,6 +462,18 @@ version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "fiat-crypto"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
@ -332,19 +593,31 @@ dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"http",
|
||||
"indexmap",
|
||||
"indexmap 2.7.0",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.2.0"
|
||||
@ -385,6 +658,18 @@ version = "1.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
|
||||
|
||||
[[package]]
|
||||
name = "httpdate"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.5.1"
|
||||
@ -398,6 +683,7 @@ dependencies = [
|
||||
"http",
|
||||
"http-body",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"smallvec",
|
||||
@ -407,9 +693,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper-rustls"
|
||||
version = "0.27.3"
|
||||
version = "0.27.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333"
|
||||
checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"http",
|
||||
@ -422,6 +708,19 @@ dependencies = [
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-timeout"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0"
|
||||
dependencies = [
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-tls"
|
||||
version = "0.6.0"
|
||||
@ -596,6 +895,16 @@ dependencies = [
|
||||
"icu_properties",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.7.0"
|
||||
@ -603,7 +912,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
"hashbrown 0.15.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -612,6 +921,21 @@ version = "2.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.14"
|
||||
@ -628,6 +952,12 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.167"
|
||||
@ -652,6 +982,12 @@ version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "matchit"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
@ -684,6 +1020,12 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multimap"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.12"
|
||||
@ -760,12 +1102,51 @@ dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pem-rfc7468"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"indexmap 2.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "1.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.15"
|
||||
@ -778,6 +1159,16 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkcs8"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
|
||||
dependencies = [
|
||||
"der",
|
||||
"spki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.31"
|
||||
@ -793,6 +1184,16 @@ dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.92"
|
||||
@ -802,6 +1203,58 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost"
|
||||
version = "0.13.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c0fef6c4230e4ccf618a35c59d7ede15dea37de8427500f50aff708806e42ec"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-build"
|
||||
version = "0.13.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0f3e5beed80eb580c68e2c600937ac2c4eedabdfd5ef1e5b7ea4f3fba84497b"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"itertools",
|
||||
"log",
|
||||
"multimap",
|
||||
"once_cell",
|
||||
"petgraph",
|
||||
"prettyplease",
|
||||
"prost",
|
||||
"prost-types",
|
||||
"regex",
|
||||
"syn",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-derive"
|
||||
version = "0.13.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "157c5a9d7ea5c2ed2d9fb8f495b64759f7816c7eaea54ba3978f0d63000162e3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-types"
|
||||
version = "0.13.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc2f1e56baa61e93533aebc21af4d2134b70f66275e0fcdf3cbe43d77ff7e8fc"
|
||||
dependencies = [
|
||||
"prost",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.37"
|
||||
@ -842,10 +1295,39 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.9"
|
||||
name = "regex"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fe060fe50f524be480214aba758c71f99f90ee8c83c5a36b5e9e1d568eb4eb3"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
@ -877,6 +1359,7 @@ dependencies = [
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tower 0.5.2",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
@ -906,6 +1389,15 @@ version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.42"
|
||||
@ -921,9 +1413,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.19"
|
||||
version = "0.23.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1"
|
||||
checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"rustls-pki-types",
|
||||
@ -943,9 +1435,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.10.0"
|
||||
version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
|
||||
checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37"
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
@ -958,6 +1450,12 @@ dependencies = [
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
@ -988,14 +1486,20 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.12.1"
|
||||
version = "2.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2"
|
||||
checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.215"
|
||||
@ -1018,9 +1522,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.133"
|
||||
version = "1.0.134"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
|
||||
checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
@ -1046,7 +1550,7 @@ version = "0.9.34+deprecated"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"indexmap 2.7.0",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
@ -1070,6 +1574,15 @@ version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signature"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
@ -1101,6 +1614,16 @@ version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"der",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
@ -1200,9 +1723,21 @@ dependencies = [
|
||||
"mio",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-native-tls"
|
||||
version = "0.3.1"
|
||||
@ -1223,6 +1758,17 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.13"
|
||||
@ -1236,6 +1782,91 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tonic"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"async-trait",
|
||||
"axum",
|
||||
"base64",
|
||||
"bytes",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-timeout",
|
||||
"hyper-util",
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"prost",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tower 0.4.13",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tonic-build"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11"
|
||||
dependencies = [
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"prost-build",
|
||||
"prost-types",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"indexmap 1.9.3",
|
||||
"pin-project",
|
||||
"pin-project-lite",
|
||||
"rand",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"pin-project-lite",
|
||||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-layer"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
|
||||
|
||||
[[package]]
|
||||
name = "tower-service"
|
||||
version = "0.3.3"
|
||||
@ -1249,9 +1880,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
||||
dependencies = [
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.33"
|
||||
@ -1314,6 +1957,12 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
|
16
Cargo.toml
16
Cargo.toml
@ -4,10 +4,22 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
ed25519-dalek = { version = "2.1.1", default-features = false, features = ["std", "alloc", "rand_core", "pem"] }
|
||||
rand_core = { version = "0.6.4", features = ["alloc", "getrandom", "std"] }
|
||||
anyhow = "1.0.94"
|
||||
cidr = { version = "0.3.0", features = ["serde"] }
|
||||
rand = "0.8.5"
|
||||
env_logger = "0.11.6"
|
||||
log = "0.4.22"
|
||||
reqwest = { version = "0.12.9", features = ["blocking"] }
|
||||
serde = { version = "1.0.215", features = ["derive"] }
|
||||
serde_yaml = "0.9.34"
|
||||
sha2 = "0.10.8"
|
||||
lazy_static = "1.5.0"
|
||||
prost = "0.13.4"
|
||||
prost-types = "0.13.4"
|
||||
rand = "0.8.5"
|
||||
tokio = { version = "1.42.0", features = ["macros", "rt-multi-thread"] }
|
||||
tokio-stream = "0.1.17"
|
||||
tonic = "0.12"
|
||||
|
||||
[build-dependencies]
|
||||
tonic-build = "0.12"
|
||||
|
145
brain.proto
Normal file
145
brain.proto
Normal file
@ -0,0 +1,145 @@
|
||||
syntax = "proto3";
|
||||
package brain;
|
||||
|
||||
message Empty {
|
||||
}
|
||||
|
||||
message NodePubkey {
|
||||
string node_pubkey = 1;
|
||||
}
|
||||
|
||||
message RegisterNodeReq {
|
||||
string node_pubkey = 1;
|
||||
string owner_pubkey = 2;
|
||||
}
|
||||
|
||||
message NodeResourceReq {
|
||||
string node_pubkey = 1;
|
||||
uint32 avail_ports = 2;
|
||||
uint32 avail_ipv4 = 3;
|
||||
uint32 avail_ipv6 = 4;
|
||||
uint32 avail_vcpus = 5;
|
||||
uint32 avail_memory_mb = 6;
|
||||
uint32 avail_storage_gb = 7;
|
||||
uint32 max_ports_per_vm = 8;
|
||||
}
|
||||
|
||||
message NewVMReq {
|
||||
string uuid = 1; // UUID is empty when CLI sends request; brain sets UUID
|
||||
string hostname = 2;
|
||||
string admin_pubkey = 3;
|
||||
string node_pubkey = 4;
|
||||
repeated uint32 extra_ports = 5;
|
||||
bool public_ipv4 = 6;
|
||||
bool public_ipv6 = 7;
|
||||
uint32 disk_size_gb = 8;
|
||||
uint32 vcpus = 9;
|
||||
uint32 memory_mb = 10;
|
||||
string kernel_url = 11;
|
||||
string kernel_sha = 12;
|
||||
string dtrfs_url = 13;
|
||||
string dtrfs_sha = 14;
|
||||
}
|
||||
|
||||
message UpdateVMReq {
|
||||
string uuid = 1;
|
||||
uint32 disk_size_gb = 3;
|
||||
uint32 vcpus = 4;
|
||||
uint32 memory_mb = 5;
|
||||
string kernel_url = 6;
|
||||
string kernel_sha = 7;
|
||||
string dtrfs_url = 8;
|
||||
string dtrfs_sha = 9;
|
||||
}
|
||||
|
||||
message UpdateVMResp {
|
||||
string uuid = 1;
|
||||
string error = 3;
|
||||
}
|
||||
|
||||
message VMContract {
|
||||
string uuid = 1;
|
||||
string hostname = 2;
|
||||
string admin_pubkey = 3;
|
||||
string node_pubkey = 4;
|
||||
repeated uint32 exposed_ports = 5;
|
||||
string public_ipv4 = 6;
|
||||
string public_ipv6 = 7;
|
||||
uint32 disk_size_gb = 8;
|
||||
uint32 vcpus = 9;
|
||||
uint32 memory_mb = 10;
|
||||
string kernel_sha = 11;
|
||||
string dtrfs_sha = 12;
|
||||
string created_at = 13;
|
||||
string updated_at = 14;
|
||||
}
|
||||
|
||||
message ListVMContractsReq {
|
||||
string admin_pubkey = 1;
|
||||
string node_pubkey = 2;
|
||||
string uuid = 3;
|
||||
}
|
||||
|
||||
message NewVmRespIP {
|
||||
uint32 nic_index = 1;
|
||||
string address = 2;
|
||||
string mask = 3;
|
||||
string gateway = 4;
|
||||
}
|
||||
|
||||
message NewVMResp {
|
||||
string uuid = 1;
|
||||
repeated uint32 exposed_ports = 2;
|
||||
string ovmf_hash = 5;
|
||||
// This is needed to allow the CLI to build the kernel params from known data.
|
||||
// The CLI will use the kernel params to get the measurement.
|
||||
repeated NewVmRespIP ips = 6;
|
||||
string error = 7;
|
||||
}
|
||||
|
||||
message DeleteVMReq {
|
||||
string uuid = 1;
|
||||
}
|
||||
|
||||
service BrainDaemonService {
|
||||
rpc RegisterNode (RegisterNodeReq) returns (Empty);
|
||||
rpc SendNodeResources (stream NodeResourceReq) returns (Empty);
|
||||
rpc GetNewVMReqs (NodePubkey) returns (stream NewVMReq);
|
||||
rpc SendNewVMResp (stream NewVMResp) returns (Empty);
|
||||
rpc GetDeleteVMReq (NodePubkey) returns (stream DeleteVMReq);
|
||||
rpc ListVMContracts (ListVMContractsReq) returns (stream VMContract);
|
||||
rpc GetUpdateVMReq (NodePubkey) returns (stream UpdateVMReq);
|
||||
rpc SendUpdateVMResp (stream UpdateVMResp) returns (Empty);
|
||||
}
|
||||
|
||||
message NodeFilters {
|
||||
uint32 free_ports = 1;
|
||||
bool offers_ipv4 = 2;
|
||||
bool offers_ipv6 = 3;
|
||||
uint32 vcpus = 4;
|
||||
uint32 memory_mb = 5;
|
||||
uint32 storage_gb = 6;
|
||||
string country = 7;
|
||||
string region = 8;
|
||||
string city = 9;
|
||||
string ip = 10;
|
||||
}
|
||||
|
||||
message NodeListResp {
|
||||
string node_pubkey = 1;
|
||||
string country = 2;
|
||||
string region = 3;
|
||||
string city = 4;
|
||||
string ip = 5; // required for latency test
|
||||
uint32 server_rating = 6;
|
||||
uint32 provider_rating = 7;
|
||||
}
|
||||
|
||||
service BrainCliService {
|
||||
rpc CreateVMContract (NewVMReq) returns (NewVMResp);
|
||||
rpc ListVMContracts (ListVMContractsReq) returns (stream VMContract);
|
||||
rpc ListNodes (NodeFilters) returns (stream NodeListResp);
|
||||
rpc GetOneNode (NodeFilters) returns (NodeListResp);
|
||||
rpc DeleteVM (DeleteVMReq) returns (Empty);
|
||||
rpc UpdateVM (UpdateVMReq) returns (UpdateVMResp);
|
||||
}
|
6
build.rs
Normal file
6
build.rs
Normal file
@ -0,0 +1,6 @@
|
||||
fn main() {
|
||||
tonic_build::configure()
|
||||
.build_server(true)
|
||||
.compile_protos(&["brain.proto"], &["proto"])
|
||||
.unwrap_or_else(|e| panic!("Failed to compile protos {:?}", e));
|
||||
}
|
@ -1,25 +1,24 @@
|
||||
brain_url: "http://164.92.249.180:31337"
|
||||
max_cores_per_vm: 4
|
||||
max_vcpu_reservation: 8
|
||||
max_mem_reservation_mb: 25000
|
||||
network_interfaces:
|
||||
- driver: "MACVTAP"
|
||||
device: "eno8303"
|
||||
ipv4:
|
||||
- subnet: "173.234.136.152/29"
|
||||
ipv4_ranges:
|
||||
- first_ip: "173.234.136.154"
|
||||
last_ip: "173.234.136.155"
|
||||
netmask: "27"
|
||||
gateway: "173.234.136.158"
|
||||
reserved_addrs:
|
||||
- "173.234.136.153"
|
||||
- "173.234.136.156"
|
||||
- "173.234.136.157"
|
||||
- "173.234.136.158"
|
||||
- subnet: "173.234.137.16/31"
|
||||
- first_ip: "173.234.137.17"
|
||||
last_ip: "173.234.137.17"
|
||||
netmask: "27"
|
||||
gateway: "173.234.137.30"
|
||||
reserved_addrs:
|
||||
- "173.234.137.16"
|
||||
ipv6:
|
||||
- subnet: "2a0d:3003:b666:a00c:2::/112"
|
||||
ipv6_ranges:
|
||||
- first_ip: "2a0d:3003:b666:a00c:0002:0000:0000:0011"
|
||||
last_ip: "2a0d:3003:b666:a00c:0002:0000:0000:fffc"
|
||||
netmask: "64"
|
||||
gateway: "2a0d:3003:b666:a00c::1"
|
||||
reserved_addrs: []
|
||||
volumes:
|
||||
- path: "/opt/detee_vms/"
|
||||
max_reservation_gb: 200
|
||||
|
3
rustfmt.toml
Normal file
3
rustfmt.toml
Normal file
@ -0,0 +1,3 @@
|
||||
reorder_impl_items = true
|
||||
use_small_heuristics = "Max"
|
||||
imports_granularity = "Crate"
|
@ -1,4 +1,5 @@
|
||||
#!/bin/bash
|
||||
OVMF_PATH="/var/lib/detee/boot/0346619257269b9a61ee003e197d521b8e2283483070d163a34940d6a1d40d76";
|
||||
|
||||
[[ -z "$VM_UUID" ]] && {
|
||||
echo "Environment variable VM_UUID is not set."
|
||||
@ -65,7 +66,7 @@ qemu-system-x86_64 $qemu_device_params \
|
||||
-machine q35,confidential-guest-support=sev0,memory-backend=ram1 \
|
||||
-smp $VCPUS,maxcpus=$VCPUS \
|
||||
-m $MEMORY,slots=5,maxmem=$MAX_MEMORY \
|
||||
-no-reboot -bios /usr/share/edk2/ovmf/OVMF.amdsev.fd \
|
||||
-no-reboot -bios "$OVMF_PATH" \
|
||||
-drive file=${DISK},if=none,id=disk0,format=qcow2 \
|
||||
-device virtio-blk-pci,drive=disk0 \
|
||||
-object memory-backend-memfd,id=ram1,size=$MEMORY,share=true,prealloc=false \
|
||||
|
114
src/config.rs
114
src/config.rs
@ -1,9 +1,10 @@
|
||||
#![allow(dead_code)]
|
||||
use cidr::{Ipv4Cidr, Ipv6Cidr};
|
||||
use anyhow::Result;
|
||||
use serde::Deserialize;
|
||||
use std::collections::HashSet;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
use std::ops::Range;
|
||||
use std::{
|
||||
net::{Ipv4Addr, Ipv6Addr},
|
||||
ops::Range,
|
||||
};
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
pub struct Volume {
|
||||
@ -13,24 +14,26 @@ pub struct Volume {
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct IPv4Range {
|
||||
pub subnet: Ipv4Cidr,
|
||||
pub first_ip: Ipv4Addr,
|
||||
pub last_ip: Ipv4Addr,
|
||||
pub netmask: String,
|
||||
pub gateway: Ipv4Addr,
|
||||
pub reserved_addrs: HashSet<Ipv4Addr>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct IPv6Range {
|
||||
pub subnet: Ipv6Cidr,
|
||||
pub first_ip: Ipv6Addr,
|
||||
pub last_ip: Ipv6Addr,
|
||||
pub netmask: String,
|
||||
pub gateway: Ipv6Addr,
|
||||
pub reserved_addrs: HashSet<Ipv6Addr>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Interface {
|
||||
pub driver: InterfaceType,
|
||||
pub device: String,
|
||||
pub ipv4: Vec<IPv4Range>,
|
||||
pub ipv6: Vec<IPv6Range>,
|
||||
pub ipv4_ranges: Vec<IPv4Range>,
|
||||
pub ipv6_ranges: Vec<IPv6Range>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
@ -42,6 +45,7 @@ pub enum InterfaceType {
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Config {
|
||||
pub brain_url: String,
|
||||
pub max_cores_per_vm: usize,
|
||||
pub max_vcpu_reservation: usize,
|
||||
pub max_mem_reservation_mb: usize,
|
||||
@ -60,10 +64,7 @@ mod range_format {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let range_repr = RangeRepr {
|
||||
start: range.start,
|
||||
end: range.end,
|
||||
};
|
||||
let range_repr = RangeRepr { start: range.start, end: range.end };
|
||||
range_repr.serialize(serializer)
|
||||
}
|
||||
|
||||
@ -83,10 +84,93 @@ mod range_format {
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn load_from_disk(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
pub fn load_from_disk(path: &str) -> Result<Self> {
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
let config: Config = serde_yaml::from_str(&content)?;
|
||||
for nic in &config.network_interfaces {
|
||||
for range in &nic.ipv4_ranges {
|
||||
let ipv4_netmask = range.netmask.parse::<u8>()?;
|
||||
if ipv4_netmask > 32 {
|
||||
return Err(anyhow::anyhow!(
|
||||
"IPv4 netmask must be in short format: a number from 1 to 32"
|
||||
));
|
||||
}
|
||||
if range.first_ip.to_bits() > range.last_ip.to_bits() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"For range {range:?} first ip is bigger than last ip."
|
||||
));
|
||||
}
|
||||
let expected_netmask = std::cmp::min(
|
||||
calc_ipv4_netmask(range.first_ip, range.gateway),
|
||||
calc_ipv4_netmask(range.last_ip, range.gateway),
|
||||
);
|
||||
if expected_netmask < ipv4_netmask as u32 {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Your netmask is too small to include the IPs and also the gateway: {range:?}"
|
||||
));
|
||||
}
|
||||
}
|
||||
for range in &nic.ipv6_ranges {
|
||||
let ipv6_netmask = range.netmask.parse::<u8>()?;
|
||||
if ipv6_netmask > 128 {
|
||||
return Err(anyhow::anyhow!(
|
||||
"IPv6 netmask must be in short format: a number from 1 to 128"
|
||||
));
|
||||
}
|
||||
if range.first_ip.to_bits() > range.last_ip.to_bits() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"For range {range:?} first ip is bigger than last ip."
|
||||
));
|
||||
}
|
||||
let expected_netmask = std::cmp::min(
|
||||
calc_ipv6_netmask(range.first_ip, range.gateway),
|
||||
calc_ipv6_netmask(range.last_ip, range.gateway),
|
||||
);
|
||||
if expected_netmask < ipv6_netmask as u128 {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Your netmask is too small to include the IPs and also the gateway: {range:?}"
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(config)
|
||||
}
|
||||
}
|
||||
|
||||
fn calc_ipv4_netmask(ip: Ipv4Addr, gateway: Ipv4Addr) -> u32 {
|
||||
// Convert the IPs to u32 for easier bit manipulation
|
||||
let ip_u32 = u32::from(ip);
|
||||
let gateway_u32 = u32::from(gateway);
|
||||
|
||||
// Find the smallest common prefix
|
||||
let mut prefix_len = 0;
|
||||
for i in 1..=32 {
|
||||
if (ip_u32 >> (32 - i)) == (gateway_u32 >> (32 - i)) {
|
||||
prefix_len = i;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the mask as a string
|
||||
prefix_len
|
||||
}
|
||||
|
||||
fn calc_ipv6_netmask(ip: Ipv6Addr, gateway: Ipv6Addr) -> u128 {
|
||||
// Convert the IPs to u128 for easier bit manipulation
|
||||
let ip_u128 = u128::from(ip);
|
||||
let gateway_u128 = u128::from(gateway);
|
||||
|
||||
// Find the smallest common prefix
|
||||
let mut prefix_len = 0;
|
||||
for i in 1..=128 {
|
||||
if (ip_u128 >> (128 - i)) == (gateway_u128 >> (128 - i)) {
|
||||
prefix_len = i;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the mask as a string
|
||||
prefix_len
|
||||
}
|
||||
|
@ -2,9 +2,13 @@
|
||||
|
||||
pub(crate) const DEFAULT_OVMF: &str = "/usr/share/edk2/ovmf/OVMF.amdsev.fd";
|
||||
pub(crate) const VM_BOOT_DIR: &str = "/var/lib/detee/boot/";
|
||||
pub(crate) const USED_RESOURCES: &str = "/etc/detee/daemon/used_resources.yaml";
|
||||
pub(crate) const VM_CONFIG_DIR: &str = "/etc/detee/daemon/vms/";
|
||||
pub(crate) const USED_RESOURCES: &str = "/etc/detee/daemon/used_resources.yaml";
|
||||
pub(crate) const VM_CONFIG_DIR: &str = "/etc/detee/daemon/vms/";
|
||||
pub(crate) const SECRET_KEY_PATH: &str = "/etc/detee/daemon/node_secret_key.pem";
|
||||
pub(crate) const DAEMON_CONFIG_PATH: &str = "/etc/detee/daemon/config.yaml";
|
||||
pub(crate) const START_VM_SCRIPT: &str = "/usr/local/bin/detee/start_qemu_vm.sh";
|
||||
// TODO: research if other CPU types provide better performance
|
||||
pub(crate) const QEMU_VM_CPU_TYPE: &str = "EPYC-v4";
|
||||
// If you modify this, also modify scripts/start_qemu_vm.sh
|
||||
pub(crate) const OVMF_HASH: &str = "0346619257269b9a61ee003e197d521b8e2283483070d163a34940d6a1d40d76";
|
||||
pub(crate) const OVMF_URL: &str = "https://drive.google.com/uc?export=download&id=1V-vLkaiLaGmFSjrN84Z6nELQOxKNAoSJ";
|
||||
|
226
src/grpc.rs
Normal file
226
src/grpc.rs
Normal file
@ -0,0 +1,226 @@
|
||||
#![allow(dead_code)]
|
||||
pub mod brain {
|
||||
tonic::include_proto!("brain");
|
||||
}
|
||||
|
||||
use anyhow::Result;
|
||||
use brain::{
|
||||
brain_daemon_service_client::BrainDaemonServiceClient, DeleteVmReq, ListVmContractsReq,
|
||||
NewVmReq, NewVmResp, NodePubkey, NodeResourceReq, RegisterNodeReq, UpdateVmReq, UpdateVmResp,
|
||||
VmContract,
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
use log::{debug, error, info, warn};
|
||||
use std::{fs::File, io::Write};
|
||||
use tokio::{
|
||||
sync::mpsc::{Receiver, Sender},
|
||||
task::JoinSet,
|
||||
};
|
||||
use tokio_stream::{wrappers::ReceiverStream, StreamExt};
|
||||
use tonic::transport::Channel;
|
||||
|
||||
lazy_static! {
|
||||
static ref PUBLIC_KEY: String = get_public_key();
|
||||
}
|
||||
|
||||
fn create_secret_key() -> Result<ed25519_dalek::SigningKey> {
|
||||
use ed25519_dalek::pkcs8::{spki::der::pem::LineEnding, EncodePrivateKey};
|
||||
let key_path = crate::constants::SECRET_KEY_PATH;
|
||||
info!("Creating new secret key at {}", key_path);
|
||||
let sk = ed25519_dalek::SigningKey::generate(&mut rand_core::OsRng);
|
||||
let sk_pem = sk.to_pkcs8_pem(LineEnding::default()).unwrap();
|
||||
let mut file = File::create(key_path)?;
|
||||
file.write_all(sk_pem.as_bytes())?;
|
||||
Ok(sk)
|
||||
}
|
||||
|
||||
fn load_secret_key() -> Result<ed25519_dalek::SigningKey> {
|
||||
use ed25519_dalek::pkcs8::DecodePrivateKey;
|
||||
let secret_key_pem = match std::fs::read_to_string(crate::constants::SECRET_KEY_PATH) {
|
||||
Ok(secret_key_pem) => secret_key_pem,
|
||||
Err(e) => {
|
||||
warn!("Could not load secret key due to error: {e:?}");
|
||||
return Ok(create_secret_key()?);
|
||||
}
|
||||
};
|
||||
Ok(ed25519_dalek::SigningKey::from_pkcs8_pem(&secret_key_pem)?)
|
||||
}
|
||||
|
||||
pub fn get_public_key() -> String {
|
||||
use ed25519_dalek::pkcs8::{spki::der::pem::LineEnding, EncodePublicKey};
|
||||
let pubkey = load_secret_key()
|
||||
.unwrap()
|
||||
.verifying_key()
|
||||
.to_public_key_pem(LineEnding::default())
|
||||
.unwrap()
|
||||
.lines()
|
||||
.nth(1)
|
||||
.unwrap()
|
||||
.to_string();
|
||||
log::info!("Loaded the following public key: {pubkey}");
|
||||
pubkey
|
||||
}
|
||||
|
||||
pub async fn list_contracts(brain_url: String) -> Result<Vec<VmContract>> {
|
||||
let mut client = BrainDaemonServiceClient::connect(brain_url).await?;
|
||||
let mut contracts = Vec::new();
|
||||
let mut grpc_stream = client
|
||||
.list_vm_contracts(ListVmContractsReq {
|
||||
node_pubkey: PUBLIC_KEY.to_string(),
|
||||
..Default::default()
|
||||
})
|
||||
.await?
|
||||
.into_inner();
|
||||
while let Some(stream_update) = grpc_stream.next().await {
|
||||
match stream_update {
|
||||
Ok(node) => {
|
||||
debug!("Received contract from brain: {node:?}");
|
||||
contracts.push(node);
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Received error instead of contracts: {e:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
info!("Brain terminated list_contracts stream.");
|
||||
Ok(contracts)
|
||||
}
|
||||
|
||||
async fn listen_for_new_vm_reqs(
|
||||
mut client: BrainDaemonServiceClient<Channel>,
|
||||
tx: Sender<NewVmReq>,
|
||||
) -> Result<()> {
|
||||
debug!("starting listen_for_new_vm_reqs");
|
||||
let node_pubkey = PUBLIC_KEY.clone();
|
||||
let mut grpc_stream = client.get_new_vm_reqs(NodePubkey { node_pubkey }).await?.into_inner();
|
||||
while let Some(stream_update) = grpc_stream.next().await {
|
||||
match stream_update {
|
||||
Ok(req) => {
|
||||
info!("Received new vm request: {req:?}");
|
||||
let _ = tx.send(req).await;
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Brain disconnected from listen_for_new_vm_reqs: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
debug!("listen_for_new_vm_reqs is about to exit");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn send_newvm_resp(
|
||||
mut client: BrainDaemonServiceClient<Channel>,
|
||||
rx: Receiver<NewVmResp>,
|
||||
) -> Result<()> {
|
||||
debug!("starting send_newvm_resp stream");
|
||||
let rx_stream = ReceiverStream::new(rx);
|
||||
client.send_new_vm_resp(rx_stream).await?;
|
||||
debug!("send_newvm_resp is about to exit");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn send_node_resources(
|
||||
mut client: BrainDaemonServiceClient<Channel>,
|
||||
rx: Receiver<NodeResourceReq>,
|
||||
) -> Result<()> {
|
||||
debug!("starting send_newvm_resp stream");
|
||||
let rx_stream = ReceiverStream::new(rx).map(|mut node_resources| {
|
||||
node_resources.node_pubkey = get_public_key();
|
||||
node_resources
|
||||
});
|
||||
client.send_node_resources(rx_stream).await?;
|
||||
debug!("send_newvm_resp is about to exit");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn register_node(mut client: BrainDaemonServiceClient<Channel>) {
|
||||
debug!("Starting node registration...");
|
||||
let req = RegisterNodeReq {
|
||||
node_pubkey: PUBLIC_KEY.clone(),
|
||||
owner_pubkey: "IamTheOwnerOf".to_string() + &PUBLIC_KEY,
|
||||
};
|
||||
match client.register_node(req).await {
|
||||
Ok(_) => {
|
||||
info!("Registered as 10.0.10.1 from Bruma/Cyrodiil with ID {}", PUBLIC_KEY.clone())
|
||||
}
|
||||
Err(e) => error!("Could not register node data: {e:?}"),
|
||||
};
|
||||
}
|
||||
|
||||
async fn listen_for_deleted_vms(
|
||||
mut client: BrainDaemonServiceClient<Channel>,
|
||||
tx: Sender<DeleteVmReq>,
|
||||
) -> Result<()> {
|
||||
debug!("starting listen_for_new_vm_reqs");
|
||||
let node_pubkey = PUBLIC_KEY.clone();
|
||||
let mut grpc_stream = client.get_delete_vm_req(NodePubkey { node_pubkey }).await?.into_inner();
|
||||
while let Some(stream_update) = grpc_stream.next().await {
|
||||
match stream_update {
|
||||
Ok(req) => {
|
||||
info!("Received delete vm request: {req:?}");
|
||||
let _ = tx.send(req).await;
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Brain disconnected from listen_for_deleted_vms: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
debug!("listen_for_new_vm_reqs is about to exit");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn listen_for_update_vm_reqs(
|
||||
mut client: BrainDaemonServiceClient<Channel>,
|
||||
tx: Sender<UpdateVmReq>,
|
||||
) -> Result<()> {
|
||||
debug!("starting listen_for_update_vm_reqs");
|
||||
let node_pubkey = PUBLIC_KEY.clone();
|
||||
let mut grpc_stream = client.get_update_vm_req(NodePubkey { node_pubkey }).await?.into_inner();
|
||||
while let Some(stream_update) = grpc_stream.next().await {
|
||||
match stream_update {
|
||||
Ok(req) => {
|
||||
info!("Received update vm request: {req:?}");
|
||||
let _ = tx.send(req).await;
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Brain disconnected from listen_for_update_vm_reqs: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
debug!("listen_for_update_vm_reqs is about to exit");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn send_updatevm_resp(
|
||||
mut client: BrainDaemonServiceClient<Channel>,
|
||||
rx: Receiver<UpdateVmResp>,
|
||||
) -> Result<()> {
|
||||
debug!("starting send_updatevm_resp stream");
|
||||
let rx_stream = ReceiverStream::new(rx);
|
||||
client.send_update_vm_resp(rx_stream).await?;
|
||||
debug!("send_updatevm_resp is about to exit");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct ConnectionData {
|
||||
pub brain_url: String,
|
||||
pub newvm_tx: Sender<NewVmReq>,
|
||||
pub confirm_vm_rx: Receiver<NewVmResp>,
|
||||
pub delete_vm_tx: Sender<DeleteVmReq>,
|
||||
pub resources_rx: Receiver<NodeResourceReq>,
|
||||
}
|
||||
|
||||
pub async fn connect_and_run(cd: ConnectionData) -> Result<()> {
|
||||
let client = BrainDaemonServiceClient::connect(cd.brain_url).await?;
|
||||
let mut streaming_tasks = JoinSet::new();
|
||||
|
||||
register_node(client.clone()).await;
|
||||
streaming_tasks.spawn(listen_for_new_vm_reqs(client.clone(), cd.newvm_tx));
|
||||
streaming_tasks.spawn(send_newvm_resp(client.clone(), cd.confirm_vm_rx));
|
||||
streaming_tasks.spawn(listen_for_deleted_vms(client.clone(), cd.delete_vm_tx));
|
||||
streaming_tasks.spawn(send_node_resources(client.clone(), cd.resources_rx));
|
||||
|
||||
let task_output = streaming_tasks.join_next().await;
|
||||
warn!("One stream exited: {task_output:?}");
|
||||
Ok(())
|
||||
}
|
284
src/main.rs
284
src/main.rs
@ -1,62 +1,234 @@
|
||||
#[allow(dead_code)]
|
||||
mod config;
|
||||
mod constants;
|
||||
mod grpc;
|
||||
mod state;
|
||||
mod tcontract;
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::state::NewVMRequest;
|
||||
use crate::state::UpdateVMReq;
|
||||
use std::fs::read_dir;
|
||||
use crate::{config::Config, grpc::brain};
|
||||
use anyhow::Result;
|
||||
use log::{debug, info, warn};
|
||||
use tokio::{
|
||||
sync::mpsc::{Receiver, Sender},
|
||||
time::{sleep, Duration},
|
||||
};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let config = Config::load_from_disk(crate::constants::DAEMON_CONFIG_PATH)?;
|
||||
let mut res = match state::Resources::load_from_disk() {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
println!("Could not load resources from disk: {e:?}");
|
||||
println!("Creating new resource calculator.");
|
||||
state::Resources::new(&config.volumes)
|
||||
}
|
||||
};
|
||||
|
||||
for entry in read_dir("/etc/detee/daemon/newvmreq/")? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if path.is_file() {
|
||||
let new_vm_req = NewVMRequest::from_file(path.to_str().unwrap())?;
|
||||
let vm = state::VM::new(new_vm_req, &config, &mut res).unwrap();
|
||||
vm.start()?;
|
||||
println!("started vm {}", vm.uuid);
|
||||
}
|
||||
}
|
||||
|
||||
for entry in read_dir("/etc/detee/daemon/deletevm/")? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if path.is_file() {
|
||||
let vm_id = path.file_name().unwrap().to_str().unwrap();
|
||||
let content = std::fs::read_to_string(
|
||||
crate::constants::VM_CONFIG_DIR.to_string() + vm_id + ".yaml",
|
||||
)?;
|
||||
let vm: crate::state::VM = serde_yaml::from_str(&content)?;
|
||||
vm.delete(&mut res)?;
|
||||
println!("deleted vm {}", vm.uuid);
|
||||
}
|
||||
}
|
||||
|
||||
for entry in read_dir("/etc/detee/daemon/updatedvmreq/")? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if path.is_file() {
|
||||
let update_vm_req = UpdateVMReq::from_file(path.to_str().unwrap())?;
|
||||
let content = std::fs::read_to_string(
|
||||
crate::constants::VM_CONFIG_DIR.to_string() + &update_vm_req.uuid + ".yaml",
|
||||
)?;
|
||||
let mut vm: crate::state::VM = serde_yaml::from_str(&content)?;
|
||||
vm.update(update_vm_req, &config, &mut res).unwrap();
|
||||
println!("updated vm {}", vm.uuid);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
#[allow(dead_code)]
|
||||
struct VMHandler {
|
||||
new_vm_req_chan: Receiver<brain::NewVmReq>,
|
||||
new_vm_resp_chan: Sender<brain::NewVmResp>,
|
||||
delete_vm_chan: Receiver<brain::DeleteVmReq>,
|
||||
resources_chan: Sender<brain::NodeResourceReq>,
|
||||
config: Config,
|
||||
res: state::Resources,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl VMHandler {
|
||||
fn new(
|
||||
new_vm_req_chan: Receiver<brain::NewVmReq>,
|
||||
new_vm_resp_chan: Sender<brain::NewVmResp>,
|
||||
delete_vm_chan: Receiver<brain::DeleteVmReq>,
|
||||
resources_chan: Sender<brain::NodeResourceReq>,
|
||||
) -> Self {
|
||||
let config = match Config::load_from_disk(crate::constants::DAEMON_CONFIG_PATH) {
|
||||
Ok(config) => config,
|
||||
Err(e) => panic!("Could not load config: {e:?}"),
|
||||
};
|
||||
let res = match state::Resources::load_from_disk() {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
warn!("Could not load resources from disk: {e:?}");
|
||||
info!("Creating new resource calculator.");
|
||||
state::Resources::new(&config.volumes)
|
||||
}
|
||||
};
|
||||
Self { new_vm_req_chan, new_vm_resp_chan, delete_vm_chan, resources_chan, config, res }
|
||||
}
|
||||
|
||||
fn get_available_ips(&self) -> (u32, u32) {
|
||||
let mut avail_ipv4 = 0;
|
||||
let mut avail_ipv6 = 0;
|
||||
for nic in self.config.network_interfaces.iter() {
|
||||
for range in nic.ipv4_ranges.iter() {
|
||||
avail_ipv4 += (range.last_ip.to_bits() + 1) - range.first_ip.to_bits();
|
||||
}
|
||||
for range in nic.ipv6_ranges.iter() {
|
||||
avail_ipv6 += (range.last_ip.to_bits() + 1) - range.first_ip.to_bits();
|
||||
}
|
||||
}
|
||||
(
|
||||
avail_ipv4.saturating_sub(self.res.reserved_ipv4.len() as u32),
|
||||
avail_ipv6.saturating_sub(self.res.reserved_ipv6.len() as u128) as u32,
|
||||
)
|
||||
}
|
||||
|
||||
async fn send_node_resources(&mut self) {
|
||||
let (avail_ipv4, avail_ipv6) = self.get_available_ips();
|
||||
let mut avail_storage_gb = 0;
|
||||
for volume in self.config.volumes.iter() {
|
||||
avail_storage_gb += volume.max_reservation_gb;
|
||||
if let Some(reservation) = self.res.reserved_storage.get(&volume.path) {
|
||||
avail_storage_gb -= reservation;
|
||||
}
|
||||
}
|
||||
let avail_storage_gb = avail_storage_gb as u32;
|
||||
let res = brain::NodeResourceReq {
|
||||
node_pubkey: String::new(),
|
||||
avail_ports: (self.config.public_port_range.len() - self.res.reserved_ports.len())
|
||||
as u32,
|
||||
avail_ipv4,
|
||||
avail_ipv6,
|
||||
avail_vcpus: (self.config.max_vcpu_reservation - self.res.reserved_vcpus) as u32,
|
||||
avail_memory_mb: (self.config.max_mem_reservation_mb - self.res.reserved_memory) as u32,
|
||||
avail_storage_gb,
|
||||
max_ports_per_vm: self.config.max_ports_per_vm as u32,
|
||||
};
|
||||
debug!("sending node resources on brain: {res:?}");
|
||||
let _ = self.resources_chan.send(res).await;
|
||||
}
|
||||
|
||||
async fn handle_new_vm_req(&mut self, new_vm_req: brain::NewVmReq) {
|
||||
debug!("Processing new vm request: {new_vm_req:?}");
|
||||
let uuid = new_vm_req.uuid.clone();
|
||||
match state::VM::new(new_vm_req.into(), &self.config, &mut self.res) {
|
||||
Ok(vm) => match vm.start() {
|
||||
Ok(_) => {
|
||||
info!("Succesfully started VM {uuid}");
|
||||
let _ = self.new_vm_resp_chan.send(vm.into()).await;
|
||||
self.send_node_resources().await;
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Could not start VM {uuid}: {e:?}");
|
||||
let _ = self
|
||||
.new_vm_resp_chan
|
||||
.send(brain::NewVmResp {
|
||||
uuid,
|
||||
error: "This node has an internal error. Choose another node."
|
||||
.to_string(),
|
||||
..Default::default()
|
||||
})
|
||||
.await;
|
||||
}
|
||||
},
|
||||
Err(e) => match e {
|
||||
crate::state::VMCreationErrors::VMAlreadyExists(vm) => {
|
||||
log::info!(
|
||||
"Got NewVmReq for VM {}, that already exist. Will send NewVmResp.",
|
||||
vm.uuid
|
||||
);
|
||||
let _ = self.new_vm_resp_chan.send(vm.into()).await;
|
||||
}
|
||||
_ => {
|
||||
warn!("Refusing to service vm {uuid} due to error: {e:?}");
|
||||
let _ = self
|
||||
.new_vm_resp_chan
|
||||
.send(brain::NewVmResp {
|
||||
uuid,
|
||||
error: format!("{e:?}"),
|
||||
..Default::default()
|
||||
})
|
||||
.await;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_delete_vm(&mut self, delete_vm_req: brain::DeleteVmReq) -> Result<()> {
|
||||
let vm_id = delete_vm_req.uuid;
|
||||
let content =
|
||||
std::fs::read_to_string(constants::VM_CONFIG_DIR.to_string() + &vm_id + ".yaml")?;
|
||||
let vm: state::VM = serde_yaml::from_str(&content)?;
|
||||
vm.delete(&mut self.res)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn run(mut self) {
|
||||
self.send_node_resources().await;
|
||||
loop {
|
||||
tokio::select! {
|
||||
Some(new_vm_req) = self.new_vm_req_chan.recv() => {
|
||||
self.handle_new_vm_req(new_vm_req).await;
|
||||
}
|
||||
Some(delete_vm_req) = self.delete_vm_chan.recv() => {
|
||||
let uuid = delete_vm_req.uuid.clone();
|
||||
if let Err(e) = self.handle_delete_vm(delete_vm_req) {
|
||||
log::error!("Could not delete vm {uuid}: {e:?}");
|
||||
} else {
|
||||
self.send_node_resources().await;
|
||||
}
|
||||
}
|
||||
else => {
|
||||
log::error!("All data channels closed.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clear_deleted_contracts(&mut self, contracts: Vec<brain::VmContract>) {
|
||||
for uuid in self.res.existing_vms.clone() {
|
||||
if contracts.iter().find(|c| c.uuid == uuid).is_none() {
|
||||
info!("VM {uuid} exists locally but not found in brain. Deleting...");
|
||||
let content = match std::fs::read_to_string(
|
||||
crate::constants::VM_CONFIG_DIR.to_string() + &uuid + ".yaml",
|
||||
) {
|
||||
Ok(content) => content,
|
||||
Err(e) => {
|
||||
log::error!("Could not find VM config for {uuid}. Cannot delete VM: {e:?}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let vm: crate::state::VM = match serde_yaml::from_str(&content) {
|
||||
Ok(vm) => vm,
|
||||
Err(e) => {
|
||||
log::error!("VM config corrupted for {uuid}. Cannot delete VM: {e:?}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
match vm.delete(&mut self.res) {
|
||||
Ok(()) => info!("Successfully deleted VM {uuid}"),
|
||||
Err(e) => log::error!("Deletion failed for VM {uuid}: {e:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
env_logger::builder().filter_level(log::LevelFilter::Debug).init();
|
||||
|
||||
loop {
|
||||
let (newvm_tx, newvm_rx) = tokio::sync::mpsc::channel(6);
|
||||
let (confirm_vm_tx, confirm_vm_rx) = tokio::sync::mpsc::channel(6);
|
||||
let (delete_vm_tx, delete_vm_rx) = tokio::sync::mpsc::channel(6);
|
||||
let (resources_tx, resources_rx) = tokio::sync::mpsc::channel(6);
|
||||
|
||||
let mut vm_handler = VMHandler::new(newvm_rx, confirm_vm_tx, delete_vm_rx, resources_tx);
|
||||
let brain_url = vm_handler.config.brain_url.clone();
|
||||
|
||||
info!("Trying to get VM Contracts from Brain to see if some Contracts got removed...");
|
||||
match grpc::list_contracts(brain_url.clone()).await {
|
||||
Ok(contracts) => vm_handler.clear_deleted_contracts(contracts),
|
||||
Err(e) => log::error!("Could not get contracts from brain: {e:?}"),
|
||||
};
|
||||
|
||||
tokio::spawn(async move {
|
||||
vm_handler.run().await;
|
||||
});
|
||||
|
||||
info!("Connecting to brain...");
|
||||
if let Err(e) = grpc::connect_and_run(grpc::ConnectionData {
|
||||
brain_url,
|
||||
newvm_tx,
|
||||
confirm_vm_rx,
|
||||
delete_vm_tx,
|
||||
resources_rx,
|
||||
})
|
||||
.await
|
||||
{
|
||||
log::error!("The connection broke: {e}");
|
||||
}
|
||||
sleep(Duration::from_secs(3)).await;
|
||||
}
|
||||
}
|
||||
|
355
src/state.rs
355
src/state.rs
@ -1,32 +1,28 @@
|
||||
#![allow(dead_code)]
|
||||
use crate::config::Config;
|
||||
use crate::constants::*;
|
||||
use anyhow::anyhow;
|
||||
use anyhow::Result;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use crate::{config::Config, constants::*, grpc::brain};
|
||||
use anyhow::{anyhow, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::fs;
|
||||
use std::fs::remove_file;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::io::Write;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
fs,
|
||||
fs::{remove_file, File},
|
||||
io::{Read, Write},
|
||||
path::Path,
|
||||
process::Command,
|
||||
};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Resources {
|
||||
existing_vms: HashSet<String>,
|
||||
pub existing_vms: HashSet<String>,
|
||||
// QEMU does not support MHz limiation
|
||||
reserved_vcpus: usize,
|
||||
reserved_memory: usize,
|
||||
reserved_ports: HashSet<u16>,
|
||||
reserved_storage: HashMap<String, usize>,
|
||||
reserved_ips: HashSet<String>,
|
||||
reserved_if_names: HashSet<String>,
|
||||
pub reserved_vcpus: usize,
|
||||
pub reserved_memory: usize,
|
||||
pub reserved_ports: HashSet<u16>,
|
||||
pub reserved_storage: HashMap<String, usize>,
|
||||
pub reserved_ipv4: HashSet<String>,
|
||||
pub reserved_ipv6: HashSet<String>,
|
||||
pub reserved_if_names: HashSet<String>,
|
||||
// sha256sum -> absolute path
|
||||
boot_files: HashSet<String>,
|
||||
}
|
||||
@ -60,7 +56,8 @@ impl Resources {
|
||||
reserved_memory: 0,
|
||||
reserved_ports: HashSet::new(),
|
||||
reserved_storage: HashMap::new(),
|
||||
reserved_ips: HashSet::new(),
|
||||
reserved_ipv4: HashSet::new(),
|
||||
reserved_ipv6: HashSet::new(),
|
||||
reserved_if_names: HashSet::new(),
|
||||
boot_files: HashSet::new(),
|
||||
};
|
||||
@ -111,11 +108,8 @@ impl Resources {
|
||||
fn available_if_name(&mut self) -> String {
|
||||
use rand::{distributions::Alphanumeric, Rng};
|
||||
loop {
|
||||
let mut interface_name: String = rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(9)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
let mut interface_name: String =
|
||||
rand::thread_rng().sample_iter(&Alphanumeric).take(9).map(char::from).collect();
|
||||
interface_name = "detee".to_string() + &interface_name;
|
||||
if !self.reserved_if_names.contains(&interface_name) {
|
||||
return interface_name;
|
||||
@ -123,13 +117,15 @@ impl Resources {
|
||||
}
|
||||
}
|
||||
|
||||
fn available_ipv4(&mut self, config: &Config) -> Option<VMNIC> {
|
||||
for nic in config.network_interfaces.iter() {
|
||||
for range in nic.ipv4.iter() {
|
||||
for ip in range.subnet.iter().skip(1) {
|
||||
if !range.reserved_addrs.contains(&ip.address())
|
||||
&& !self.reserved_ips.contains(&ip.address().to_string())
|
||||
&& ip.address() != range.gateway
|
||||
fn available_ipv4(&mut self, nics: &Vec<crate::config::Interface>) -> Option<VMNIC> {
|
||||
for nic in nics.iter() {
|
||||
for range in nic.ipv4_ranges.iter() {
|
||||
let first_ip = range.first_ip.to_bits();
|
||||
let last_ip = range.last_ip.to_bits();
|
||||
for ip in first_ip..last_ip + 1 {
|
||||
let ip_addr = std::net::Ipv4Addr::from_bits(ip);
|
||||
if !self.reserved_ipv4.contains(&ip_addr.to_string())
|
||||
&& ip_addr != range.gateway
|
||||
{
|
||||
let if_config = match nic.driver {
|
||||
crate::config::InterfaceType::MACVTAP => InterfaceConfig::MACVTAP {
|
||||
@ -140,14 +136,14 @@ impl Resources {
|
||||
name: self.available_if_name(),
|
||||
device: nic.device.clone(),
|
||||
},
|
||||
crate::config::InterfaceType::Bridge => InterfaceConfig::Bridge {
|
||||
device: nic.device.clone(),
|
||||
},
|
||||
crate::config::InterfaceType::Bridge => {
|
||||
InterfaceConfig::Bridge { device: nic.device.clone() }
|
||||
}
|
||||
};
|
||||
let mut ips = Vec::new();
|
||||
ips.push(IPConfig {
|
||||
address: ip.address().to_string(),
|
||||
mask: calc_ipv4_netmask(ip.address(), range.gateway),
|
||||
address: ip_addr.to_string(),
|
||||
mask: range.netmask.clone(),
|
||||
gateway: range.gateway.to_string(),
|
||||
});
|
||||
return Some(VMNIC { if_config, ips });
|
||||
@ -158,13 +154,15 @@ impl Resources {
|
||||
None
|
||||
}
|
||||
|
||||
fn available_ipv6(&mut self, config: &Config) -> Option<VMNIC> {
|
||||
for nic in config.network_interfaces.iter() {
|
||||
for range in nic.ipv6.iter() {
|
||||
for ip in range.subnet.iter().skip(1) {
|
||||
if !range.reserved_addrs.contains(&ip.address())
|
||||
&& !self.reserved_ips.contains(&ip.address().to_string())
|
||||
&& ip.address() != range.gateway
|
||||
fn available_ipv6(&mut self, nics: &Vec<crate::config::Interface>) -> Option<VMNIC> {
|
||||
for nic in nics.iter() {
|
||||
for range in nic.ipv6_ranges.iter() {
|
||||
let first_ip = range.first_ip.to_bits();
|
||||
let last_ip = range.last_ip.to_bits();
|
||||
for ip in first_ip..last_ip + 1 {
|
||||
let ip_addr = std::net::Ipv6Addr::from_bits(ip);
|
||||
if !self.reserved_ipv6.contains(&ip_addr.to_string())
|
||||
&& ip_addr != range.gateway
|
||||
{
|
||||
let if_config = match nic.driver {
|
||||
crate::config::InterfaceType::MACVTAP => InterfaceConfig::MACVTAP {
|
||||
@ -175,14 +173,14 @@ impl Resources {
|
||||
name: self.available_if_name(),
|
||||
device: nic.device.clone(),
|
||||
},
|
||||
crate::config::InterfaceType::Bridge => InterfaceConfig::Bridge {
|
||||
device: nic.device.clone(),
|
||||
},
|
||||
crate::config::InterfaceType::Bridge => {
|
||||
InterfaceConfig::Bridge { device: nic.device.clone() }
|
||||
}
|
||||
};
|
||||
let mut ips = Vec::new();
|
||||
ips.push(IPConfig {
|
||||
address: ip.address().to_string(),
|
||||
mask: calc_ipv6_netmask(ip.address(), range.gateway),
|
||||
address: ip_addr.to_string(),
|
||||
mask: range.netmask.clone(),
|
||||
gateway: range.gateway.to_string(),
|
||||
});
|
||||
return Some(VMNIC { if_config, ips });
|
||||
@ -213,7 +211,7 @@ impl Resources {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn download_boot_file(&mut self, url: String, sha: String) -> Result<()> {
|
||||
fn find_or_download_file(&mut self, url: String, sha: String) -> Result<()> {
|
||||
if !self.boot_files.contains(&sha) {
|
||||
download_and_check_sha(&url, &sha)?;
|
||||
}
|
||||
@ -230,7 +228,14 @@ impl Resources {
|
||||
self.reserved_if_names.insert(vtap);
|
||||
}
|
||||
for ip in nic.ips.iter() {
|
||||
self.reserved_ips.insert(ip.address.clone());
|
||||
if let Ok(ip_address) = ip.address.parse::<std::net::IpAddr>() {
|
||||
if ip_address.is_ipv4() {
|
||||
self.reserved_ipv4.insert(ip.address.clone());
|
||||
}
|
||||
if ip_address.is_ipv6() {
|
||||
self.reserved_ipv6.insert(ip.address.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (host_port, _) in vm.fw_ports.iter() {
|
||||
@ -253,15 +258,20 @@ impl Resources {
|
||||
self.reserved_if_names.remove(&vtap);
|
||||
}
|
||||
for ip in nic.ips.iter() {
|
||||
self.reserved_ips.remove(&ip.address.clone());
|
||||
if let Ok(ip_address) = ip.address.parse::<std::net::IpAddr>() {
|
||||
if ip_address.is_ipv4() {
|
||||
self.reserved_ipv4.remove(&ip.address);
|
||||
}
|
||||
if ip_address.is_ipv6() {
|
||||
self.reserved_ipv6.remove(&ip.address);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (host_port, _) in vm.fw_ports.iter() {
|
||||
self.reserved_ports.remove(host_port);
|
||||
}
|
||||
self.reserved_storage
|
||||
.entry(vm.storage_dir.clone())
|
||||
.and_modify(|gb| *gb -= vm.disk_size_gb);
|
||||
self.reserved_storage.entry(vm.storage_dir.clone()).and_modify(|gb| *gb -= vm.disk_size_gb);
|
||||
let _ = self.save_to_disk();
|
||||
}
|
||||
}
|
||||
@ -333,12 +343,6 @@ pub struct VMNIC {
|
||||
ips: Vec<IPConfig>,
|
||||
}
|
||||
|
||||
impl VMNIC {
|
||||
fn new() -> VMNIC {
|
||||
todo!("implement this here to improve code elegance of resource reservation");
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct VM {
|
||||
pub uuid: String,
|
||||
@ -356,6 +360,35 @@ pub struct VM {
|
||||
storage_dir: String,
|
||||
}
|
||||
|
||||
impl Into<brain::NewVmResp> for VM {
|
||||
fn into(self) -> brain::NewVmResp {
|
||||
let mut nic_index: u32 = 0;
|
||||
let mut ips: Vec<brain::NewVmRespIp> = Vec::new();
|
||||
if self.fw_ports.len() > 0 {
|
||||
nic_index += 1;
|
||||
}
|
||||
// TODO: when brain supports multiple IPs per VM, fix this
|
||||
for nic in self.nics {
|
||||
for ip in nic.ips {
|
||||
ips.push(brain::NewVmRespIp {
|
||||
nic_index,
|
||||
address: ip.address,
|
||||
mask: ip.mask,
|
||||
gateway: ip.gateway,
|
||||
});
|
||||
}
|
||||
nic_index += 1;
|
||||
}
|
||||
brain::NewVmResp {
|
||||
uuid: self.uuid,
|
||||
exposed_ports: self.fw_ports.iter().map(|(p, _)| *p as u32).collect(),
|
||||
ips,
|
||||
ovmf_hash: crate::constants::OVMF_HASH.to_string(),
|
||||
error: "".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct NewVMRequest {
|
||||
uuid: String,
|
||||
@ -373,11 +406,23 @@ pub struct NewVMRequest {
|
||||
dtrfs_sha: String,
|
||||
}
|
||||
|
||||
impl NewVMRequest {
|
||||
pub fn from_file(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
let request: NewVMRequest = serde_yaml::from_str(&content)?;
|
||||
Ok(request)
|
||||
impl From<brain::NewVmReq> for NewVMRequest {
|
||||
fn from(req: brain::NewVmReq) -> Self {
|
||||
Self {
|
||||
uuid: req.uuid,
|
||||
hostname: req.hostname,
|
||||
admin_key: req.admin_pubkey,
|
||||
extra_ports: req.extra_ports.iter().map(|&port| port as u16).collect(),
|
||||
public_ipv4: req.public_ipv4,
|
||||
public_ipv6: req.public_ipv6,
|
||||
disk_size_gb: req.disk_size_gb as usize,
|
||||
vcpus: req.vcpus as usize,
|
||||
memory_mb: req.memory_mb as usize,
|
||||
kernel_url: req.kernel_url,
|
||||
kernel_sha: req.kernel_sha,
|
||||
dtrfs_url: req.dtrfs_url,
|
||||
dtrfs_sha: req.dtrfs_sha,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -394,17 +439,9 @@ pub struct UpdateVMReq {
|
||||
dtrfs_sha: String,
|
||||
}
|
||||
|
||||
impl UpdateVMReq {
|
||||
pub fn from_file(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
let request: UpdateVMReq = serde_yaml::from_str(&content)?;
|
||||
Ok(request)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum VMCreationErrors {
|
||||
VMAlreadyExists,
|
||||
VMAlreadyExists(VM),
|
||||
NATandIPv4Conflict,
|
||||
TooManyCores,
|
||||
NotEnoughPorts,
|
||||
@ -426,7 +463,11 @@ impl VM {
|
||||
res: &mut Resources,
|
||||
) -> Result<Self, VMCreationErrors> {
|
||||
if res.existing_vms.contains(&req.uuid) {
|
||||
return Err(VMCreationErrors::VMAlreadyExists);
|
||||
let content = std::fs::read_to_string(VM_CONFIG_DIR.to_string() + &req.uuid + ".yaml")
|
||||
.map_err(|e| VMCreationErrors::ServerDiskError(e.to_string()))?;
|
||||
let vm: crate::state::VM = serde_yaml::from_str(&content)
|
||||
.map_err(|e| VMCreationErrors::ServerDiskError(e.to_string()))?;
|
||||
return Err(VMCreationErrors::VMAlreadyExists(vm));
|
||||
}
|
||||
if req.extra_ports.len() > 0 && req.public_ipv4 {
|
||||
return Err(VMCreationErrors::NATandIPv4Conflict);
|
||||
@ -444,12 +485,20 @@ impl VM {
|
||||
return Err(VMCreationErrors::DiskTooSmall);
|
||||
}
|
||||
|
||||
if let Err(kernel_err) = res.download_boot_file(req.kernel_url, req.kernel_sha.clone()) {
|
||||
if let Err(ovmf_err) = res.find_or_download_file(
|
||||
crate::constants::OVMF_URL.to_string(),
|
||||
crate::constants::OVMF_HASH.to_string(),
|
||||
) {
|
||||
return Err(VMCreationErrors::BootFileError(format!(
|
||||
"Could not get OVMF: {ovmf_err:?}"
|
||||
)));
|
||||
};
|
||||
if let Err(kernel_err) = res.find_or_download_file(req.kernel_url, req.kernel_sha.clone()) {
|
||||
return Err(VMCreationErrors::BootFileError(format!(
|
||||
"Could not get kernel: {kernel_err:?}"
|
||||
)));
|
||||
};
|
||||
if let Err(dtrfs_err) = res.download_boot_file(req.dtrfs_url, req.dtrfs_sha.clone()) {
|
||||
if let Err(dtrfs_err) = res.find_or_download_file(req.dtrfs_url, req.dtrfs_sha.clone()) {
|
||||
return Err(VMCreationErrors::BootFileError(format!(
|
||||
"Could not get dtrfs: {dtrfs_err:?}"
|
||||
)));
|
||||
@ -457,13 +506,13 @@ impl VM {
|
||||
|
||||
let mut vm_nics = Vec::new();
|
||||
if req.public_ipv4 {
|
||||
match res.available_ipv4(config) {
|
||||
match res.available_ipv4(&config.network_interfaces) {
|
||||
Some(vmnic) => vm_nics.push(vmnic),
|
||||
None => return Err(VMCreationErrors::IPv4NotAvailable),
|
||||
}
|
||||
}
|
||||
if req.public_ipv6 {
|
||||
match res.available_ipv6(config) {
|
||||
match res.available_ipv6(&config.network_interfaces) {
|
||||
Some(mut vmnic) => {
|
||||
if let Some(mut existing_vmnic) = vm_nics.pop() {
|
||||
if vmnic.if_config.device_name() == existing_vmnic.if_config.device_name() {
|
||||
@ -478,7 +527,7 @@ impl VM {
|
||||
}
|
||||
}
|
||||
None => {
|
||||
return Err(VMCreationErrors::IPv4NotAvailable);
|
||||
return Err(VMCreationErrors::IPv6NotAvailable);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -532,18 +581,12 @@ impl VM {
|
||||
return Err(VMCreationErrors::TooManyCores);
|
||||
}
|
||||
if config.max_vcpu_reservation
|
||||
< res
|
||||
.reserved_vcpus
|
||||
.saturating_sub(self.vcpus)
|
||||
.saturating_add(req.vcpus)
|
||||
< res.reserved_vcpus.saturating_sub(self.vcpus).saturating_add(req.vcpus)
|
||||
{
|
||||
return Err(VMCreationErrors::NotEnoughCPU);
|
||||
}
|
||||
if config.max_mem_reservation_mb
|
||||
< res
|
||||
.reserved_memory
|
||||
.saturating_sub(self.memory_mb)
|
||||
.saturating_add(req.memory_mb)
|
||||
< res.reserved_memory.saturating_sub(self.memory_mb).saturating_add(req.memory_mb)
|
||||
{
|
||||
return Err(VMCreationErrors::NotEnoughMemory);
|
||||
}
|
||||
@ -558,12 +601,14 @@ impl VM {
|
||||
));
|
||||
}
|
||||
|
||||
if let Err(kern_err) = res.download_boot_file(req.kernel_url, req.kernel_sha.clone()) {
|
||||
if let Err(kern_err) = res.find_or_download_file(req.kernel_url, req.kernel_sha.clone())
|
||||
{
|
||||
return Err(VMCreationErrors::BootFileError(format!(
|
||||
"Could not get kernel: {kern_err:?}"
|
||||
)));
|
||||
};
|
||||
if let Err(dtrfs_err) = res.download_boot_file(req.dtrfs_url, req.dtrfs_sha.clone()) {
|
||||
if let Err(dtrfs_err) = res.find_or_download_file(req.dtrfs_url, req.dtrfs_sha.clone())
|
||||
{
|
||||
return Err(VMCreationErrors::BootFileError(format!(
|
||||
"Could not get dtrfs: {dtrfs_err:?}"
|
||||
)));
|
||||
@ -578,12 +623,10 @@ impl VM {
|
||||
res.reserved_memory = res.reserved_memory.saturating_sub(self.memory_mb);
|
||||
res.reserved_vcpus = res.reserved_vcpus.saturating_add(req.vcpus);
|
||||
res.reserved_vcpus = res.reserved_vcpus.saturating_sub(self.vcpus);
|
||||
res.reserved_storage
|
||||
.entry(self.storage_dir.clone())
|
||||
.and_modify(|gb| {
|
||||
*gb = gb.saturating_add(req.disk_size_gb);
|
||||
*gb = gb.saturating_sub(self.disk_size_gb);
|
||||
});
|
||||
res.reserved_storage.entry(self.storage_dir.clone()).and_modify(|gb| {
|
||||
*gb = gb.saturating_add(req.disk_size_gb);
|
||||
*gb = gb.saturating_sub(self.disk_size_gb);
|
||||
});
|
||||
let _ = res.save_to_disk();
|
||||
|
||||
self.memory_mb = req.memory_mb;
|
||||
@ -645,28 +688,25 @@ impl VM {
|
||||
dir + &self.uuid + ".qcow2"
|
||||
}
|
||||
|
||||
// If you change this here, you also have to change it in the CLI.
|
||||
// The kernel params must match on both daemon and CLI to build the measurement.
|
||||
pub fn kernel_params(&self) -> String {
|
||||
let mut ip_string = String::new();
|
||||
let mut i = 0;
|
||||
if self.fw_ports.len() > 0 {
|
||||
ip_string += &format!(
|
||||
"detee_net_eth{}={}_{}_{} ",
|
||||
i, "10.0.2.15", "24", "10.0.2.2"
|
||||
);
|
||||
ip_string += &format!("detee_net_eth{}={}_{}_{} ", i, "10.0.2.15", "24", "10.0.2.2");
|
||||
i += 1;
|
||||
}
|
||||
for nic in self.nics.iter() {
|
||||
for ip in nic.ips.iter() {
|
||||
ip_string += &format!(
|
||||
"detee_net_eth{}={}_{}_{} ",
|
||||
i, ip.address, ip.mask, ip.gateway
|
||||
);
|
||||
ip_string +=
|
||||
&format!("detee_net_eth{}={}_{}_{} ", i, ip.address, ip.mask, ip.gateway);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
let admin_key = format!("detee_admin={}", self.admin_key);
|
||||
let admin_key = format!("detee_admin={} ", self.admin_key);
|
||||
let hostname = format!("detee_name={}", self.hostname);
|
||||
format!("{} {} {}", ip_string, admin_key, hostname)
|
||||
format!("{}{}{}", ip_string, admin_key, hostname)
|
||||
}
|
||||
|
||||
fn write_config(&self) -> Result<()> {
|
||||
@ -686,11 +726,7 @@ impl VM {
|
||||
let mut i = 0;
|
||||
for nic in self.nics.iter() {
|
||||
let mut interface = String::new();
|
||||
interface += &format!(
|
||||
r#"export NETWORK_INTERFACE_{}="{}"#,
|
||||
i,
|
||||
nic.if_config.if_type()
|
||||
);
|
||||
interface += &format!(r#"export NETWORK_INTERFACE_{}="{}"#, i, nic.if_config.if_type());
|
||||
// device is currently ignored in case of NAT cause we assume QEMU userspace NAT
|
||||
if let Some(vtap_name) = nic.if_config.vtap_name() {
|
||||
interface += &format!("_{}_{}", nic.if_config.device_name(), vtap_name);
|
||||
@ -711,15 +747,9 @@ impl VM {
|
||||
vars += "export NETWORK_INTERFACE_0000=NAT\n";
|
||||
}
|
||||
|
||||
vars += &format!(
|
||||
r#"export KERNEL="{}""#,
|
||||
VM_BOOT_DIR.to_string() + &self.kernel_sha
|
||||
);
|
||||
vars += &format!(r#"export KERNEL="{}""#, VM_BOOT_DIR.to_string() + &self.kernel_sha);
|
||||
vars += "\n";
|
||||
vars += &format!(
|
||||
r#"export INITRD="{}""#,
|
||||
VM_BOOT_DIR.to_string() + &self.dtrfs_sha
|
||||
);
|
||||
vars += &format!(r#"export INITRD="{}""#, VM_BOOT_DIR.to_string() + &self.dtrfs_sha);
|
||||
vars += "\n";
|
||||
vars += &format!(r#"export PARAMS="{}""#, self.kernel_params());
|
||||
vars += "\n";
|
||||
@ -747,11 +777,7 @@ impl VM {
|
||||
fn delete_vtap_interfaces(&self) -> Result<()> {
|
||||
for nic in self.nics.iter() {
|
||||
if let Some(name) = nic.if_config.vtap_name() {
|
||||
let result = Command::new("ip")
|
||||
.arg("link")
|
||||
.arg("del")
|
||||
.arg(&name)
|
||||
.output()?;
|
||||
let result = Command::new("ip").arg("link").arg("del").arg(&name).output()?;
|
||||
if !result.status.success() {
|
||||
return Err(anyhow!(
|
||||
"Could not delete vtap interface {:?}:\n{:?}\n{:?}",
|
||||
@ -794,10 +820,7 @@ impl VM {
|
||||
|
||||
fn create_disk(&self) -> Result<()> {
|
||||
if std::path::Path::new(&self.disk_path()).exists() {
|
||||
return Err(anyhow!(
|
||||
"Could not create {}. The file already exists.",
|
||||
self.disk_path()
|
||||
));
|
||||
return Err(anyhow!("Could not create {}. The file already exists.", self.disk_path()));
|
||||
}
|
||||
|
||||
let result = Command::new("qemu-img")
|
||||
@ -844,10 +867,8 @@ impl VM {
|
||||
}
|
||||
|
||||
fn systemctl_start_and_enable(vm_uuid: &str) -> Result<()> {
|
||||
let result = Command::new("systemctl")
|
||||
.arg("start")
|
||||
.arg(vm_uuid.to_string() + ".service")
|
||||
.output()?;
|
||||
let result =
|
||||
Command::new("systemctl").arg("start").arg(vm_uuid.to_string() + ".service").output()?;
|
||||
if !result.status.success() {
|
||||
return Err(anyhow!(
|
||||
"Could not reload systemctl daemon:\n{:?}\n{:?}",
|
||||
@ -857,10 +878,8 @@ fn systemctl_start_and_enable(vm_uuid: &str) -> Result<()> {
|
||||
.unwrap_or("Could not grab stderr from creation script.".to_string()),
|
||||
));
|
||||
}
|
||||
let result = Command::new("systemctl")
|
||||
.arg("enable")
|
||||
.arg(vm_uuid.to_string() + ".service")
|
||||
.output()?;
|
||||
let result =
|
||||
Command::new("systemctl").arg("enable").arg(vm_uuid.to_string() + ".service").output()?;
|
||||
if !result.status.success() {
|
||||
return Err(anyhow!(
|
||||
"Could not reload systemctl daemon:\n{:?}\n{:?}",
|
||||
@ -874,10 +893,8 @@ fn systemctl_start_and_enable(vm_uuid: &str) -> Result<()> {
|
||||
}
|
||||
|
||||
fn systemctl_stop_and_disable(vm_uuid: &str) -> Result<()> {
|
||||
let result = Command::new("systemctl")
|
||||
.arg("stop")
|
||||
.arg(vm_uuid.to_string() + ".service")
|
||||
.output()?;
|
||||
let result =
|
||||
Command::new("systemctl").arg("stop").arg(vm_uuid.to_string() + ".service").output()?;
|
||||
if !result.status.success() {
|
||||
return Err(anyhow!(
|
||||
"Could not reload systemctl daemon:\n{:?}\n{:?}",
|
||||
@ -887,10 +904,8 @@ fn systemctl_stop_and_disable(vm_uuid: &str) -> Result<()> {
|
||||
.unwrap_or("Could not grab stderr from creation script.".to_string()),
|
||||
));
|
||||
}
|
||||
let result = Command::new("systemctl")
|
||||
.arg("disable")
|
||||
.arg(vm_uuid.to_string() + ".service")
|
||||
.output()?;
|
||||
let result =
|
||||
Command::new("systemctl").arg("disable").arg(vm_uuid.to_string() + ".service").output()?;
|
||||
if !result.status.success() {
|
||||
return Err(anyhow!(
|
||||
"Could not reload systemctl daemon:\n{:?}\n{:?}",
|
||||
@ -919,9 +934,7 @@ fn systemctl_reload() -> Result<()> {
|
||||
|
||||
fn download_and_check_sha(url: &str, sha: &str) -> Result<()> {
|
||||
use reqwest::blocking::get;
|
||||
use std::fs::File;
|
||||
use std::io::copy;
|
||||
use std::path::Path;
|
||||
use std::{fs::File, io::copy, path::Path};
|
||||
let save_path = VM_BOOT_DIR.to_string() + sha;
|
||||
let response = get(url)?;
|
||||
if !response.status().is_success() {
|
||||
@ -958,41 +971,3 @@ fn compute_sha256<P: AsRef<Path>>(path: P) -> Result<String> {
|
||||
let result = hasher.finalize();
|
||||
Ok(format!("{:x}", result))
|
||||
}
|
||||
|
||||
fn calc_ipv4_netmask(ip: Ipv4Addr, gateway: Ipv4Addr) -> String {
|
||||
// Convert the IPs to u32 for easier bit manipulation
|
||||
let ip_u32 = u32::from(ip);
|
||||
let gateway_u32 = u32::from(gateway);
|
||||
|
||||
// Find the smallest common prefix
|
||||
let mut prefix_len = 0;
|
||||
for i in 1..=32 {
|
||||
if (ip_u32 >> (32 - i)) == (gateway_u32 >> (32 - i)) {
|
||||
prefix_len = i;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the mask as a string
|
||||
prefix_len.to_string()
|
||||
}
|
||||
|
||||
fn calc_ipv6_netmask(ip: Ipv6Addr, gateway: Ipv6Addr) -> String {
|
||||
// Convert the IPs to u128 for easier bit manipulation
|
||||
let ip_u128 = u128::from(ip);
|
||||
let gateway_u128 = u128::from(gateway);
|
||||
|
||||
// Find the smallest common prefix
|
||||
let mut prefix_len = 0;
|
||||
for i in 1..=128 {
|
||||
if (ip_u128 >> (128 - i)) == (gateway_u128 >> (128 - i)) {
|
||||
prefix_len = i;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the mask as a string
|
||||
prefix_len.to_string()
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
#![allow(dead_code)]
|
||||
// this is defined in the engine but we will mock it here for now
|
||||
|
||||
pub struct FinalizedTContract {
|
||||
pub owner: String,
|
||||
pub user: String,
|
||||
pub alloc: ResourceAllocation,
|
||||
pub kernel_uri: String,
|
||||
pub kernel_sha: String,
|
||||
pub dtrfs_uri: String,
|
||||
pub dtrfs_sha: String,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ResourceAllocation {
|
||||
pub vcpus: usize,
|
||||
pub memory: usize,
|
||||
pub storage: usize,
|
||||
pub extra_ports: Vec<u16>,
|
||||
// storage tier: not part of MVP
|
||||
// pub storage_tier: usize,
|
||||
pub public_ipv4: Option<String>,
|
||||
pub public_ipv6: Option<String>,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user