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" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" | 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]] | [[package]] | ||||||
| name = "anyhow" | name = "anyhow" | ||||||
| version = "1.0.94" | version = "1.0.94" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" | 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]] | [[package]] | ||||||
| name = "atomic-waker" | name = "atomic-waker" | ||||||
| version = "1.1.2" | version = "1.1.2" | ||||||
| @ -35,6 +126,53 @@ version = "1.4.0" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" | 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]] | [[package]] | ||||||
| name = "backtrace" | name = "backtrace" | ||||||
| version = "0.3.74" | version = "0.3.74" | ||||||
| @ -56,6 +194,12 @@ version = "0.22.1" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "base64ct" | ||||||
|  | version = "1.6.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "bitflags" | name = "bitflags" | ||||||
| version = "2.6.0" | version = "2.6.0" | ||||||
| @ -91,9 +235,9 @@ checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" | |||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "cc" | name = "cc" | ||||||
| version = "1.2.3" | version = "1.2.6" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" | checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "shlex", |  "shlex", | ||||||
| ] | ] | ||||||
| @ -105,13 +249,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||||
| checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "cidr" | name = "colorchoice" | ||||||
| version = "0.3.0" | version = "1.0.3" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "bfc95a0c21d5409adc146dbbb152b5c65aaea32bc2d2f57cf12f850bffdd7ab8" | checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" | ||||||
| dependencies = [ | 
 | ||||||
|  "serde", | [[package]] | ||||||
| ] | name = "const-oid" | ||||||
|  | version = "0.9.6" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "core-foundation" | name = "core-foundation" | ||||||
| @ -148,17 +295,65 @@ dependencies = [ | |||||||
|  "typenum", |  "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]] | [[package]] | ||||||
| name = "detee-snp-daemon" | name = "detee-snp-daemon" | ||||||
| version = "0.1.0" | version = "0.1.0" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "anyhow", |  "anyhow", | ||||||
|  "cidr", |  "ed25519-dalek", | ||||||
|  |  "env_logger", | ||||||
|  |  "lazy_static", | ||||||
|  |  "log", | ||||||
|  |  "prost", | ||||||
|  |  "prost-types", | ||||||
|  "rand", |  "rand", | ||||||
|  |  "rand_core", | ||||||
|  "reqwest", |  "reqwest", | ||||||
|  "serde", |  "serde", | ||||||
|  "serde_yaml", |  "serde_yaml", | ||||||
|  "sha2", |  "sha2", | ||||||
|  |  "tokio", | ||||||
|  |  "tokio-stream", | ||||||
|  |  "tonic", | ||||||
|  |  "tonic-build", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| @ -182,6 +377,37 @@ dependencies = [ | |||||||
|  "syn", |  "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]] | [[package]] | ||||||
| name = "encoding_rs" | name = "encoding_rs" | ||||||
| version = "0.8.35" | version = "0.8.35" | ||||||
| @ -191,6 +417,29 @@ dependencies = [ | |||||||
|  "cfg-if", |  "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]] | [[package]] | ||||||
| name = "equivalent" | name = "equivalent" | ||||||
| version = "1.0.1" | version = "1.0.1" | ||||||
| @ -213,6 +462,18 @@ version = "2.3.0" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" | 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]] | [[package]] | ||||||
| name = "fnv" | name = "fnv" | ||||||
| version = "1.0.7" | version = "1.0.7" | ||||||
| @ -332,19 +593,31 @@ dependencies = [ | |||||||
|  "futures-core", |  "futures-core", | ||||||
|  "futures-sink", |  "futures-sink", | ||||||
|  "http", |  "http", | ||||||
|  "indexmap", |  "indexmap 2.7.0", | ||||||
|  "slab", |  "slab", | ||||||
|  "tokio", |  "tokio", | ||||||
|  "tokio-util", |  "tokio-util", | ||||||
|  "tracing", |  "tracing", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "hashbrown" | ||||||
|  | version = "0.12.3" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "hashbrown" | name = "hashbrown" | ||||||
| version = "0.15.2" | version = "0.15.2" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "heck" | ||||||
|  | version = "0.5.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "http" | name = "http" | ||||||
| version = "1.2.0" | version = "1.2.0" | ||||||
| @ -385,6 +658,18 @@ version = "1.9.5" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" | 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]] | [[package]] | ||||||
| name = "hyper" | name = "hyper" | ||||||
| version = "1.5.1" | version = "1.5.1" | ||||||
| @ -398,6 +683,7 @@ dependencies = [ | |||||||
|  "http", |  "http", | ||||||
|  "http-body", |  "http-body", | ||||||
|  "httparse", |  "httparse", | ||||||
|  |  "httpdate", | ||||||
|  "itoa", |  "itoa", | ||||||
|  "pin-project-lite", |  "pin-project-lite", | ||||||
|  "smallvec", |  "smallvec", | ||||||
| @ -407,9 +693,9 @@ dependencies = [ | |||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "hyper-rustls" | name = "hyper-rustls" | ||||||
| version = "0.27.3" | version = "0.27.5" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" | checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "futures-util", |  "futures-util", | ||||||
|  "http", |  "http", | ||||||
| @ -422,6 +708,19 @@ dependencies = [ | |||||||
|  "tower-service", |  "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]] | [[package]] | ||||||
| name = "hyper-tls" | name = "hyper-tls" | ||||||
| version = "0.6.0" | version = "0.6.0" | ||||||
| @ -596,6 +895,16 @@ dependencies = [ | |||||||
|  "icu_properties", |  "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]] | [[package]] | ||||||
| name = "indexmap" | name = "indexmap" | ||||||
| version = "2.7.0" | version = "2.7.0" | ||||||
| @ -603,7 +912,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||||
| checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" | checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "equivalent", |  "equivalent", | ||||||
|  "hashbrown", |  "hashbrown 0.15.2", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| @ -612,6 +921,21 @@ version = "2.10.1" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" | 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]] | [[package]] | ||||||
| name = "itoa" | name = "itoa" | ||||||
| version = "1.0.14" | version = "1.0.14" | ||||||
| @ -628,6 +952,12 @@ dependencies = [ | |||||||
|  "wasm-bindgen", |  "wasm-bindgen", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "lazy_static" | ||||||
|  | version = "1.5.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "libc" | name = "libc" | ||||||
| version = "0.2.167" | version = "0.2.167" | ||||||
| @ -652,6 +982,12 @@ version = "0.4.22" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "matchit" | ||||||
|  | version = "0.7.3" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "memchr" | name = "memchr" | ||||||
| version = "2.7.4" | version = "2.7.4" | ||||||
| @ -684,6 +1020,12 @@ dependencies = [ | |||||||
|  "windows-sys 0.52.0", |  "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]] | [[package]] | ||||||
| name = "native-tls" | name = "native-tls" | ||||||
| version = "0.2.12" | version = "0.2.12" | ||||||
| @ -760,12 +1102,51 @@ dependencies = [ | |||||||
|  "vcpkg", |  "vcpkg", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "pem-rfc7468" | ||||||
|  | version = "0.7.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" | ||||||
|  | dependencies = [ | ||||||
|  |  "base64ct", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "percent-encoding" | name = "percent-encoding" | ||||||
| version = "2.3.1" | version = "2.3.1" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" | 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]] | [[package]] | ||||||
| name = "pin-project-lite" | name = "pin-project-lite" | ||||||
| version = "0.2.15" | version = "0.2.15" | ||||||
| @ -778,6 +1159,16 @@ version = "0.1.0" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" | 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]] | [[package]] | ||||||
| name = "pkg-config" | name = "pkg-config" | ||||||
| version = "0.3.31" | version = "0.3.31" | ||||||
| @ -793,6 +1184,16 @@ dependencies = [ | |||||||
|  "zerocopy", |  "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]] | [[package]] | ||||||
| name = "proc-macro2" | name = "proc-macro2" | ||||||
| version = "1.0.92" | version = "1.0.92" | ||||||
| @ -802,6 +1203,58 @@ dependencies = [ | |||||||
|  "unicode-ident", |  "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]] | [[package]] | ||||||
| name = "quote" | name = "quote" | ||||||
| version = "1.0.37" | version = "1.0.37" | ||||||
| @ -842,10 +1295,39 @@ dependencies = [ | |||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "reqwest" | name = "regex" | ||||||
| version = "0.12.9" | version = "1.11.1" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | 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 = [ | dependencies = [ | ||||||
|  "base64", |  "base64", | ||||||
|  "bytes", |  "bytes", | ||||||
| @ -877,6 +1359,7 @@ dependencies = [ | |||||||
|  "system-configuration", |  "system-configuration", | ||||||
|  "tokio", |  "tokio", | ||||||
|  "tokio-native-tls", |  "tokio-native-tls", | ||||||
|  |  "tower 0.5.2", | ||||||
|  "tower-service", |  "tower-service", | ||||||
|  "url", |  "url", | ||||||
|  "wasm-bindgen", |  "wasm-bindgen", | ||||||
| @ -906,6 +1389,15 @@ version = "0.1.24" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" | 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]] | [[package]] | ||||||
| name = "rustix" | name = "rustix" | ||||||
| version = "0.38.42" | version = "0.38.42" | ||||||
| @ -921,9 +1413,9 @@ dependencies = [ | |||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "rustls" | name = "rustls" | ||||||
| version = "0.23.19" | version = "0.23.20" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" | checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "once_cell", |  "once_cell", | ||||||
|  "rustls-pki-types", |  "rustls-pki-types", | ||||||
| @ -943,9 +1435,9 @@ dependencies = [ | |||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "rustls-pki-types" | name = "rustls-pki-types" | ||||||
| version = "1.10.0" | version = "1.10.1" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" | checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "rustls-webpki" | name = "rustls-webpki" | ||||||
| @ -958,6 +1450,12 @@ dependencies = [ | |||||||
|  "untrusted", |  "untrusted", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "rustversion" | ||||||
|  | version = "1.0.18" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "ryu" | name = "ryu" | ||||||
| version = "1.0.18" | version = "1.0.18" | ||||||
| @ -988,14 +1486,20 @@ dependencies = [ | |||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "security-framework-sys" | name = "security-framework-sys" | ||||||
| version = "2.12.1" | version = "2.13.0" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" | checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "core-foundation-sys", |  "core-foundation-sys", | ||||||
|  "libc", |  "libc", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "semver" | ||||||
|  | version = "1.0.24" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "serde" | name = "serde" | ||||||
| version = "1.0.215" | version = "1.0.215" | ||||||
| @ -1018,9 +1522,9 @@ dependencies = [ | |||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "serde_json" | name = "serde_json" | ||||||
| version = "1.0.133" | version = "1.0.134" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" | checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "itoa", |  "itoa", | ||||||
|  "memchr", |  "memchr", | ||||||
| @ -1046,7 +1550,7 @@ version = "0.9.34+deprecated" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" | checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "indexmap", |  "indexmap 2.7.0", | ||||||
|  "itoa", |  "itoa", | ||||||
|  "ryu", |  "ryu", | ||||||
|  "serde", |  "serde", | ||||||
| @ -1070,6 +1574,15 @@ version = "1.3.0" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" | 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]] | [[package]] | ||||||
| name = "slab" | name = "slab" | ||||||
| version = "0.4.9" | version = "0.4.9" | ||||||
| @ -1101,6 +1614,16 @@ version = "0.9.8" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" | 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]] | [[package]] | ||||||
| name = "stable_deref_trait" | name = "stable_deref_trait" | ||||||
| version = "1.2.0" | version = "1.2.0" | ||||||
| @ -1200,9 +1723,21 @@ dependencies = [ | |||||||
|  "mio", |  "mio", | ||||||
|  "pin-project-lite", |  "pin-project-lite", | ||||||
|  "socket2", |  "socket2", | ||||||
|  |  "tokio-macros", | ||||||
|  "windows-sys 0.52.0", |  "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]] | [[package]] | ||||||
| name = "tokio-native-tls" | name = "tokio-native-tls" | ||||||
| version = "0.3.1" | version = "0.3.1" | ||||||
| @ -1223,6 +1758,17 @@ dependencies = [ | |||||||
|  "tokio", |  "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]] | [[package]] | ||||||
| name = "tokio-util" | name = "tokio-util" | ||||||
| version = "0.7.13" | version = "0.7.13" | ||||||
| @ -1236,6 +1782,91 @@ dependencies = [ | |||||||
|  "tokio", |  "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]] | [[package]] | ||||||
| name = "tower-service" | name = "tower-service" | ||||||
| version = "0.3.3" | version = "0.3.3" | ||||||
| @ -1249,9 +1880,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||||
| checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "pin-project-lite", |  "pin-project-lite", | ||||||
|  |  "tracing-attributes", | ||||||
|  "tracing-core", |  "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]] | [[package]] | ||||||
| name = "tracing-core" | name = "tracing-core" | ||||||
| version = "0.1.33" | version = "0.1.33" | ||||||
| @ -1314,6 +1957,12 @@ version = "1.0.4" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "utf8parse" | ||||||
|  | version = "0.2.2" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "vcpkg" | name = "vcpkg" | ||||||
| version = "0.2.15" | version = "0.2.15" | ||||||
|  | |||||||
							
								
								
									
										16
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										16
									
								
								Cargo.toml
									
									
									
									
									
								
							| @ -4,10 +4,22 @@ version = "0.1.0" | |||||||
| edition = "2021" | edition = "2021" | ||||||
| 
 | 
 | ||||||
| [dependencies] | [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" | anyhow = "1.0.94" | ||||||
| cidr = { version = "0.3.0", features = ["serde"] } | env_logger = "0.11.6" | ||||||
| rand = "0.8.5" | log = "0.4.22" | ||||||
| reqwest = { version = "0.12.9", features = ["blocking"] } | reqwest = { version = "0.12.9", features = ["blocking"] } | ||||||
| serde = { version = "1.0.215", features = ["derive"] } | serde = { version = "1.0.215", features = ["derive"] } | ||||||
| serde_yaml = "0.9.34" | serde_yaml = "0.9.34" | ||||||
| sha2 = "0.10.8" | 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_cores_per_vm: 4 | ||||||
| max_vcpu_reservation: 8 | max_vcpu_reservation: 8 | ||||||
| max_mem_reservation_mb: 25000 | max_mem_reservation_mb: 25000 | ||||||
| network_interfaces: | network_interfaces: | ||||||
|   - driver: "MACVTAP" |   - driver: "MACVTAP" | ||||||
|     device: "eno8303" |     device: "eno8303" | ||||||
|     ipv4: |     ipv4_ranges: | ||||||
|       - subnet: "173.234.136.152/29" |       - first_ip: "173.234.136.154" | ||||||
|  |         last_ip: "173.234.136.155" | ||||||
|  |         netmask: "27" | ||||||
|         gateway: "173.234.136.158" |         gateway: "173.234.136.158" | ||||||
|         reserved_addrs: |       - first_ip: "173.234.137.17" | ||||||
|           - "173.234.136.153" |         last_ip: "173.234.137.17" | ||||||
|           - "173.234.136.156" |         netmask: "27" | ||||||
|           - "173.234.136.157" |  | ||||||
|           - "173.234.136.158" |  | ||||||
|       - subnet: "173.234.137.16/31" |  | ||||||
|         gateway: "173.234.137.30" |         gateway: "173.234.137.30" | ||||||
|         reserved_addrs: |     ipv6_ranges: | ||||||
|           - "173.234.137.16" |       - first_ip: "2a0d:3003:b666:a00c:0002:0000:0000:0011" | ||||||
|     ipv6: |         last_ip: "2a0d:3003:b666:a00c:0002:0000:0000:fffc" | ||||||
|       - subnet: "2a0d:3003:b666:a00c:2::/112" |         netmask: "64" | ||||||
|         gateway: "2a0d:3003:b666:a00c::1" |         gateway: "2a0d:3003:b666:a00c::1" | ||||||
|         reserved_addrs: [] |  | ||||||
| volumes: | volumes: | ||||||
|   - path: "/opt/detee_vms/" |   - path: "/opt/detee_vms/" | ||||||
|     max_reservation_gb: 200 |     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 | #!/bin/bash | ||||||
|  | OVMF_PATH="/var/lib/detee/boot/0346619257269b9a61ee003e197d521b8e2283483070d163a34940d6a1d40d76"; | ||||||
| 
 | 
 | ||||||
| [[ -z "$VM_UUID" ]] && { | [[ -z "$VM_UUID" ]] && { | ||||||
|   echo "Environment variable VM_UUID is not set." |   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 \ |     -machine q35,confidential-guest-support=sev0,memory-backend=ram1 \ | ||||||
|     -smp $VCPUS,maxcpus=$VCPUS \ |     -smp $VCPUS,maxcpus=$VCPUS \ | ||||||
|     -m $MEMORY,slots=5,maxmem=$MAX_MEMORY \ |     -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 \ |     -drive file=${DISK},if=none,id=disk0,format=qcow2 \ | ||||||
|     -device virtio-blk-pci,drive=disk0 \ |     -device virtio-blk-pci,drive=disk0 \ | ||||||
|     -object memory-backend-memfd,id=ram1,size=$MEMORY,share=true,prealloc=false \ |     -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)] | #![allow(dead_code)] | ||||||
| use cidr::{Ipv4Cidr, Ipv6Cidr}; | use anyhow::Result; | ||||||
| use serde::Deserialize; | use serde::Deserialize; | ||||||
| use std::collections::HashSet; | use std::{ | ||||||
| use std::net::{Ipv4Addr, Ipv6Addr}; |     net::{Ipv4Addr, Ipv6Addr}, | ||||||
| use std::ops::Range; |     ops::Range, | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| #[derive(Deserialize, Debug, Clone)] | #[derive(Deserialize, Debug, Clone)] | ||||||
| pub struct Volume { | pub struct Volume { | ||||||
| @ -13,24 +14,26 @@ pub struct Volume { | |||||||
| 
 | 
 | ||||||
| #[derive(Deserialize, Debug)] | #[derive(Deserialize, Debug)] | ||||||
| pub struct IPv4Range { | pub struct IPv4Range { | ||||||
|     pub subnet: Ipv4Cidr, |     pub first_ip: Ipv4Addr, | ||||||
|  |     pub last_ip: Ipv4Addr, | ||||||
|  |     pub netmask: String, | ||||||
|     pub gateway: Ipv4Addr, |     pub gateway: Ipv4Addr, | ||||||
|     pub reserved_addrs: HashSet<Ipv4Addr>, |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Deserialize, Debug)] | #[derive(Deserialize, Debug)] | ||||||
| pub struct IPv6Range { | pub struct IPv6Range { | ||||||
|     pub subnet: Ipv6Cidr, |     pub first_ip: Ipv6Addr, | ||||||
|  |     pub last_ip: Ipv6Addr, | ||||||
|  |     pub netmask: String, | ||||||
|     pub gateway: Ipv6Addr, |     pub gateway: Ipv6Addr, | ||||||
|     pub reserved_addrs: HashSet<Ipv6Addr>, |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Deserialize, Debug)] | #[derive(Deserialize, Debug)] | ||||||
| pub struct Interface { | pub struct Interface { | ||||||
|     pub driver: InterfaceType, |     pub driver: InterfaceType, | ||||||
|     pub device: String, |     pub device: String, | ||||||
|     pub ipv4: Vec<IPv4Range>, |     pub ipv4_ranges: Vec<IPv4Range>, | ||||||
|     pub ipv6: Vec<IPv6Range>, |     pub ipv6_ranges: Vec<IPv6Range>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Deserialize, Debug)] | #[derive(Deserialize, Debug)] | ||||||
| @ -42,6 +45,7 @@ pub enum InterfaceType { | |||||||
| 
 | 
 | ||||||
| #[derive(Deserialize, Debug)] | #[derive(Deserialize, Debug)] | ||||||
| pub struct Config { | pub struct Config { | ||||||
|  |     pub brain_url: String, | ||||||
|     pub max_cores_per_vm: usize, |     pub max_cores_per_vm: usize, | ||||||
|     pub max_vcpu_reservation: usize, |     pub max_vcpu_reservation: usize, | ||||||
|     pub max_mem_reservation_mb: usize, |     pub max_mem_reservation_mb: usize, | ||||||
| @ -60,10 +64,7 @@ mod range_format { | |||||||
|     where |     where | ||||||
|         S: Serializer, |         S: Serializer, | ||||||
|     { |     { | ||||||
|         let range_repr = RangeRepr { |         let range_repr = RangeRepr { start: range.start, end: range.end }; | ||||||
|             start: range.start, |  | ||||||
|             end: range.end, |  | ||||||
|         }; |  | ||||||
|         range_repr.serialize(serializer) |         range_repr.serialize(serializer) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -83,10 +84,93 @@ mod range_format { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Config { | 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 content = std::fs::read_to_string(path)?; | ||||||
|         let config: Config = serde_yaml::from_str(&content)?; |         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) |         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 | ||||||
|  | } | ||||||
|  | |||||||
| @ -4,7 +4,11 @@ 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 VM_BOOT_DIR: &str = "/var/lib/detee/boot/"; | ||||||
| pub(crate) const USED_RESOURCES: &str = "/etc/detee/daemon/used_resources.yaml"; | 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 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 DAEMON_CONFIG_PATH: &str = "/etc/detee/daemon/config.yaml"; | ||||||
| pub(crate) const START_VM_SCRIPT: &str = "/usr/local/bin/detee/start_qemu_vm.sh"; | pub(crate) const START_VM_SCRIPT: &str = "/usr/local/bin/detee/start_qemu_vm.sh"; | ||||||
| // TODO: research if other CPU types provide better performance
 | // TODO: research if other CPU types provide better performance
 | ||||||
| pub(crate) const QEMU_VM_CPU_TYPE: &str = "EPYC-v4"; | 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(()) | ||||||
|  | } | ||||||
							
								
								
									
										264
									
								
								src/main.rs
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										264
									
								
								src/main.rs
									
									
									
									
									
								
							| @ -1,62 +1,234 @@ | |||||||
|  | #[allow(dead_code)] | ||||||
| mod config; | mod config; | ||||||
| mod constants; | mod constants; | ||||||
|  | mod grpc; | ||||||
| mod state; | mod state; | ||||||
| mod tcontract; |  | ||||||
| 
 | 
 | ||||||
| use crate::config::Config; | use crate::{config::Config, grpc::brain}; | ||||||
| use crate::state::NewVMRequest; | use anyhow::Result; | ||||||
| use crate::state::UpdateVMReq; | use log::{debug, info, warn}; | ||||||
| use std::fs::read_dir; | use tokio::{ | ||||||
|  |     sync::mpsc::{Receiver, Sender}, | ||||||
|  |     time::{sleep, Duration}, | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| fn main() -> Result<(), Box<dyn std::error::Error>> { | #[allow(dead_code)] | ||||||
|     let config = Config::load_from_disk(crate::constants::DAEMON_CONFIG_PATH)?; | struct VMHandler { | ||||||
|     let mut res = match state::Resources::load_from_disk() { |     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, |             Ok(res) => res, | ||||||
|             Err(e) => { |             Err(e) => { | ||||||
|             println!("Could not load resources from disk: {e:?}"); |                 warn!("Could not load resources from disk: {e:?}"); | ||||||
|             println!("Creating new resource calculator."); |                 info!("Creating new resource calculator."); | ||||||
|                 state::Resources::new(&config.volumes) |                 state::Resources::new(&config.volumes) | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|  |         Self { new_vm_req_chan, new_vm_resp_chan, delete_vm_chan, resources_chan, config, res } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     for entry in read_dir("/etc/detee/daemon/newvmreq/")? { |     fn get_available_ips(&self) -> (u32, u32) { | ||||||
|         let entry = entry?; |         let mut avail_ipv4 = 0; | ||||||
|         let path = entry.path(); |         let mut avail_ipv6 = 0; | ||||||
|         if path.is_file() { |         for nic in self.config.network_interfaces.iter() { | ||||||
|             let new_vm_req = NewVMRequest::from_file(path.to_str().unwrap())?; |             for range in nic.ipv4_ranges.iter() { | ||||||
|             let vm = state::VM::new(new_vm_req, &config, &mut res).unwrap(); |                 avail_ipv4 += (range.last_ip.to_bits() + 1) - range.first_ip.to_bits(); | ||||||
|             vm.start()?; |             } | ||||||
|             println!("started vm {}", vm.uuid); |             for range in nic.ipv6_ranges.iter() { | ||||||
|         } |                 avail_ipv6 += (range.last_ip.to_bits() + 1) - range.first_ip.to_bits(); | ||||||
|     } |             } | ||||||
| 
 |         } | ||||||
|     for entry in read_dir("/etc/detee/daemon/deletevm/")? { |         ( | ||||||
|         let entry = entry?; |             avail_ipv4.saturating_sub(self.res.reserved_ipv4.len() as u32), | ||||||
|         let path = entry.path(); |             avail_ipv6.saturating_sub(self.res.reserved_ipv6.len() as u128) as u32, | ||||||
|         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", |     async fn send_node_resources(&mut self) { | ||||||
|             )?; |         let (avail_ipv4, avail_ipv6) = self.get_available_ips(); | ||||||
|             let vm: crate::state::VM = serde_yaml::from_str(&content)?; |         let mut avail_storage_gb = 0; | ||||||
|             vm.delete(&mut res)?; |         for volume in self.config.volumes.iter() { | ||||||
|             println!("deleted vm {}", vm.uuid); |             avail_storage_gb += volume.max_reservation_gb; | ||||||
|         } |             if let Some(reservation) = self.res.reserved_storage.get(&volume.path) { | ||||||
|     } |                 avail_storage_gb -= reservation; | ||||||
| 
 |             } | ||||||
|     for entry in read_dir("/etc/detee/daemon/updatedvmreq/")? { |         } | ||||||
|         let entry = entry?; |         let avail_storage_gb = avail_storage_gb as u32; | ||||||
|         let path = entry.path(); |         let res = brain::NodeResourceReq { | ||||||
|         if path.is_file() { |             node_pubkey: String::new(), | ||||||
|             let update_vm_req = UpdateVMReq::from_file(path.to_str().unwrap())?; |             avail_ports: (self.config.public_port_range.len() - self.res.reserved_ports.len()) | ||||||
|             let content = std::fs::read_to_string( |                 as u32, | ||||||
|                 crate::constants::VM_CONFIG_DIR.to_string() + &update_vm_req.uuid + ".yaml", |             avail_ipv4, | ||||||
|             )?; |             avail_ipv6, | ||||||
|             let mut vm: crate::state::VM = serde_yaml::from_str(&content)?; |             avail_vcpus: (self.config.max_vcpu_reservation - self.res.reserved_vcpus) as u32, | ||||||
|             vm.update(update_vm_req, &config, &mut res).unwrap(); |             avail_memory_mb: (self.config.max_mem_reservation_mb - self.res.reserved_memory) as u32, | ||||||
|             println!("updated vm {}", vm.uuid); |             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(()) |         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; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										349
									
								
								src/state.rs
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										349
									
								
								src/state.rs
									
									
									
									
									
								
							| @ -1,32 +1,28 @@ | |||||||
| #![allow(dead_code)] | #![allow(dead_code)] | ||||||
| use crate::config::Config; | use crate::{config::Config, constants::*, grpc::brain}; | ||||||
| use crate::constants::*; | use anyhow::{anyhow, Result}; | ||||||
| use anyhow::anyhow; | use serde::{Deserialize, Serialize}; | ||||||
| use anyhow::Result; |  | ||||||
| use serde::Deserialize; |  | ||||||
| use serde::Serialize; |  | ||||||
| use sha2::{Digest, Sha256}; | use sha2::{Digest, Sha256}; | ||||||
| use std::collections::HashMap; | use std::{ | ||||||
| use std::collections::HashSet; |     collections::{HashMap, HashSet}, | ||||||
| use std::fs; |     fs, | ||||||
| use std::fs::remove_file; |     fs::{remove_file, File}, | ||||||
| use std::fs::File; |     io::{Read, Write}, | ||||||
| use std::io::Read; |     path::Path, | ||||||
| use std::io::Write; |     process::Command, | ||||||
| use std::net::{Ipv4Addr, Ipv6Addr}; | }; | ||||||
| use std::path::Path; |  | ||||||
| use std::process::Command; |  | ||||||
| 
 | 
 | ||||||
| #[derive(Serialize, Deserialize, Debug)] | #[derive(Serialize, Deserialize, Debug)] | ||||||
| pub struct Resources { | pub struct Resources { | ||||||
|     existing_vms: HashSet<String>, |     pub existing_vms: HashSet<String>, | ||||||
|     // QEMU does not support MHz limiation
 |     // QEMU does not support MHz limiation
 | ||||||
|     reserved_vcpus: usize, |     pub reserved_vcpus: usize, | ||||||
|     reserved_memory: usize, |     pub reserved_memory: usize, | ||||||
|     reserved_ports: HashSet<u16>, |     pub reserved_ports: HashSet<u16>, | ||||||
|     reserved_storage: HashMap<String, usize>, |     pub reserved_storage: HashMap<String, usize>, | ||||||
|     reserved_ips: HashSet<String>, |     pub reserved_ipv4: HashSet<String>, | ||||||
|     reserved_if_names: HashSet<String>, |     pub reserved_ipv6: HashSet<String>, | ||||||
|  |     pub reserved_if_names: HashSet<String>, | ||||||
|     // sha256sum -> absolute path
 |     // sha256sum -> absolute path
 | ||||||
|     boot_files: HashSet<String>, |     boot_files: HashSet<String>, | ||||||
| } | } | ||||||
| @ -60,7 +56,8 @@ impl Resources { | |||||||
|             reserved_memory: 0, |             reserved_memory: 0, | ||||||
|             reserved_ports: HashSet::new(), |             reserved_ports: HashSet::new(), | ||||||
|             reserved_storage: HashMap::new(), |             reserved_storage: HashMap::new(), | ||||||
|             reserved_ips: HashSet::new(), |             reserved_ipv4: HashSet::new(), | ||||||
|  |             reserved_ipv6: HashSet::new(), | ||||||
|             reserved_if_names: HashSet::new(), |             reserved_if_names: HashSet::new(), | ||||||
|             boot_files: HashSet::new(), |             boot_files: HashSet::new(), | ||||||
|         }; |         }; | ||||||
| @ -111,11 +108,8 @@ impl Resources { | |||||||
|     fn available_if_name(&mut self) -> String { |     fn available_if_name(&mut self) -> String { | ||||||
|         use rand::{distributions::Alphanumeric, Rng}; |         use rand::{distributions::Alphanumeric, Rng}; | ||||||
|         loop { |         loop { | ||||||
|             let mut interface_name: String = rand::thread_rng() |             let mut interface_name: String = | ||||||
|                 .sample_iter(&Alphanumeric) |                 rand::thread_rng().sample_iter(&Alphanumeric).take(9).map(char::from).collect(); | ||||||
|                 .take(9) |  | ||||||
|                 .map(char::from) |  | ||||||
|                 .collect(); |  | ||||||
|             interface_name = "detee".to_string() + &interface_name; |             interface_name = "detee".to_string() + &interface_name; | ||||||
|             if !self.reserved_if_names.contains(&interface_name) { |             if !self.reserved_if_names.contains(&interface_name) { | ||||||
|                 return interface_name; |                 return interface_name; | ||||||
| @ -123,13 +117,15 @@ impl Resources { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn available_ipv4(&mut self, config: &Config) -> Option<VMNIC> { |     fn available_ipv4(&mut self, nics: &Vec<crate::config::Interface>) -> Option<VMNIC> { | ||||||
|         for nic in config.network_interfaces.iter() { |         for nic in nics.iter() { | ||||||
|             for range in nic.ipv4.iter() { |             for range in nic.ipv4_ranges.iter() { | ||||||
|                 for ip in range.subnet.iter().skip(1) { |                 let first_ip = range.first_ip.to_bits(); | ||||||
|                     if !range.reserved_addrs.contains(&ip.address()) |                 let last_ip = range.last_ip.to_bits(); | ||||||
|                         && !self.reserved_ips.contains(&ip.address().to_string()) |                 for ip in first_ip..last_ip + 1 { | ||||||
|                         && ip.address() != range.gateway |                     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 { |                         let if_config = match nic.driver { | ||||||
|                             crate::config::InterfaceType::MACVTAP => InterfaceConfig::MACVTAP { |                             crate::config::InterfaceType::MACVTAP => InterfaceConfig::MACVTAP { | ||||||
| @ -140,14 +136,14 @@ impl Resources { | |||||||
|                                 name: self.available_if_name(), |                                 name: self.available_if_name(), | ||||||
|                                 device: nic.device.clone(), |                                 device: nic.device.clone(), | ||||||
|                             }, |                             }, | ||||||
|                             crate::config::InterfaceType::Bridge => InterfaceConfig::Bridge { |                             crate::config::InterfaceType::Bridge => { | ||||||
|                                 device: nic.device.clone(), |                                 InterfaceConfig::Bridge { device: nic.device.clone() } | ||||||
|                             }, |                             } | ||||||
|                         }; |                         }; | ||||||
|                         let mut ips = Vec::new(); |                         let mut ips = Vec::new(); | ||||||
|                         ips.push(IPConfig { |                         ips.push(IPConfig { | ||||||
|                             address: ip.address().to_string(), |                             address: ip_addr.to_string(), | ||||||
|                             mask: calc_ipv4_netmask(ip.address(), range.gateway), |                             mask: range.netmask.clone(), | ||||||
|                             gateway: range.gateway.to_string(), |                             gateway: range.gateway.to_string(), | ||||||
|                         }); |                         }); | ||||||
|                         return Some(VMNIC { if_config, ips }); |                         return Some(VMNIC { if_config, ips }); | ||||||
| @ -158,13 +154,15 @@ impl Resources { | |||||||
|         None |         None | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn available_ipv6(&mut self, config: &Config) -> Option<VMNIC> { |     fn available_ipv6(&mut self, nics: &Vec<crate::config::Interface>) -> Option<VMNIC> { | ||||||
|         for nic in config.network_interfaces.iter() { |         for nic in nics.iter() { | ||||||
|             for range in nic.ipv6.iter() { |             for range in nic.ipv6_ranges.iter() { | ||||||
|                 for ip in range.subnet.iter().skip(1) { |                 let first_ip = range.first_ip.to_bits(); | ||||||
|                     if !range.reserved_addrs.contains(&ip.address()) |                 let last_ip = range.last_ip.to_bits(); | ||||||
|                         && !self.reserved_ips.contains(&ip.address().to_string()) |                 for ip in first_ip..last_ip + 1 { | ||||||
|                         && ip.address() != range.gateway |                     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 { |                         let if_config = match nic.driver { | ||||||
|                             crate::config::InterfaceType::MACVTAP => InterfaceConfig::MACVTAP { |                             crate::config::InterfaceType::MACVTAP => InterfaceConfig::MACVTAP { | ||||||
| @ -175,14 +173,14 @@ impl Resources { | |||||||
|                                 name: self.available_if_name(), |                                 name: self.available_if_name(), | ||||||
|                                 device: nic.device.clone(), |                                 device: nic.device.clone(), | ||||||
|                             }, |                             }, | ||||||
|                             crate::config::InterfaceType::Bridge => InterfaceConfig::Bridge { |                             crate::config::InterfaceType::Bridge => { | ||||||
|                                 device: nic.device.clone(), |                                 InterfaceConfig::Bridge { device: nic.device.clone() } | ||||||
|                             }, |                             } | ||||||
|                         }; |                         }; | ||||||
|                         let mut ips = Vec::new(); |                         let mut ips = Vec::new(); | ||||||
|                         ips.push(IPConfig { |                         ips.push(IPConfig { | ||||||
|                             address: ip.address().to_string(), |                             address: ip_addr.to_string(), | ||||||
|                             mask: calc_ipv6_netmask(ip.address(), range.gateway), |                             mask: range.netmask.clone(), | ||||||
|                             gateway: range.gateway.to_string(), |                             gateway: range.gateway.to_string(), | ||||||
|                         }); |                         }); | ||||||
|                         return Some(VMNIC { if_config, ips }); |                         return Some(VMNIC { if_config, ips }); | ||||||
| @ -213,7 +211,7 @@ impl Resources { | |||||||
|         Ok(()) |         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) { |         if !self.boot_files.contains(&sha) { | ||||||
|             download_and_check_sha(&url, &sha)?; |             download_and_check_sha(&url, &sha)?; | ||||||
|         } |         } | ||||||
| @ -230,7 +228,14 @@ impl Resources { | |||||||
|                 self.reserved_if_names.insert(vtap); |                 self.reserved_if_names.insert(vtap); | ||||||
|             } |             } | ||||||
|             for ip in nic.ips.iter() { |             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() { |         for (host_port, _) in vm.fw_ports.iter() { | ||||||
| @ -253,15 +258,20 @@ impl Resources { | |||||||
|                 self.reserved_if_names.remove(&vtap); |                 self.reserved_if_names.remove(&vtap); | ||||||
|             } |             } | ||||||
|             for ip in nic.ips.iter() { |             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() { |         for (host_port, _) in vm.fw_ports.iter() { | ||||||
|             self.reserved_ports.remove(host_port); |             self.reserved_ports.remove(host_port); | ||||||
|         } |         } | ||||||
|         self.reserved_storage |         self.reserved_storage.entry(vm.storage_dir.clone()).and_modify(|gb| *gb -= vm.disk_size_gb); | ||||||
|             .entry(vm.storage_dir.clone()) |  | ||||||
|             .and_modify(|gb| *gb -= vm.disk_size_gb); |  | ||||||
|         let _ = self.save_to_disk(); |         let _ = self.save_to_disk(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -333,12 +343,6 @@ pub struct VMNIC { | |||||||
|     ips: Vec<IPConfig>, |     ips: Vec<IPConfig>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl VMNIC { |  | ||||||
|     fn new() -> VMNIC { |  | ||||||
|         todo!("implement this here to improve code elegance of resource reservation"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Serialize, Deserialize, Debug)] | #[derive(Serialize, Deserialize, Debug)] | ||||||
| pub struct VM { | pub struct VM { | ||||||
|     pub uuid: String, |     pub uuid: String, | ||||||
| @ -356,6 +360,35 @@ pub struct VM { | |||||||
|     storage_dir: String, |     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)] | #[derive(Deserialize, Debug)] | ||||||
| pub struct NewVMRequest { | pub struct NewVMRequest { | ||||||
|     uuid: String, |     uuid: String, | ||||||
| @ -373,11 +406,23 @@ pub struct NewVMRequest { | |||||||
|     dtrfs_sha: String, |     dtrfs_sha: String, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl NewVMRequest { | impl From<brain::NewVmReq> for NewVMRequest { | ||||||
|     pub fn from_file(path: &str) -> Result<Self, Box<dyn std::error::Error>> { |     fn from(req: brain::NewVmReq) -> Self { | ||||||
|         let content = std::fs::read_to_string(path)?; |         Self { | ||||||
|         let request: NewVMRequest = serde_yaml::from_str(&content)?; |             uuid: req.uuid, | ||||||
|         Ok(request) |             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, |     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)] | #[derive(Debug)] | ||||||
| pub enum VMCreationErrors { | pub enum VMCreationErrors { | ||||||
|     VMAlreadyExists, |     VMAlreadyExists(VM), | ||||||
|     NATandIPv4Conflict, |     NATandIPv4Conflict, | ||||||
|     TooManyCores, |     TooManyCores, | ||||||
|     NotEnoughPorts, |     NotEnoughPorts, | ||||||
| @ -426,7 +463,11 @@ impl VM { | |||||||
|         res: &mut Resources, |         res: &mut Resources, | ||||||
|     ) -> Result<Self, VMCreationErrors> { |     ) -> Result<Self, VMCreationErrors> { | ||||||
|         if res.existing_vms.contains(&req.uuid) { |         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 { |         if req.extra_ports.len() > 0 && req.public_ipv4 { | ||||||
|             return Err(VMCreationErrors::NATandIPv4Conflict); |             return Err(VMCreationErrors::NATandIPv4Conflict); | ||||||
| @ -444,12 +485,20 @@ impl VM { | |||||||
|             return Err(VMCreationErrors::DiskTooSmall); |             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!( |             return Err(VMCreationErrors::BootFileError(format!( | ||||||
|                 "Could not get kernel: {kernel_err:?}" |                 "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!( |             return Err(VMCreationErrors::BootFileError(format!( | ||||||
|                 "Could not get dtrfs: {dtrfs_err:?}" |                 "Could not get dtrfs: {dtrfs_err:?}" | ||||||
|             ))); |             ))); | ||||||
| @ -457,13 +506,13 @@ impl VM { | |||||||
| 
 | 
 | ||||||
|         let mut vm_nics = Vec::new(); |         let mut vm_nics = Vec::new(); | ||||||
|         if req.public_ipv4 { |         if req.public_ipv4 { | ||||||
|             match res.available_ipv4(config) { |             match res.available_ipv4(&config.network_interfaces) { | ||||||
|                 Some(vmnic) => vm_nics.push(vmnic), |                 Some(vmnic) => vm_nics.push(vmnic), | ||||||
|                 None => return Err(VMCreationErrors::IPv4NotAvailable), |                 None => return Err(VMCreationErrors::IPv4NotAvailable), | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         if req.public_ipv6 { |         if req.public_ipv6 { | ||||||
|             match res.available_ipv6(config) { |             match res.available_ipv6(&config.network_interfaces) { | ||||||
|                 Some(mut vmnic) => { |                 Some(mut vmnic) => { | ||||||
|                     if let Some(mut existing_vmnic) = vm_nics.pop() { |                     if let Some(mut existing_vmnic) = vm_nics.pop() { | ||||||
|                         if vmnic.if_config.device_name() == existing_vmnic.if_config.device_name() { |                         if vmnic.if_config.device_name() == existing_vmnic.if_config.device_name() { | ||||||
| @ -478,7 +527,7 @@ impl VM { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 None => { |                 None => { | ||||||
|                     return Err(VMCreationErrors::IPv4NotAvailable); |                     return Err(VMCreationErrors::IPv6NotAvailable); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -532,18 +581,12 @@ impl VM { | |||||||
|             return Err(VMCreationErrors::TooManyCores); |             return Err(VMCreationErrors::TooManyCores); | ||||||
|         } |         } | ||||||
|         if config.max_vcpu_reservation |         if config.max_vcpu_reservation | ||||||
|             < res |             < res.reserved_vcpus.saturating_sub(self.vcpus).saturating_add(req.vcpus) | ||||||
|                 .reserved_vcpus |  | ||||||
|                 .saturating_sub(self.vcpus) |  | ||||||
|                 .saturating_add(req.vcpus) |  | ||||||
|         { |         { | ||||||
|             return Err(VMCreationErrors::NotEnoughCPU); |             return Err(VMCreationErrors::NotEnoughCPU); | ||||||
|         } |         } | ||||||
|         if config.max_mem_reservation_mb |         if config.max_mem_reservation_mb | ||||||
|             < res |             < res.reserved_memory.saturating_sub(self.memory_mb).saturating_add(req.memory_mb) | ||||||
|                 .reserved_memory |  | ||||||
|                 .saturating_sub(self.memory_mb) |  | ||||||
|                 .saturating_add(req.memory_mb) |  | ||||||
|         { |         { | ||||||
|             return Err(VMCreationErrors::NotEnoughMemory); |             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!( |                 return Err(VMCreationErrors::BootFileError(format!( | ||||||
|                     "Could not get kernel: {kern_err:?}" |                     "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!( |                 return Err(VMCreationErrors::BootFileError(format!( | ||||||
|                     "Could not get dtrfs: {dtrfs_err:?}" |                     "Could not get dtrfs: {dtrfs_err:?}" | ||||||
|                 ))); |                 ))); | ||||||
| @ -578,9 +623,7 @@ impl VM { | |||||||
|         res.reserved_memory = res.reserved_memory.saturating_sub(self.memory_mb); |         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_add(req.vcpus); | ||||||
|         res.reserved_vcpus = res.reserved_vcpus.saturating_sub(self.vcpus); |         res.reserved_vcpus = res.reserved_vcpus.saturating_sub(self.vcpus); | ||||||
|         res.reserved_storage |         res.reserved_storage.entry(self.storage_dir.clone()).and_modify(|gb| { | ||||||
|             .entry(self.storage_dir.clone()) |  | ||||||
|             .and_modify(|gb| { |  | ||||||
|             *gb = gb.saturating_add(req.disk_size_gb); |             *gb = gb.saturating_add(req.disk_size_gb); | ||||||
|             *gb = gb.saturating_sub(self.disk_size_gb); |             *gb = gb.saturating_sub(self.disk_size_gb); | ||||||
|         }); |         }); | ||||||
| @ -645,28 +688,25 @@ impl VM { | |||||||
|         dir + &self.uuid + ".qcow2" |         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 { |     pub fn kernel_params(&self) -> String { | ||||||
|         let mut ip_string = String::new(); |         let mut ip_string = String::new(); | ||||||
|         let mut i = 0; |         let mut i = 0; | ||||||
|         if self.fw_ports.len() > 0 { |         if self.fw_ports.len() > 0 { | ||||||
|             ip_string += &format!( |             ip_string += &format!("detee_net_eth{}={}_{}_{} ", i, "10.0.2.15", "24", "10.0.2.2"); | ||||||
|                 "detee_net_eth{}={}_{}_{} ", |  | ||||||
|                 i, "10.0.2.15", "24", "10.0.2.2" |  | ||||||
|             ); |  | ||||||
|             i += 1; |             i += 1; | ||||||
|         } |         } | ||||||
|         for nic in self.nics.iter() { |         for nic in self.nics.iter() { | ||||||
|             for ip in nic.ips.iter() { |             for ip in nic.ips.iter() { | ||||||
|                 ip_string += &format!( |                 ip_string += | ||||||
|                     "detee_net_eth{}={}_{}_{} ", |                     &format!("detee_net_eth{}={}_{}_{} ", i, ip.address, ip.mask, ip.gateway); | ||||||
|                     i, ip.address, ip.mask, ip.gateway |  | ||||||
|                 ); |  | ||||||
|             } |             } | ||||||
|             i += 1; |             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); |         let hostname = format!("detee_name={}", self.hostname); | ||||||
|         format!("{} {} {}", ip_string, admin_key, hostname) |         format!("{}{}{}", ip_string, admin_key, hostname) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn write_config(&self) -> Result<()> { |     fn write_config(&self) -> Result<()> { | ||||||
| @ -686,11 +726,7 @@ impl VM { | |||||||
|         let mut i = 0; |         let mut i = 0; | ||||||
|         for nic in self.nics.iter() { |         for nic in self.nics.iter() { | ||||||
|             let mut interface = String::new(); |             let mut interface = String::new(); | ||||||
|             interface += &format!( |             interface += &format!(r#"export NETWORK_INTERFACE_{}="{}"#, i, nic.if_config.if_type()); | ||||||
|                 r#"export NETWORK_INTERFACE_{}="{}"#, |  | ||||||
|                 i, |  | ||||||
|                 nic.if_config.if_type() |  | ||||||
|             ); |  | ||||||
|             // device is currently ignored in case of NAT cause we assume QEMU userspace NAT
 |             // device is currently ignored in case of NAT cause we assume QEMU userspace NAT
 | ||||||
|             if let Some(vtap_name) = nic.if_config.vtap_name() { |             if let Some(vtap_name) = nic.if_config.vtap_name() { | ||||||
|                 interface += &format!("_{}_{}", nic.if_config.device_name(), 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 += "export NETWORK_INTERFACE_0000=NAT\n"; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         vars += &format!( |         vars += &format!(r#"export KERNEL="{}""#, VM_BOOT_DIR.to_string() + &self.kernel_sha); | ||||||
|             r#"export KERNEL="{}""#, |  | ||||||
|             VM_BOOT_DIR.to_string() + &self.kernel_sha |  | ||||||
|         ); |  | ||||||
|         vars += "\n"; |         vars += "\n"; | ||||||
|         vars += &format!( |         vars += &format!(r#"export INITRD="{}""#, VM_BOOT_DIR.to_string() + &self.dtrfs_sha); | ||||||
|             r#"export INITRD="{}""#, |  | ||||||
|             VM_BOOT_DIR.to_string() + &self.dtrfs_sha |  | ||||||
|         ); |  | ||||||
|         vars += "\n"; |         vars += "\n"; | ||||||
|         vars += &format!(r#"export PARAMS="{}""#, self.kernel_params()); |         vars += &format!(r#"export PARAMS="{}""#, self.kernel_params()); | ||||||
|         vars += "\n"; |         vars += "\n"; | ||||||
| @ -747,11 +777,7 @@ impl VM { | |||||||
|     fn delete_vtap_interfaces(&self) -> Result<()> { |     fn delete_vtap_interfaces(&self) -> Result<()> { | ||||||
|         for nic in self.nics.iter() { |         for nic in self.nics.iter() { | ||||||
|             if let Some(name) = nic.if_config.vtap_name() { |             if let Some(name) = nic.if_config.vtap_name() { | ||||||
|                 let result = Command::new("ip") |                 let result = Command::new("ip").arg("link").arg("del").arg(&name).output()?; | ||||||
|                     .arg("link") |  | ||||||
|                     .arg("del") |  | ||||||
|                     .arg(&name) |  | ||||||
|                     .output()?; |  | ||||||
|                 if !result.status.success() { |                 if !result.status.success() { | ||||||
|                     return Err(anyhow!( |                     return Err(anyhow!( | ||||||
|                         "Could not delete vtap interface {:?}:\n{:?}\n{:?}", |                         "Could not delete vtap interface {:?}:\n{:?}\n{:?}", | ||||||
| @ -794,10 +820,7 @@ impl VM { | |||||||
| 
 | 
 | ||||||
|     fn create_disk(&self) -> Result<()> { |     fn create_disk(&self) -> Result<()> { | ||||||
|         if std::path::Path::new(&self.disk_path()).exists() { |         if std::path::Path::new(&self.disk_path()).exists() { | ||||||
|             return Err(anyhow!( |             return Err(anyhow!("Could not create {}. The file already exists.", self.disk_path())); | ||||||
|                 "Could not create {}. The file already exists.", |  | ||||||
|                 self.disk_path() |  | ||||||
|             )); |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let result = Command::new("qemu-img") |         let result = Command::new("qemu-img") | ||||||
| @ -844,10 +867,8 @@ impl VM { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn systemctl_start_and_enable(vm_uuid: &str) -> Result<()> { | fn systemctl_start_and_enable(vm_uuid: &str) -> Result<()> { | ||||||
|     let result = Command::new("systemctl") |     let result = | ||||||
|         .arg("start") |         Command::new("systemctl").arg("start").arg(vm_uuid.to_string() + ".service").output()?; | ||||||
|         .arg(vm_uuid.to_string() + ".service") |  | ||||||
|         .output()?; |  | ||||||
|     if !result.status.success() { |     if !result.status.success() { | ||||||
|         return Err(anyhow!( |         return Err(anyhow!( | ||||||
|             "Could not reload systemctl daemon:\n{:?}\n{:?}", |             "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()), |                 .unwrap_or("Could not grab stderr from creation script.".to_string()), | ||||||
|         )); |         )); | ||||||
|     } |     } | ||||||
|     let result = Command::new("systemctl") |     let result = | ||||||
|         .arg("enable") |         Command::new("systemctl").arg("enable").arg(vm_uuid.to_string() + ".service").output()?; | ||||||
|         .arg(vm_uuid.to_string() + ".service") |  | ||||||
|         .output()?; |  | ||||||
|     if !result.status.success() { |     if !result.status.success() { | ||||||
|         return Err(anyhow!( |         return Err(anyhow!( | ||||||
|             "Could not reload systemctl daemon:\n{:?}\n{:?}", |             "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<()> { | fn systemctl_stop_and_disable(vm_uuid: &str) -> Result<()> { | ||||||
|     let result = Command::new("systemctl") |     let result = | ||||||
|         .arg("stop") |         Command::new("systemctl").arg("stop").arg(vm_uuid.to_string() + ".service").output()?; | ||||||
|         .arg(vm_uuid.to_string() + ".service") |  | ||||||
|         .output()?; |  | ||||||
|     if !result.status.success() { |     if !result.status.success() { | ||||||
|         return Err(anyhow!( |         return Err(anyhow!( | ||||||
|             "Could not reload systemctl daemon:\n{:?}\n{:?}", |             "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()), |                 .unwrap_or("Could not grab stderr from creation script.".to_string()), | ||||||
|         )); |         )); | ||||||
|     } |     } | ||||||
|     let result = Command::new("systemctl") |     let result = | ||||||
|         .arg("disable") |         Command::new("systemctl").arg("disable").arg(vm_uuid.to_string() + ".service").output()?; | ||||||
|         .arg(vm_uuid.to_string() + ".service") |  | ||||||
|         .output()?; |  | ||||||
|     if !result.status.success() { |     if !result.status.success() { | ||||||
|         return Err(anyhow!( |         return Err(anyhow!( | ||||||
|             "Could not reload systemctl daemon:\n{:?}\n{:?}", |             "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<()> { | fn download_and_check_sha(url: &str, sha: &str) -> Result<()> { | ||||||
|     use reqwest::blocking::get; |     use reqwest::blocking::get; | ||||||
|     use std::fs::File; |     use std::{fs::File, io::copy, path::Path}; | ||||||
|     use std::io::copy; |  | ||||||
|     use std::path::Path; |  | ||||||
|     let save_path = VM_BOOT_DIR.to_string() + sha; |     let save_path = VM_BOOT_DIR.to_string() + sha; | ||||||
|     let response = get(url)?; |     let response = get(url)?; | ||||||
|     if !response.status().is_success() { |     if !response.status().is_success() { | ||||||
| @ -958,41 +971,3 @@ fn compute_sha256<P: AsRef<Path>>(path: P) -> Result<String> { | |||||||
|     let result = hasher.finalize(); |     let result = hasher.finalize(); | ||||||
|     Ok(format!("{:x}", result)) |     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